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:
co-authored by
Cursor
parent
8a68e98258
commit
cfee69c9a6
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user