MCPcopy Index your code
hub / github.com/simstudioai/sim / runRepair

Function runRepair

apps/sim/scripts/repair-table-order-key-collation.ts:47–159  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

45const WRITE_CHUNK_SIZE = 5000
46
47export async function runRepair(): Promise<void> {
48 const dryRun = process.argv.includes('--dry-run')
49 const connectionString = process.env.DATABASE_URL ?? process.env.POSTGRES_URL
50 if (!connectionString) {
51 console.error('Missing DATABASE_URL or POSTGRES_URL')
52 process.exit(1)
53 }
54
55 const client = postgres(connectionString, {
56 prepare: false,
57 idle_timeout: 20,
58 connect_timeout: 30,
59 max: 5,
60 onnotice: () => {},
61 })
62 const db = drizzle(client)
63
64 const stats = { tables: 0, tablesKeyed: 0, rowsKeyed: 0, failed: 0 }
65
66 try {
67 // Tables with a bytewise (`COLLATE "C"`) inversion or duplicate among their
68 // non-null keys. Walking rows in their authoritative `position, id` order (the
69 // order the re-key writes), a healthy table has strictly INCREASING keys; flag
70 // any table where a row's key is `>=` the next row's. Ordering by `position`
71 // (not by `order_key`) is what makes this detect actual mis-assignment — e.g.
72 // pos 0 holding "a0" while pos 1 holds "Zz" (bytewise "Zz" < "a0") — and not
73 // just adjacent duplicates. The explicit `COLLATE "C"` keeps the comparison
74 // bytewise whether or not migration 0228 has been applied yet.
75 const pending = await db.execute<{ table_id: string }>(sql`
76 SELECT DISTINCT table_id FROM (
77 SELECT
78 table_id,
79 order_key,
80 LEAD(order_key) OVER (
81 PARTITION BY table_id ORDER BY position, id
82 ) AS next_key
83 FROM user_table_rows
84 WHERE order_key IS NOT NULL
85 ) t
86 WHERE next_key IS NOT NULL AND order_key COLLATE "C" >= next_key COLLATE "C"
87 `)
88
89 console.log(
90 `Repair starting — ${pending.length} table(s) with mis-ordered keys${dryRun ? ' [DRY RUN]' : ''}`
91 )
92
93 for (const { table_id: tableId } of pending) {
94 stats.tables += 1
95 try {
96 if (dryRun) {
97 // Sizing only — count outside any transaction/lock so we never serialize
98 // live inserts on the table (taking the advisory lock just to count would
99 // make the dry run the opposite of safe).
100 const [row] = await db
101 .select({ rowCount: sql<number>`count(*)`.mapWith(Number) })
102 .from(userTableRows)
103 .where(eq(userTableRows.tableId, tableId))
104 stats.tablesKeyed += 1

Calls 7

nKeysBetweenFunction · 0.90
getErrorMessageFunction · 0.90
errorMethod · 0.80
logMethod · 0.80
joinMethod · 0.80
executeMethod · 0.65
eqFunction · 0.50

Tested by

no test coverage detected