← back to Tk 11331 Exec

d2_rollback.mjs

34 lines

// UNDO Decision 2 — restore min/uom old values from d2-restore-map.jsonl.
// If old uom was null, DELETE the unit_of_measure metafield. Also reverts the PG mirror. --apply.
import fs from 'fs';
import {execSync} from 'child_process';
import {gql,sleep} from './lib.mjs';
const APPLY=process.argv.includes('--apply');
const rows=fs.readFileSync('data/d2-restore-map.jsonl','utf8').trim().split('\n').filter(Boolean).map(l=>JSON.parse(l));
const SET=`mutation($mf:[MetafieldsSetInput!]!){metafieldsSet(metafields:$mf){metafields{key} userErrors{field message}}}`;
const DEL=`mutation($id:ID!){metafieldDelete(input:{id:$id}){deletedId userErrors{field message}}}`;
const FIND=`query($id:ID!){product(id:$id){mf:metafield(namespace:"global",key:"unit_of_measure"){id}}}`;
const psql=sql=>execSync(`psql -h /tmp -d dw_unified -Atc ${JSON.stringify(sql)}`,{encoding:'utf8'}).trim();
console.log(`${APPLY?'APPLY':'DRY'} D2 rollback — ${rows.length} products`);
let ok=0,fail=0;
for(const r of rows){
  const mf=[];
  if(r.wrote.min!==null && r.old.min!==null) mf.push({ownerId:r.gid,namespace:'global',key:'v_prods_quantity_order_min',type:'single_line_text_field',value:r.old.min});
  if(r.wrote.uom!==null && r.old.uom!==null) mf.push({ownerId:r.gid,namespace:'global',key:'unit_of_measure',type:'single_line_text_field',value:r.old.uom});
  if(!APPLY){ console.log(`  would restore ${r.pid} min=${JSON.stringify(r.old.min)} uom=${JSON.stringify(r.old.uom)}${r.wrote.uom!==null&&r.old.uom===null?' (DELETE uom)':''}`); continue; }
  try{
    if(mf.length) { const res=await gql(SET,{mf}); if(res.metafieldsSet.userErrors.length){fail++;console.log('  SET-ERR',r.pid);continue;} }
    if(r.wrote.uom!==null && r.old.uom===null){ // delete the uom we created
      const f=await gql(FIND,{id:r.gid}); if(f.product.mf?.id){ await gql(DEL,{id:f.product.mf.id}); }
    }
    // revert PG mirror to old values (best-effort)
    if(r.wrote.min!==null){ const v=r.old.min===null?null:`'{"type":"single_line_text_field","value":${JSON.stringify(r.old.min)}}'::jsonb`;
      if(v) psql(`update shopify_products set metafields=jsonb_set(metafields,'{global,v_prods_quantity_order_min}',${v},true) where shopify_id='${r.gid}';`); }
    if(r.wrote.uom!==null){ if(r.old.uom===null) psql(`update shopify_products set metafields=metafields#-'{global,unit_of_measure}' where shopify_id='${r.gid}';`);
      else psql(`update shopify_products set metafields=jsonb_set(metafields,'{global,unit_of_measure}','{"type":"single_line_text_field","value":${JSON.stringify(r.old.uom)}}'::jsonb,true) where shopify_id='${r.gid}';`); }
    ok++;
  }catch(e){ fail++; console.log('  ERR',r.pid,String(e).slice(0,120)); }
  await sleep(300);
}
console.log(`D2 rollback ${APPLY?'APPLIED':'DRY'} ok=${ok} fail=${fail}`);