← back to Dw Sarah Rowland Searchfix

apply.mjs

50 lines

// TK-10037 — make the Sarah Rowland collection searchable.
// Adds tag "Sarah Rowland" (search fix) + custom.designer="Sarah Rowland" (structured data)
// to every product in the collection. Idempotent. Writes to LIVE production Shopify.
//
//   node apply.mjs canary   -> first 1 product only, then verify
//   node apply.mjs all      -> all products (safe to re-run; idempotent)
import fs from 'node:fs';
import { gql } from './lib.mjs';

const TAG = 'Sarah Rowland';
const mode = process.argv[2];
if (!['canary', 'all'].includes(mode)) { console.error('usage: node apply.mjs canary|all'); process.exit(1); }

const products = JSON.parse(fs.readFileSync(new URL('./products.json', import.meta.url)));
const batch = mode === 'canary' ? products.slice(0, 1) : products;

const TAGS_ADD = `mutation($id:ID!,$tags:[String!]!){ tagsAdd(id:$id, tags:$tags){ userErrors{ message } } }`;
const MF_SET = `mutation($mf:[MetafieldsSetInput!]!){ metafieldsSet(metafields:$mf){ userErrors{ field message } } }`;

const sleep = (ms) => new Promise(r => setTimeout(r, ms));
let ok = 0, fail = 0;
console.log(`MODE=${mode} — processing ${batch.length} product(s)\n`);

for (const p of batch) {
  try {
    await gql(TAGS_ADD, { id: p.id, tags: [TAG] });
    await gql(MF_SET, { mf: [{ ownerId: p.id, namespace: 'custom', key: 'designer',
      type: 'single_line_text_field', value: TAG }] });
    ok++;
    if (mode === 'canary' || ok % 20 === 0) console.log(`  ✓ ${ok}/${batch.length}  ${p.title.slice(0,45)}`);
  } catch (e) {
    fail++;
    console.log(`  ✗ FAIL  ${p.title.slice(0,45)} — ${e.message}`);
  }
  await sleep(120);
}
console.log(`\nDone: ${ok} ok, ${fail} failed.`);

// verify
const VERIFY = `query($id:ID!){ product(id:$id){ tags metafield(namespace:"custom",key:"designer"){ value } } }`;
console.log('\nVerifying...');
let vTag = 0, vMeta = 0;
for (const p of batch) {
  const d = await gql(VERIFY, { id: p.id });
  if (d.product.tags.includes(TAG)) vTag++;
  if (d.product.metafield && d.product.metafield.value === TAG) vMeta++;
  await sleep(60);
}
console.log(`Verified: ${vTag}/${batch.length} carry the tag, ${vMeta}/${batch.length} carry custom.designer.`);