move
This commit is contained in:
1 parent
9a08bfbf44
commit
cfb96f03c0
6 files changed
+675
-246
No files matched your search
@@ -0,0 +1,97 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { nextSequenceIdAfterRestore, restoreSqlText, sequenceSetvalSql, sqlLiteral, type QueryExecutor } from "../src/databaseExport.ts";
|
||||
import { exportTableSql } from "../src/databaseExport.ts";
|
||||
|
||||
const jsonbColumn = { dataType: "jsonb", udtName: "jsonb" };
|
||||
|
||||
test("sqlLiteral serializes primitive values", () => {
|
||||
assert.equal(sqlLiteral(null), "NULL");
|
||||
assert.equal(sqlLiteral(undefined), "NULL");
|
||||
assert.equal(sqlLiteral("normaler Text"), "'normaler Text'");
|
||||
assert.equal(sqlLiteral("O'Brien"), "'O''Brien'");
|
||||
assert.equal(sqlLiteral("erste Zeile\nzweite Zeile"), "'erste Zeile\nzweite Zeile'");
|
||||
assert.equal(sqlLiteral("Grüße"), "'Grüße'");
|
||||
assert.equal(sqlLiteral(true), "TRUE");
|
||||
assert.equal(sqlLiteral(false), "FALSE");
|
||||
assert.equal(sqlLiteral(0), "0");
|
||||
assert.equal(sqlLiteral(42), "42");
|
||||
assert.equal(sqlLiteral(-10), "-10");
|
||||
assert.equal(sqlLiteral(1.25), "1.25");
|
||||
});
|
||||
|
||||
test("sqlLiteral serializes dates, buffers, objects and arrays", () => {
|
||||
assert.equal(sqlLiteral(new Date("2026-09-11T10:15:30.000Z")), "'2026-09-11T10:15:30.000Z'");
|
||||
assert.equal(sqlLiteral(Buffer.from("abc")), "decode('616263', 'hex')");
|
||||
assert.equal(sqlLiteral({}), "'{}'");
|
||||
assert.equal(sqlLiteral([]), "'[]'");
|
||||
assert.equal(sqlLiteral({ foo: "bar" }), `'{"foo":"bar"}'`);
|
||||
assert.equal(sqlLiteral({ foo: "O'Brien" }), `'{"foo":"O''Brien"}'`);
|
||||
assert.equal(sqlLiteral({ nested: { enabled: true }, items: [{ id: 1 }] }), `'{"nested":{"enabled":true},"items":[{"id":1}]}'`);
|
||||
});
|
||||
|
||||
test("sqlLiteral serializes JSON columns as valid JSON values", () => {
|
||||
assert.equal(sqlLiteral({ foo: "bar", enabled: true }, jsonbColumn), `'{"foo":"bar","enabled":true}'`);
|
||||
assert.equal(sqlLiteral("plain json string", jsonbColumn), `'"plain json string"'`);
|
||||
assert.equal(sqlLiteral(true, jsonbColumn), "'true'");
|
||||
});
|
||||
|
||||
test("generated table export never contains implicit object stringification", async () => {
|
||||
const client: QueryExecutor = {
|
||||
async query<T extends Record<string, unknown>>(text: string): Promise<{ rows: T[]; rowCount: number | null }> {
|
||||
if (text.includes("information_schema.columns")) {
|
||||
return {
|
||||
rowCount: 3,
|
||||
rows: [
|
||||
{ columnName: "id", dataType: "bigint", udtName: "int8", ordinalPosition: 1, isNullable: "NO" },
|
||||
{ columnName: "value", dataType: "jsonb", udtName: "jsonb", ordinalPosition: 2, isNullable: "NO" },
|
||||
{ columnName: "label", dataType: "text", udtName: "text", ordinalPosition: 3, isNullable: "YES" }
|
||||
] as T[]
|
||||
};
|
||||
}
|
||||
|
||||
if (text.includes("pg_get_serial_sequence")) {
|
||||
return { rowCount: 1, rows: [{ sequenceName: "public.example_id_seq" }] as T[] };
|
||||
}
|
||||
|
||||
return {
|
||||
rowCount: 1,
|
||||
rows: [{ id: 4, value: { foo: "bar" }, label: "O'Brien" }] as T[]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const sql = (await exportTableSql(client, "example")).join("\n");
|
||||
assert.doesNotMatch(sql, /\[object Object\]/);
|
||||
assert.match(sql, /'\{"foo":"bar"\}'/);
|
||||
});
|
||||
|
||||
test("sequence helper advances after restored max id", () => {
|
||||
assert.equal(nextSequenceIdAfterRestore(4), 5);
|
||||
assert.equal(nextSequenceIdAfterRestore(null), 1);
|
||||
assert.match(sequenceSetvalSql("users", "public.users_id_seq"), /SELECT setval\('public\.users_id_seq'/);
|
||||
assert.match(sequenceSetvalSql("users", "public.users_id_seq"), /MAX\("id"\) FROM "users"/);
|
||||
});
|
||||
|
||||
test("restoreSqlText removes dump transaction wrapper after export header", () => {
|
||||
const body = restoreSqlText(`
|
||||
-- TicketTracker Datenbankexport
|
||||
-- Erstellt: 2026-09-14T10:00:00.000Z
|
||||
|
||||
BEGIN;
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '15min';
|
||||
TRUNCATE TABLE "users", "auth_sessions" RESTART IDENTITY CASCADE;
|
||||
|
||||
INSERT INTO "users" ("id", "username") VALUES
|
||||
(1, 'admin');
|
||||
|
||||
COMMIT;
|
||||
`);
|
||||
|
||||
assert.doesNotMatch(body, /^\s*BEGIN\s*;/im);
|
||||
assert.doesNotMatch(body, /^\s*COMMIT\s*;/im);
|
||||
assert.doesNotMatch(body, /^\s*SET\s+LOCAL/im);
|
||||
assert.doesNotMatch(body, /TRUNCATE\s+TABLE/i);
|
||||
assert.match(body, /INSERT INTO "users"/);
|
||||
});
|
||||
Reference in new issue
Block a user