/** * D0 requirement 3 — review report for names that cannot be split safely. * * The migration backfills firstName = first token, lastName = the rest. That is * correct for two-token names and a guess for anything longer: "سید محمد * حسینی" should almost certainly be firstName="سید محمد", and the migration * writes firstName="سید" instead. Those rows need a human. * * READ-ONLY. It changes nothing; it prints what a person has to check. * * node scripts/report-name-split.cjs # print to stdout * node scripts/report-name-split.cjs --csv out.csv * * Run it AFTER the 20260922120000_customer_name_parts migration. */ const { PrismaClient } = require('@prisma/client'); const fs = require('fs'); const prisma = new PrismaClient(); /** Same normalisation the migration's SQL uses. */ const tokens = (s) => String(s ?? '').trim().replace(/\s+/g, ' ').split(' ').filter(Boolean); (async () => { const customers = await prisma.$queryRawUnsafe(` SELECT id, "fullName", "firstName", "lastName", mobile, "memberCode" FROM "Customer" ORDER BY "createdAt" `); const multi = []; const empty = []; const single = []; for (const c of customers) { const t = tokens(c.fullName); if (t.length === 0) empty.push(c); else if (t.length === 1) single.push(c); else if (t.length > 2) multi.push({ ...c, tokenCount: t.length }); } console.log(`Customers scanned: ${customers.length}`); console.log(` two tokens (split is reliable): ${customers.length - multi.length - empty.length - single.length}`); console.log(` one token (lastName is NULL): ${single.length}`); console.log(` empty name (nothing to split): ${empty.length}`); console.log(` MORE THAN TWO TOKENS — NEEDS REVIEW: ${multi.length}`); if (single.length) { console.log('\n--- single-token names (no surname recorded) ---'); for (const c of single) console.log(` ${c.id} ${c.mobile} "${c.fullName}"`); } if (empty.length) { console.log('\n--- empty names ---'); for (const c of empty) console.log(` ${c.id} ${c.mobile}`); } if (multi.length) { console.log('\n--- NEEDS REVIEW: more than two tokens ---'); console.log('The migration guessed first-token / rest. Verify each one.\n'); for (const c of multi) { console.log(` ${c.id} ${c.mobile} (${c.tokenCount} tokens)`); console.log(` fullName : "${c.fullName}"`); console.log(` guessed : firstName="${c.firstName}" lastName="${c.lastName}"`); } } const csvArg = process.argv.indexOf('--csv'); if (csvArg !== -1 && process.argv[csvArg + 1]) { const esc = (v) => `"${String(v ?? '').replace(/"/g, '""')}"`; const rows = [ ['id', 'mobile', 'memberCode', 'fullName', 'guessedFirstName', 'guessedLastName', 'tokenCount'].join(','), ...multi.map((c) => [c.id, c.mobile, c.memberCode, c.fullName, c.firstName, c.lastName, c.tokenCount].map(esc).join(','), ), ]; // BOM so Excel opens the Persian text in the right encoding. fs.writeFileSync(process.argv[csvArg + 1], '' + rows.join('\n'), 'utf8'); console.log(`\nCSV written: ${process.argv[csvArg + 1]} (${multi.length} rows)`); } await prisma.$disconnect(); })().catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });