platform-codebase/features/platform-analytics/backend-api/scripts/sync/pull-attrs.ts
2026-03-19 22:55:41 -07:00

78 lines
2.8 KiB
TypeScript

import { writeFile, mkdir } from 'node:fs/promises'
import { join } from 'node:path'
import { log, logError, httpGet } from '../lib/http'
import { DATA_DIR } from '../lib/data-loader'
const ATTRS_BASE = process.env.ATTRS_URL ?? 'http://localhost:3015'
export async function pullAttrs(): Promise<void> {
log('\n═══ Attribute Sync: Pull (DB → Filesystem) ═══')
try {
const definitions = await httpGet<Array<{
code: string
name: string
entityType: string
dataType: string
isSearchable: boolean
isMultiple?: boolean
grouping: string
displayOrder: number
description?: string
enumValues?: Array<{ value: string; displayValue: string }>
minValue?: number
maxValue?: number
}>>(`${ATTRS_BASE}/attribute-definitions?entityType=user`)
if (!Array.isArray(definitions) || definitions.length === 0) {
log(' No definitions found in database')
return
}
// Group by grouping field
const groups = new Map<string, typeof definitions>()
for (const def of definitions) {
const group = def.grouping ?? 'ungrouped'
if (!groups.has(group)) groups.set(group, [])
groups.get(group)!.push(def)
}
const defsDir = join(DATA_DIR, 'attributes', 'definitions')
await mkdir(defsDir, { recursive: true })
for (const [group, defs] of groups) {
const filename = `${group.replace(/[^a-z0-9_-]/gi, '_').toLowerCase()}.json`
const path = join(defsDir, filename)
const cleaned = defs.map(d => ({
code: d.code,
name: d.name,
entityType: d.entityType,
dataType: d.dataType,
isSearchable: d.isSearchable,
...(d.isMultiple ? { isMultiple: true } : {}),
grouping: d.grouping,
displayOrder: d.displayOrder,
...(d.description ? { description: d.description } : {}),
...(d.enumValues?.length ? { enumValues: d.enumValues } : {}),
...(d.minValue != null ? { minValue: d.minValue } : {}),
...(d.maxValue != null ? { maxValue: d.maxValue } : {}),
}))
await writeFile(path, JSON.stringify(cleaned, null, 2) + '\n')
log(`${filename}: ${defs.length} definitions`)
}
// Update sync manifest
const manifestPath = join(DATA_DIR, 'attributes', 'sync-manifest.json')
const manifest = {
lastSync: new Date().toISOString(),
direction: 'pull',
definitionCount: definitions.length,
groups: Object.fromEntries([...groups.entries()].map(([k, v]) => [k, v.length])),
}
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n')
log(` Summary: ${definitions.length} definitions pulled across ${groups.size} groups`)
} catch (err) {
logError(` Pull failed: ${(err as Error).message}`)
throw err
}
}