Keep prod users local and fix post-restore id sequences.

Prod restore skips users/session/audit, syncs serial sequences after load, and user create re-aligns users_id_seq so new accounts are not misreported as duplicates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Danila Khodjaef
2026-08-05 19:26:52 +03:00
co-authored by Cursor
parent 8a68e98258
commit cfee69c9a6
7 changed files with 83 additions and 9 deletions
+47 -1
View File
@@ -19,7 +19,47 @@ const { printCliResult } = require('./lib/cli-result');
const { Client } = pg;
// Prod restore keeps these tables untouched (no TRUNCATE, no INSERT from dev backup).
const PROD_RESTORE_SKIP_TABLES = new Set(['curator_audit_log']);
// Staff accounts, sessions, and audit history stay env-local — never overwrite from gallery_dev.
const PROD_RESTORE_SKIP_TABLES = new Set(['users', 'session', 'curator_audit_log']);
function quoteIdent(name) {
return `"${String(name).replace(/"/g, '""')}"`;
}
/** Align serial/identity sequences with MAX(column) after explicit-id INSERTs. */
async function syncSerialSequences(client) {
const { rows } = await client.query(
`SELECT
c.relname AS table_name,
a.attname AS column_name,
pg_get_serial_sequence(format('%I.%I', n.nspname, c.relname), a.attname) AS seq_name
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped
JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum
WHERE c.relkind = 'r'
AND n.nspname = 'public'
AND pg_get_expr(d.adbin, d.adrelid) LIKE 'nextval(%'`
);
let synced = 0;
for (const row of rows) {
if (!row.seq_name) continue;
await client.query(
`SELECT setval(
$1::regclass,
GREATEST(
1,
COALESCE((SELECT MAX(${quoteIdent(row.column_name)}) FROM ${quoteIdent(row.table_name)}), 1)
),
true
)`,
[row.seq_name]
);
synced += 1;
}
return synced;
}
function getInsertTableName(statement) {
const match = statement.match(/^INSERT INTO "([^"]+)"/i)
@@ -239,6 +279,12 @@ async function main() {
}
}
// Backups insert explicit primary keys; without this, serial nextval() can
// collide with existing ids (e.g. creating a user fails as "already exists").
console.log('Syncing serial sequences to MAX(id)...');
const synced = await syncSerialSequences(client);
console.log(` synced ${synced} sequence(s)`);
await client.end();
console.log(`Restore complete: ${restored} statements into "${dbName}".`);
if (skippedInserts > 0) {