Release: weekly deploy
This commit is contained in:
@@ -32,6 +32,11 @@ function sqlLiteral(value) {
|
||||
if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';
|
||||
if (value instanceof Date) return `'${value.toISOString()}'`;
|
||||
if (typeof value === 'number' || typeof value === 'bigint') return String(value);
|
||||
// node-pg returns JS arrays for Postgres array columns (e.g. users.permissions TEXT[])
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length === 0) return `ARRAY[]::text[]`;
|
||||
return `ARRAY[${value.map((item) => sqlLiteral(item)).join(', ')}]`;
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
return `'${JSON.stringify(value).replace(/'/g, "''")}'`;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,28 @@ function getInsertTableName(statement) {
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Older backups serialized TEXT[] (e.g. users.permissions) via JSON.stringify,
|
||||
* producing '["a","b"]' which Postgres rejects as an array literal. Rewrite
|
||||
* JSON string-array literals to ARRAY['a','b']::text[].
|
||||
*/
|
||||
function coerceJsonStringArrayLiterals(statement) {
|
||||
return statement.replace(/'(\[(?:"(?:\\.|[^"\\])*"(?:\s*,\s*"(?:\\.|[^"\\])*")*)?\])'/g, (full, jsonBody) => {
|
||||
let arr;
|
||||
try {
|
||||
arr = JSON.parse(jsonBody);
|
||||
} catch {
|
||||
return full;
|
||||
}
|
||||
if (!Array.isArray(arr) || !arr.every((item) => typeof item === 'string')) {
|
||||
return full;
|
||||
}
|
||||
if (arr.length === 0) return `ARRAY[]::text[]`;
|
||||
const items = arr.map((s) => `'${String(s).replace(/'/g, "''")}'`).join(', ');
|
||||
return `ARRAY[${items}]::text[]`;
|
||||
});
|
||||
}
|
||||
|
||||
function filterInsertsForRestore(inserts, prod) {
|
||||
if (!prod) return inserts;
|
||||
return inserts.filter((statement) => {
|
||||
@@ -113,7 +135,9 @@ async function main() {
|
||||
|
||||
const config = prod ? loadProdPgConfig() : loadDevPgConfig();
|
||||
const dbName = config.database;
|
||||
const allInserts = extractInsertStatements(fs.readFileSync(filePath, 'utf8'));
|
||||
const allInserts = extractInsertStatements(fs.readFileSync(filePath, 'utf8')).map(
|
||||
coerceJsonStringArrayLiterals
|
||||
);
|
||||
const inserts = filterInsertsForRestore(allInserts, prod);
|
||||
const skippedInserts = prod ? allInserts.length - inserts.length : 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user