@ -5,9 +5,10 @@
// Does NOT overwrite the name's spelling/casing — only appends the number.
// Does NOT overwrite the name's spelling/casing — only appends the number.
// LTD_JSON=<results.json> DATABASE_URL=postgres://… npx tsx apps/hq/scripts/apply-ltd-numbers.ts
// LTD_JSON=<results.json> DATABASE_URL=postgres://… npx tsx apps/hq/scripts/apply-ltd-numbers.ts
import { readFileSync } from 'node:fs'
import { readFileSync } from 'node:fs'
import { openDb } from '../src/db'
import { openDb , sqliteFilePath } from '../src/db'
import { openPgDb } from '../src/db-pg'
import { openPgDb , pgTargetDescription , requireDbUrlForEnv } from '../src/db-pg'
import { updateClient } from '../src/repos-clients'
import { updateClient } from '../src/repos-clients'
import type { DB } from '../src/db'
interface Res { clientId : string ; ltdNo : string ; found : boolean }
interface Res { clientId : string ; ltdNo : string ; found : boolean }
@ -16,27 +17,39 @@ async function main() {
if ( path === undefined ) throw new Error ( 'Set LTD_JSON to the workflow result json path' )
if ( path === undefined ) throw new Error ( 'Set LTD_JSON to the workflow result json path' )
const parsed = JSON . parse ( readFileSync ( path , 'utf8' ) ) as { results? : Res [ ] } | Res [ ]
const parsed = JSON . parse ( readFileSync ( path , 'utf8' ) ) as { results? : Res [ ] } | Res [ ]
const results = Array . isArray ( parsed ) ? parsed : ( parsed . results ? ? [ ] )
const results = Array . isArray ( parsed ) ? parsed : ( parsed . results ? ? [ ] )
const pgUrl = process . env [ 'DATABASE_URL' ] ? ? ''
const db = pgUrl !== '' ? await openPgDb ( pgUrl ) : openDb ( process . env [ 'HQ_DATA_DIR' ] )
let applied = 0 , already = 0 , skipped = 0
// Pre-ship audit FIX A: the SAME resolver server.ts uses (never re-derived locally) — and,
const seen = new Set < string > ( )
// unlike the server, this one-off script hard-fails rather than silently falling back to a
for ( const r of results ) {
// throwaway SQLite file when NODE_ENV=production resolves no Postgres target.
const ltd = ( r . ltdNo ? ? '' ) . trim ( )
const pgUrl = requireDbUrlForEnv ( )
if ( ! r . found || ltd === '' || seen . has ( r . clientId ) ) { skipped ++ ; continue }
if ( pgUrl !== '' ) {
seen . add ( r . clientId )
console . log ( ` [db] engine: postgres ${ pgTargetDescription ( pgUrl ) } ` )
const cur = await db . get < { name : string } > ( ` SELECT name FROM client WHERE id=? ` , r . clientId )
} else {
if ( cur === undefined ) { skipped ++ ; continue }
console . log ( ` [db] engine: sqlite at ${ sqliteFilePath ( process . env [ 'HQ_DATA_DIR' ] ) } ` )
// Already carries this number (bare, or "LTD. K 1028" with spaces/punct)? Don't duplicate.
}
// Compare with all non-alphanumerics stripped so "K 1028" matches "K1028".
const db : DB = pgUrl !== '' ? await openPgDb ( pgUrl ) : openDb ( process . env [ 'HQ_DATA_DIR' ] )
const squish = ( s : string ) = > s . toUpperCase ( ) . replace ( /[^A-Z0-9]/g , '' )
try {
if ( squish ( cur . name ) . includes ( squish ( ltd ) ) ) { already ++ ; continue }
let applied = 0 , already = 0 , skipped = 0
const newName = ` ${ cur . name } LTD NO. ${ ltd } `
const seen = new Set < string > ( )
await updateClient ( db , 'system' , r . clientId , { name : newName } )
for ( const r of results ) {
applied ++
const ltd = ( r . ltdNo ? ? '' ) . trim ( )
if ( ! r . found || ltd === '' || seen . has ( r . clientId ) ) { skipped ++ ; continue }
seen . add ( r . clientId )
const cur = await db . get < { name : string } > ( ` SELECT name FROM client WHERE id=? ` , r . clientId )
if ( cur === undefined ) { skipped ++ ; continue }
// Already carries this number (bare, or "LTD. K 1028" with spaces/punct)? Don't duplicate.
// Compare with all non-alphanumerics stripped so "K 1028" matches "K1028".
const squish = ( s : string ) = > s . toUpperCase ( ) . replace ( /[^A-Z0-9]/g , '' )
if ( squish ( cur . name ) . includes ( squish ( ltd ) ) ) { already ++ ; continue }
const newName = ` ${ cur . name } LTD NO. ${ ltd } `
await updateClient ( db , 'system' , r . clientId , { name : newName } )
applied ++
}
// eslint-disable-next-line no-console
console . log ( ` LTD numbers: ${ applied } appended, ${ already } already present, ${ skipped } skipped (not found / no number). ` )
} finally {
await db . close ( )
}
}
// eslint-disable-next-line no-console
console . log ( ` LTD numbers: ${ applied } appended, ${ already } already present, ${ skipped } skipped (not found / no number). ` )
}
}
main ( ) . catch ( ( e ) = > { console . error ( e ) ; process . exit ( 1 ) } )
main ( ) . catch ( ( e ) = > { console . error ( e ) ; process . exit ( 1 ) } )