← back to Council 0809 Builds

rolls-ar-deeplink/scan-metafield-coverage.js

46 lines

// Live Shopify Admin-API coverage scan for Council #5 (read-only).
// Tallies, across ACTIVE products, how many carry a PARSEABLE custom.width
// and what repeat metafields exist. $0 (Admin API is unmetered).
const fs = require('fs');
const env = fs.readFileSync(require('os').homedir()+'/Projects/secrets-manager/.env','utf8');
const g = k => (env.match(new RegExp('^'+k+'=(.*)$','m'))||[])[1];
const TOKEN = g('SHOPIFY_ADMIN_TOKEN'), STORE = g('SHOPIFY_STORE');
const URL = `https://${STORE}/admin/api/2024-10/graphql.json`;
const numish = v => { if(v==null) return false; const n=parseFloat(String(v).replace(/[^0-9.]/g,'')); return Number.isFinite(n)&&n>0; };
const Q = `query($c:String){ products(first:200, after:$c, query:"status:active"){
  pageInfo{hasNextPage endCursor}
  nodes{ id productType
    width: metafield(namespace:"custom", key:"width"){value}
    prep: metafield(namespace:"custom", key:"pattern_repeat"){value}
    rep: metafield(namespace:"custom", key:"repeat"){value}
    prnum: metafield(namespace:"custom", key:"pattern_repeat_number"){value}
  }}}`;
(async()=>{
  let cur=null, more=true, page=0;
  const t={total:0, width_ok:0, width_any:0, prep_any:0, prep_numish:0, rep_numish:0, prnum_any:0, width_and_repeatnum:0, byType:{}};
  const CAP = parseInt(process.env.CAP||'99',10);
  while(more && page<CAP){
    const r=await fetch(URL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:Q,variables:{c:cur}})});
    const j=await r.json();
    if(j.errors){console.error(JSON.stringify(j.errors).slice(0,300)); break;}
    const d=j.data.products;
    for(const n of d.nodes){
      t.total++;
      const pt=(n.productType||'(none)');
      t.byType[pt]=(t.byType[pt]||0)+1;
      if(n.width){t.width_any++; if(numish(n.width.value)) t.width_ok++;}
      if(n.prep){t.prep_any++; if(numish(n.prep.value)) t.prep_numish++;}
      if(n.rep && numish(n.rep.value)) t.rep_numish++;
      if(n.prnum){t.prnum_any++;}
      const hasWidth = n.width && numish(n.width.value);
      const hasRepeatNum = (n.prep&&numish(n.prep.value))||(n.rep&&numish(n.rep.value))||(n.prnum&&numish(n.prnum.value));
      if(hasWidth && hasRepeatNum) t.width_and_repeatnum++;
    }
    cur=d.pageInfo.endCursor; more=d.pageInfo.hasNextPage; page++;
    if(page%10===0) console.error(`...page ${page}, scanned ${t.total}`);
    await new Promise(x=>setTimeout(x,120));
  }
  t.pages=page; t.completed=!more;
  console.log(JSON.stringify(t,null,2));
})().catch(e=>{console.error(e.message);process.exit(1);});