You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sims-hq/apps/hq/scripts/apply-name-fixes.ts

51 lines
2.3 KiB
TypeScript

// apps/hq/scripts/apply-name-fixes.ts — one-off (D35 data correction): apply the approved
// client-name corrections from name-review.json via the audited updateClient path.
// REVIEW_JSON=<path> DATABASE_URL=postgres://… npx tsx apps/hq/scripts/apply-name-fixes.ts
import { readFileSync } from 'node:fs'
import { openDb, sqliteFilePath } from '../src/db'
import { openPgDb, pgTargetDescription, requireDbUrlForEnv } from '../src/db-pg'
import { updateClient } from '../src/repos-clients'
import type { DB } from '../src/db'
interface Row { id: string; current: string; suggested: string; changed: boolean }
async function main() {
const path = process.env['REVIEW_JSON']
if (path === undefined) throw new Error('Set REVIEW_JSON to the name-review.json path')
const rows = JSON.parse(readFileSync(path, 'utf8')) as Row[]
// Pre-ship audit FIX A: the SAME resolver server.ts uses (never re-derived locally) — and,
// unlike the server, this one-off script hard-fails rather than silently falling back to a
// throwaway SQLite file when NODE_ENV=production resolves no Postgres target.
const pgUrl = requireDbUrlForEnv()
if (pgUrl !== '') {
console.log(`[db] engine: postgres ${pgTargetDescription(pgUrl)}`)
} else {
console.log(`[db] engine: sqlite at ${sqliteFilePath(process.env['HQ_DATA_DIR'])}`)
}
const db: DB = pgUrl !== '' ? await openPgDb(pgUrl) : openDb(process.env['HQ_DATA_DIR'])
try {
let applied = 0, skipped = 0
for (const r of rows) {
if (!r.changed || r.suggested === r.current) continue
try {
// Guard: only touch a client whose stored name still matches what was reviewed.
const cur = await db.get<{ name: string }>(`SELECT name FROM client WHERE id=?`, r.id)
if (cur === undefined || cur.name !== r.current) { skipped++; continue }
await updateClient(db, 'system', r.id, { name: r.suggested })
applied++
} catch (e) {
skipped++
// eslint-disable-next-line no-console
console.error(` skip ${r.current}: ${e instanceof Error ? e.message : String(e)}`)
}
}
// eslint-disable-next-line no-console
console.log(`Name corrections: ${applied} applied, ${skipped} skipped.`)
} finally {
await db.close()
}
}
main().catch((e) => { console.error(e); process.exit(1) })