← back to Dwjs Consolidation 2026 04 23

dwqw_survey.js

69 lines

#!/usr/bin/env node
// Survey DWQW active products for natural collection groupings
const https = require('https');
const STORE='designer-laboratory-sandbox.myshopify.com';
const TOKEN=(process.env.SHOPIFY_ADMIN_TOKEN || '');
function gql(b){return new Promise((res,rej)=>{const d=JSON.stringify(b);const r=https.request({hostname:STORE,path:'/admin/api/2024-10/graphql.json',method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json','Content-Length':Buffer.byteLength(d)}},R=>{let c='';R.on('data',x=>c+=x);R.on('end',()=>{try{res(JSON.parse(c))}catch{res({})}})});r.on('error',rej);r.setTimeout(60000,()=>{r.destroy();rej(new Error('t'))});r.write(d);r.end();});}

(async()=>{
  const q = `{
    products(query:"sku:DWQW* AND status:active") {
      edges { node {
        id title vendor tags productType
        style: metafield(namespace:"specs",key:"style") { value }
        pattern_mf: metafield(namespace:"specs",key:"pattern") { value }
        color_family: metafield(namespace:"custom",key:"color_family") { value }
      } }
    }
  }`;
  for (let i=0;i<10;i++){
    const r=await gql({query:'{ currentBulkOperation { status } }'});
    const st=r?.data?.currentBulkOperation?.status;
    if (!st || ['COMPLETED','FAILED','CANCELED','EXPIRED'].includes(st)) break;
    await new Promise(r=>setTimeout(r,3000));
  }
  await gql({query:`mutation{ bulkOperationRunQuery(query: """${q}""") { bulkOperation{id} userErrors{message} } }`});
  let url=null;
  for(;;){
    await new Promise(r=>setTimeout(r,4000));
    const p=await gql({query:'{ currentBulkOperation { status objectCount url } }'});
    const op=p?.data?.currentBulkOperation;
    if (op?.status==='COMPLETED'){ url=op.url; break; }
    if (['FAILED','CANCELED','EXPIRED'].includes(op?.status)) throw new Error(op.status);
  }
  const chunks=[]; await new Promise((r,j)=>{https.get(url,res=>{res.on('data',d=>chunks.push(d));res.on('end',r)}).on('error',j)});
  const fs=require('fs');
  const data = Buffer.concat(chunks).toString();
  fs.writeFileSync('/Users/macstudio3/Projects/dwjs-consolidation-2026-04-23/dwqw_active.jsonl', data);
  const products = [];
  for (const l of data.split('\n').filter(Boolean)){
    const o=JSON.parse(l);
    if (o.id?.includes('/Product/')) products.push({
      title:o.title, vendor:o.vendor, type:o.productType,
      style:o.style?.value||'', pattern:o.pattern_mf?.value||'',
      color_family:o.color_family?.value||'',
      tags: o.tags||[]
    });
  }
  console.log(`active DWQW: ${products.length}`);
  // vendor distribution
  const C = require('util');
  const count = (arr, fn) => {
    const m = {};
    for (const x of arr) { const k=fn(x); if (!k) continue; m[k]=(m[k]||0)+1; }
    return Object.entries(m).sort((a,b)=>b[1]-a[1]);
  };
  console.log('\nvendors:'); count(products,p=>p.vendor).slice(0,10).forEach(([k,v])=>console.log(`  ${v}  ${k}`));
  console.log('\nproduct types:'); count(products,p=>p.type).slice(0,10).forEach(([k,v])=>console.log(`  ${v}  ${k}`));
  console.log('\nstyle (top 20):'); count(products,p=>p.style).slice(0,20).forEach(([k,v])=>console.log(`  ${v}  ${k}`));
  console.log('\npattern mf (top 15):'); count(products,p=>p.pattern).slice(0,15).forEach(([k,v])=>console.log(`  ${v}  ${k}`));
  console.log('\ncolor_family (top 15):'); count(products,p=>p.color_family).slice(0,15).forEach(([k,v])=>console.log(`  ${v}  ${k}`));

  // Tag analysis - candidate collection-worthy tags
  const tagCount = {};
  for (const p of products) for (const t of p.tags) tagCount[t]=(tagCount[t]||0)+1;
  const topTags = Object.entries(tagCount).sort((a,b)=>b[1]-a[1]).slice(0,50);
  console.log('\ntop 50 tags:');
  topTags.forEach(([k,v])=>console.log(`  ${String(v).padStart(5)}  ${k}`));
})().catch(e=>{console.error(e); process.exit(1);});