← back to Hollywood Import
momentum-feed/assign-sku.mjs
84 lines
#!/usr/bin/env node
// Momentum → Hollywood assign-sku: give every unmapped colorway (dw_sku IS NULL) a
// sequential DWHD- SKU, its pattern a fresh CA-coastal collection name (pl_city_name),
// and pl_brand='Hollywood Wallcoverings'. STAGING ONLY — decoupled from the go-live drip,
// which reads the fixed manifest the67_full.json, NOT this table. Reversible.
// Run: NODE_PATH=.../AbramsOS/node_modules node assign-sku.mjs [--commit]
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const { Pool } = require('pg');
const pool = new Pool({ connectionString: 'postgresql://dw_admin:DW2024!@127.0.0.1:5432/dw_unified' });
const COMMIT = process.argv.includes('--commit');
// Real CA coastal place names (base pool). Expanded with suffixes if 258+ collision-free needed.
const BASE = `Zuma,Point Dume,Paradise Cove,Leo Carrillo,El Matador,Trancas,Nicholas Canyon,Broad Beach,
Crystal Cove,Corona del Mar,Little Corona,Reef Point,Pelican Point,Abalone Cove,Portuguese Bend,Royal Palms,
Cabrillo Beach,White Point,Point Fermin,Redondo Breakwater,Hermosa Strand,El Porto,Dockweiler,Playa del Rey,
Malaga Cove,Bluff Cove,Lunada Bay,Torrance Beach,Sunset Cliffs,Ocean Beach,La Jolla Shores,Windansea,
Black's Beach,Torrey Pines,Del Mar,Cardiff Reef,Swami's,Moonlight Beach,Ponto,Terramar,Carlsbad State,
San Onofre,Trestles,Church Beach,Cottons Point,Poche,Capistrano Beach,Dana Point,Salt Creek,Monarch Bay,
Three Arch Bay,Woods Cove,Divers Cove,Shaw's Cove,Crescent Bay,Emerald Bay,Cameo Shores,Balboa Peninsula,
Newport Point,Huntington Cliffs,Bolsa Chica,Sunset Beach,Seal Beach,Cabrillo,Refugio,El Capitan,Gaviota,
Arroyo Burro,Butterfly Beach,Miramar,Rincon,Carpinteria,Faria,Emma Wood,Surfers Point,Mondos,Solimar,
Oxnard Shores,Silver Strand,Point Mugu,Sycamore Cove,County Line,Deer Creek,Staircase Beach,Thornhill Broome,
Pfeiffer Beach,Sand Dollar,Willow Creek,Kirk Creek,Limekiln,Partington Cove,McWay Falls,Andrew Molera,
Garrapata,Bixby Bridge,Point Lobos,Carmel River,Monastery Beach,Spanish Bay,Asilomar,Lovers Point,
Moss Landing,Zmudowski,Sunset State,Manresa,Rio Del Mar,Capitola,Pleasure Point,Steamer Lane,Cowell Beach,
Natural Bridges,Wilder Ranch,Scott Creek,Waddell,Ano Nuevo,Pigeon Point,Pescadero,Pomponio,San Gregorio,
Pacifica Pier,Rockaway Beach,Mori Point,Montara,Gray Whale Cove,Devils Slide,Half Moon Bay,Miramar Beach,
Dunes Beach,Poplar Beach,Cowell Ranch,Martins Beach,Ocean Cove,Salt Point,Fort Ross,Timber Cove,
Stillwater Cove,Gerstle Cove,Goat Rock,Wrights Beach,Duncans Landing,Salmon Creek,Bodega Head,Doran Beach,
Dillon Beach,Lawsons Landing,McClures Beach,Limantour,Drakes Beach,Point Reyes,Kehoe Beach,Abbotts Lagoon,
Stinson Beach,Bolinas,Muir Beach,Rodeo Beach,Kirby Cove,Baker Beach,China Beach,Lands End,Ocean Beach SF,
Mavericks,Trinidad State,Moonstone Beach,Clam Beach,Agate Beach,Luffenholtz,College Cove,Houda Point`
.split(',').map(s => s.trim().replace(/\s+/g, ' ')).filter(Boolean);
const SUFFIX = ['Cove','Point','Bluffs','Landing','Reef','Strand','Shores','Head','Bay','Overlook'];
function buildPool(need, used) {
const out = [], seen = new Set([...used].map(s => s.toLowerCase()));
const add = n => { const k = n.toLowerCase(); if (!seen.has(k)) { seen.add(k); out.push(n); } };
for (const n of BASE) { add(n); if (out.length >= need) return out; }
for (const sfx of SUFFIX) for (const n of BASE) { add(`${n.split(' ')[0]} ${sfx}`); if (out.length >= need) return out; }
return out; // (BASE 170 × 10 suffixes ≫ 258; guaranteed enough)
}
async function main() {
const used = (await pool.query(`SELECT DISTINCT pl_city_name c FROM momentum_colorways WHERE pl_city_name IS NOT NULL`))
.rows.map(r => r.c).filter(Boolean);
const maxNum = (await pool.query(
`SELECT COALESCE(MAX((substring(dw_sku from 'DWHD-([0-9]+)'))::int),500000) m FROM momentum_colorways WHERE dw_sku ~ '^DWHD-[0-9]+$'`)).rows[0].m;
// Deterministic order: WC before Acoustic, then pattern, then colorway.
const { rows } = await pool.query(
`SELECT id, pattern_name, color_name, color_number, category FROM momentum_colorways
WHERE dw_sku IS NULL ORDER BY category, pattern_name, color_number NULLS LAST, id`);
const patterns = [...new Set(rows.map(r => r.pattern_name))];
const pool2 = buildPool(patterns.length, used);
if (pool2.length < patterns.length) throw new Error(`pool short: ${pool2.length} < ${patterns.length}`);
const cityOf = new Map(patterns.map((p, i) => [p, pool2[i]]));
let n = maxNum;
const plan = rows.map(r => ({ id: r.id, dw_sku: `DWHD-${++n}`, city: cityOf.get(r.pattern_name),
pattern: r.pattern_name, color: r.color_name, cat: r.category }));
console.log(`assign-sku: ${plan.length} colorways / ${patterns.length} patterns.`);
console.log(` DWHD range: DWHD-${maxNum + 1} … DWHD-${n}`);
console.log(` new cities minted: ${patterns.length} (0 collisions w/ ${used.length} existing)`);
console.log(' samples:'); plan.slice(0, 4).forEach(p => console.log(` ${p.dw_sku} ${p.cat} "${p.pattern}" / ${p.color} → ${p.city}`));
if (!COMMIT) { console.log('DRY-RUN — re-run with --commit to write.'); await pool.end(); return; }
const c = await pool.connect();
let done = 0;
try {
await c.query('BEGIN');
for (const p of plan) {
await c.query(
`UPDATE momentum_colorways SET dw_sku=$1, pl_city_name=$2, pl_brand='Hollywood Wallcoverings', updated_at=now()
WHERE id=$3 AND dw_sku IS NULL`, [p.dw_sku, p.city, p.id]);
done++;
}
await c.query('COMMIT');
console.log(`COMMITTED — assigned ${done} DWHD SKUs + ${patterns.length} CA-city collections. pl_brand set. (staging only; drip manifest untouched)`);
} catch (e) { await c.query('ROLLBACK'); console.error('ROLLBACK:', e.message); process.exitCode = 1; }
finally { c.release(); await pool.end(); }
}
main().catch(e => { console.error(e); process.exit(1); });