@linkforty/core 1.41.2 → 1.41.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/lib/database.d.ts +15 -0
- package/dist/lib/database.d.ts.map +1 -1
- package/dist/lib/database.js +36 -2
- package/dist/lib/database.js.map +1 -1
- package/dist/lib/database.test.js +73 -0
- package/dist/lib/database.test.js.map +1 -1
- package/dist/lib/schema-guard.d.ts +46 -0
- package/dist/lib/schema-guard.d.ts.map +1 -0
- package/dist/lib/schema-guard.js +135 -0
- package/dist/lib/schema-guard.js.map +1 -0
- package/dist/lib/schema-guard.test.d.ts +2 -0
- package/dist/lib/schema-guard.test.d.ts.map +1 -0
- package/dist/lib/schema-guard.test.js +83 -0
- package/dist/lib/schema-guard.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -670,6 +670,21 @@ await fastify.register(linkRoutes);
|
|
|
670
670
|
await fastify.listen({ port: 3000 });
|
|
671
671
|
```
|
|
672
672
|
|
|
673
|
+
#### Starting while the database is busy
|
|
674
|
+
|
|
675
|
+
`initializeDatabase()` creates or updates the schema on every start. Postgres takes a table's lock *before* it evaluates `IF NOT EXISTS`, so a statement such as `ALTER TABLE links ADD COLUMN IF NOT EXISTS …` for a column that already exists would still request an exclusive lock on `links` — and if a long statement (a retention job, a large export) holds that table, the request waits, and every later query on the table, redirects included, queues behind it until the long statement ends. To keep a routine start from ever doing that, statements whose effect already exists are answered from the catalog and never sent, and you can bound the wait for the rest:
|
|
676
|
+
|
|
677
|
+
```typescript
|
|
678
|
+
await initializeDatabase({
|
|
679
|
+
url: 'postgresql://localhost/linkforty',
|
|
680
|
+
// A schema change that waits longer than this fails the start with
|
|
681
|
+
// SQLSTATE 55P03 rather than queueing the table. Retry or restart.
|
|
682
|
+
lockTimeoutMs: 5000,
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
The timeout applies only to the initialisation session and is reset before that connection returns to the pool. When adding schema statements of your own, use the idempotent shapes (`ADD COLUMN IF NOT EXISTS`, `CREATE INDEX IF NOT EXISTS`, `DROP CONSTRAINT IF EXISTS`) or a `DO $$ … IF NOT EXISTS (SELECT … FROM information_schema …)` block, never a bare `ALTER` that asks for a lock on every start.
|
|
687
|
+
|
|
673
688
|
## Deployment
|
|
674
689
|
|
|
675
690
|
LinkForty can be deployed in multiple ways depending on your needs:
|
package/dist/lib/database.d.ts
CHANGED
|
@@ -5,6 +5,21 @@ export interface DatabaseOptions {
|
|
|
5
5
|
min?: number;
|
|
6
6
|
max?: number;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* How long a schema statement at initialisation may wait for a table lock,
|
|
10
|
+
* in milliseconds. Unset (the default) means it waits as long as Postgres
|
|
11
|
+
* lets it.
|
|
12
|
+
*
|
|
13
|
+
* Postgres takes a table's lock before it evaluates `IF NOT EXISTS`, so an
|
|
14
|
+
* `ALTER TABLE … ADD COLUMN IF NOT EXISTS` for a column that already exists
|
|
15
|
+
* still asks for ACCESS EXCLUSIVE. Statements whose effect already exists
|
|
16
|
+
* are answered from the catalog and never sent, so this only matters for
|
|
17
|
+
* statements that genuinely change the schema. When one of those waits
|
|
18
|
+
* longer than this, `initializeDatabase()` fails with SQLSTATE `55P03`
|
|
19
|
+
* instead of parking a lock request that every later query on the table
|
|
20
|
+
* would queue behind; the host decides whether to retry or restart.
|
|
21
|
+
*/
|
|
22
|
+
lockTimeoutMs?: number;
|
|
8
23
|
}
|
|
9
24
|
export declare let db: pg.Pool;
|
|
10
25
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAKpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF;;;;;;;;;;;;;OAaG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA4BvB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,yFAAyF;AACzF,eAAO,MAAM,6BAA6B,UAAU,CAAC;AAErD,oGAAoG;AACpG,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAGnD,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBAuwBrE"}
|
package/dist/lib/database.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pg from 'pg';
|
|
2
|
+
import { guardSchemaClient, isLockTimeout } from './schema-guard.js';
|
|
2
3
|
const { Pool } = pg;
|
|
3
4
|
export let db;
|
|
4
5
|
// Helper function to wait for a specified time
|
|
@@ -54,7 +55,15 @@ export async function initializeDatabase(options = {}) {
|
|
|
54
55
|
db.on('error', (error) => {
|
|
55
56
|
console.error('Database connection lost while idle; it will be replaced:', error.message);
|
|
56
57
|
});
|
|
57
|
-
const
|
|
58
|
+
const raw = await connectWithRetry();
|
|
59
|
+
// Idempotent statements whose effect already exists (a column, an index, an
|
|
60
|
+
// absent constraint, a settled NOT NULL) are answered from the catalog and
|
|
61
|
+
// never reach Postgres, so a routine start never asks for a table lock it
|
|
62
|
+
// does not need. See schema-guard.ts for why that matters.
|
|
63
|
+
const client = guardSchemaClient(raw);
|
|
64
|
+
const lockTimeoutMs = Number.isFinite(options.lockTimeoutMs) && options.lockTimeoutMs > 0
|
|
65
|
+
? Math.trunc(options.lockTimeoutMs)
|
|
66
|
+
: null;
|
|
58
67
|
// Serialise schema initialisation across processes.
|
|
59
68
|
//
|
|
60
69
|
// `CREATE TABLE IF NOT EXISTS` is not atomic: the existence check and the
|
|
@@ -79,6 +88,12 @@ export async function initializeDatabase(options = {}) {
|
|
|
79
88
|
try {
|
|
80
89
|
await client.query('SELECT pg_advisory_lock($1)', [SCHEMA_INIT_LOCK_KEY]);
|
|
81
90
|
lockHeld = true;
|
|
91
|
+
// Set after the advisory lock is held: waiting for another instance's
|
|
92
|
+
// initialisation is wanted, waiting for a table lock is not. Session-level
|
|
93
|
+
// on this client only; RESET below before it goes back to the pool.
|
|
94
|
+
if (lockTimeoutMs !== null) {
|
|
95
|
+
await raw.query(`SET lock_timeout = ${lockTimeoutMs}`);
|
|
96
|
+
}
|
|
82
97
|
// Organizations table (must be created before links, which references it).
|
|
83
98
|
//
|
|
84
99
|
// The redirect path LEFT JOINs this table to read `settings.appConfig`, which
|
|
@@ -705,13 +720,32 @@ export async function initializeDatabase(options = {}) {
|
|
|
705
720
|
END IF;
|
|
706
721
|
END $$;
|
|
707
722
|
`);
|
|
708
|
-
|
|
723
|
+
if (client.skipped.length > 0) {
|
|
724
|
+
console.log(`Database schema initialized successfully (${client.skipped.length} statement(s) already applied, not re-sent)`);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
console.log('Database schema initialized successfully');
|
|
728
|
+
}
|
|
709
729
|
}
|
|
710
730
|
catch (error) {
|
|
731
|
+
if (isLockTimeout(error)) {
|
|
732
|
+
// Say what happened in operator terms and keep the SQLSTATE so a host
|
|
733
|
+
// can recognise it and retry the start with backoff.
|
|
734
|
+
const wrapped = new Error(`Schema initialisation waited ${lockTimeoutMs} ms for a table lock and gave up ` +
|
|
735
|
+
`(another statement is holding the table; retry the start once it finishes): ${error.message}`);
|
|
736
|
+
wrapped.code = error.code;
|
|
737
|
+
console.error('Error initializing database:', wrapped.message);
|
|
738
|
+
throw wrapped;
|
|
739
|
+
}
|
|
711
740
|
console.error('Error initializing database:', error);
|
|
712
741
|
throw error;
|
|
713
742
|
}
|
|
714
743
|
finally {
|
|
744
|
+
if (lockTimeoutMs !== null) {
|
|
745
|
+
// The client returns to the shared pool: the timeout must not follow it
|
|
746
|
+
// into request handling.
|
|
747
|
+
await raw.query('RESET lock_timeout').catch(() => undefined);
|
|
748
|
+
}
|
|
715
749
|
if (lockHeld) {
|
|
716
750
|
// Best effort: a broken connection has already dropped the lock, and
|
|
717
751
|
// failing to unlock must not mask the error that got us here.
|
package/dist/lib/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -77,6 +77,79 @@ describe.skipIf(!ADMIN_URL)('initializeDatabase schema lock', () => {
|
|
|
77
77
|
}
|
|
78
78
|
}, 30000);
|
|
79
79
|
});
|
|
80
|
+
describe.skipIf(!ADMIN_URL)('initialisation against a table someone is reading', () => {
|
|
81
|
+
// Postgres takes a table's lock before it evaluates IF NOT EXISTS, so a
|
|
82
|
+
// second start used to park an ACCESS EXCLUSIVE request on `links` behind
|
|
83
|
+
// any long reader — and every redirect behind that. With the catalog guard
|
|
84
|
+
// nothing is sent for a column that exists, and with a lock timeout a
|
|
85
|
+
// statement that does need the table gives up instead of queueing it.
|
|
86
|
+
const scratchName = `lf_core_schema_guard_${Date.now()}`;
|
|
87
|
+
let admin;
|
|
88
|
+
let scratchUrl;
|
|
89
|
+
const pools = [];
|
|
90
|
+
beforeAll(async () => {
|
|
91
|
+
admin = new pg.Client({ connectionString: ADMIN_URL });
|
|
92
|
+
await admin.connect();
|
|
93
|
+
await admin.query(`CREATE DATABASE ${scratchName}`);
|
|
94
|
+
const url = new URL(ADMIN_URL);
|
|
95
|
+
url.pathname = `/${scratchName}`;
|
|
96
|
+
scratchUrl = url.toString();
|
|
97
|
+
// First start: every table, column and index exists afterwards.
|
|
98
|
+
await initializeDatabase({ url: scratchUrl, pool: { min: 1, max: 2 } });
|
|
99
|
+
pools.push(db);
|
|
100
|
+
}, 60000);
|
|
101
|
+
afterAll(async () => {
|
|
102
|
+
for (const p of pools)
|
|
103
|
+
await p.end().catch(() => undefined);
|
|
104
|
+
await db?.end().catch(() => undefined);
|
|
105
|
+
await admin.query(`DROP DATABASE IF EXISTS ${scratchName} WITH (FORCE)`);
|
|
106
|
+
await admin.end();
|
|
107
|
+
}, 30000);
|
|
108
|
+
it('a second start completes while a transaction holds ACCESS SHARE on links, and the setting does not leak', async () => {
|
|
109
|
+
const reader = new pg.Client({ connectionString: scratchUrl });
|
|
110
|
+
await reader.connect();
|
|
111
|
+
try {
|
|
112
|
+
await reader.query('BEGIN');
|
|
113
|
+
await reader.query('SELECT 1 FROM links LIMIT 1');
|
|
114
|
+
const started = Date.now();
|
|
115
|
+
await initializeDatabase({ url: scratchUrl, pool: { min: 1, max: 2 }, lockTimeoutMs: 2000 });
|
|
116
|
+
pools.push(db);
|
|
117
|
+
// Nothing waited: well under a single lock timeout.
|
|
118
|
+
expect(Date.now() - started).toBeLessThan(10000);
|
|
119
|
+
// The reader was never blocked either.
|
|
120
|
+
const t = Date.now();
|
|
121
|
+
await reader.query('SELECT 1 FROM links LIMIT 1');
|
|
122
|
+
expect(Date.now() - t).toBeLessThan(1000);
|
|
123
|
+
// The timeout was session-level on the initialisation client and was
|
|
124
|
+
// reset before that client went back to the pool.
|
|
125
|
+
const { rows } = await db.query('SHOW lock_timeout');
|
|
126
|
+
expect(rows[0].lock_timeout).toBe('0');
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await reader.query('ROLLBACK').catch(() => undefined);
|
|
130
|
+
await reader.end();
|
|
131
|
+
}
|
|
132
|
+
}, 60000);
|
|
133
|
+
it('a statement that does need the table fails with 55P03 after the timeout instead of queueing it', async () => {
|
|
134
|
+
const reader = new pg.Client({ connectionString: scratchUrl });
|
|
135
|
+
const other = new pg.Client({ connectionString: scratchUrl });
|
|
136
|
+
await reader.connect();
|
|
137
|
+
await other.connect();
|
|
138
|
+
try {
|
|
139
|
+
await reader.query('BEGIN');
|
|
140
|
+
await reader.query('SELECT 1 FROM links LIMIT 1');
|
|
141
|
+
await other.query('SET lock_timeout = 1000');
|
|
142
|
+
const t = Date.now();
|
|
143
|
+
await expect(other.query('ALTER TABLE links ADD COLUMN probe_column_not_guarded INTEGER')).rejects.toMatchObject({ code: '55P03' });
|
|
144
|
+
expect(Date.now() - t).toBeLessThan(5000);
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await reader.query('ROLLBACK').catch(() => undefined);
|
|
148
|
+
await reader.end();
|
|
149
|
+
await other.end();
|
|
150
|
+
}
|
|
151
|
+
}, 30000);
|
|
152
|
+
});
|
|
80
153
|
describe.skipIf(!ADMIN_URL)('idle connection errors', () => {
|
|
81
154
|
const scratchName = `lf_core_idle_error_${Date.now()}`;
|
|
82
155
|
let admin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.test.js","sourceRoot":"","sources":["../../src/lib/database.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"database.test.js","sourceRoot":"","sources":["../../src/lib/database.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type pg from 'pg';
|
|
2
|
+
/**
|
|
3
|
+
* Schema statements that never ask Postgres for a lock they do not need.
|
|
4
|
+
*
|
|
5
|
+
* Postgres acquires a table's lock *before* it evaluates `IF NOT EXISTS`. An
|
|
6
|
+
* `ALTER TABLE … ADD COLUMN IF NOT EXISTS` for a column that has existed for a
|
|
7
|
+
* year still requests ACCESS EXCLUSIVE on the table; `CREATE INDEX IF NOT
|
|
8
|
+
* EXISTS` for an index that exists still requests SHARE. If anything long is
|
|
9
|
+
* reading or writing the table at that moment — a retention job, a large
|
|
10
|
+
* export, an analytics rebuild — the request waits, and Postgres then queues
|
|
11
|
+
* every later request on the table behind the waiting one. A routine start of
|
|
12
|
+
* a second instance becomes a stall of the whole table for as long as the long
|
|
13
|
+
* statement runs; redirects included, since they read `links`.
|
|
14
|
+
*
|
|
15
|
+
* `guardSchemaClient` wraps the initialisation client and answers the
|
|
16
|
+
* idempotent statement shapes from the catalog first: a column that exists, an
|
|
17
|
+
* index that exists, a constraint that is already gone, a NOT NULL that is
|
|
18
|
+
* already set or dropped. Those statements never reach Postgres, so they never
|
|
19
|
+
* ask for a lock. Anything else — a new column, a `CREATE TABLE`, a `DO`
|
|
20
|
+
* block, a parameterised query, a string holding several statements — passes
|
|
21
|
+
* through untouched.
|
|
22
|
+
*/
|
|
23
|
+
/** SQLSTATE for "canceling statement due to lock timeout". */
|
|
24
|
+
export declare const LOCK_NOT_AVAILABLE = "55P03";
|
|
25
|
+
export interface Queryable {
|
|
26
|
+
query: (text: string, params?: any[]) => Promise<pg.QueryResult<any>>;
|
|
27
|
+
}
|
|
28
|
+
export interface SchemaClient extends Queryable {
|
|
29
|
+
release: () => void;
|
|
30
|
+
/** Statements answered from the catalog instead of being sent to Postgres. */
|
|
31
|
+
readonly skipped: string[];
|
|
32
|
+
}
|
|
33
|
+
export declare function isLockTimeout(error: unknown): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Decide whether a statement's effect already exists. Returns the reason to
|
|
36
|
+
* skip it, or null to send it to Postgres.
|
|
37
|
+
*/
|
|
38
|
+
export declare function alreadyApplied(client: Queryable, text: string): Promise<string | null>;
|
|
39
|
+
/**
|
|
40
|
+
* A client whose idempotent schema statements are answered from the catalog
|
|
41
|
+
* when their effect already exists, so they never ask Postgres for a lock.
|
|
42
|
+
*/
|
|
43
|
+
export declare function guardSchemaClient(client: Queryable & {
|
|
44
|
+
release: () => void;
|
|
45
|
+
}): SchemaClient;
|
|
46
|
+
//# sourceMappingURL=schema-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-guard.d.ts","sourceRoot":"","sources":["../../src/lib/schema-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAErD;AAwDD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuC5F;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,YAAY,CAgB3F"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema statements that never ask Postgres for a lock they do not need.
|
|
3
|
+
*
|
|
4
|
+
* Postgres acquires a table's lock *before* it evaluates `IF NOT EXISTS`. An
|
|
5
|
+
* `ALTER TABLE … ADD COLUMN IF NOT EXISTS` for a column that has existed for a
|
|
6
|
+
* year still requests ACCESS EXCLUSIVE on the table; `CREATE INDEX IF NOT
|
|
7
|
+
* EXISTS` for an index that exists still requests SHARE. If anything long is
|
|
8
|
+
* reading or writing the table at that moment — a retention job, a large
|
|
9
|
+
* export, an analytics rebuild — the request waits, and Postgres then queues
|
|
10
|
+
* every later request on the table behind the waiting one. A routine start of
|
|
11
|
+
* a second instance becomes a stall of the whole table for as long as the long
|
|
12
|
+
* statement runs; redirects included, since they read `links`.
|
|
13
|
+
*
|
|
14
|
+
* `guardSchemaClient` wraps the initialisation client and answers the
|
|
15
|
+
* idempotent statement shapes from the catalog first: a column that exists, an
|
|
16
|
+
* index that exists, a constraint that is already gone, a NOT NULL that is
|
|
17
|
+
* already set or dropped. Those statements never reach Postgres, so they never
|
|
18
|
+
* ask for a lock. Anything else — a new column, a `CREATE TABLE`, a `DO`
|
|
19
|
+
* block, a parameterised query, a string holding several statements — passes
|
|
20
|
+
* through untouched.
|
|
21
|
+
*/
|
|
22
|
+
/** SQLSTATE for "canceling statement due to lock timeout". */
|
|
23
|
+
export const LOCK_NOT_AVAILABLE = '55P03';
|
|
24
|
+
export function isLockTimeout(error) {
|
|
25
|
+
return typeof error === 'object' && error !== null && error.code === LOCK_NOT_AVAILABLE;
|
|
26
|
+
}
|
|
27
|
+
// One statement only: a trailing semicolon is fine, a second statement is not
|
|
28
|
+
// ours to interpret, so it passes through.
|
|
29
|
+
function single(text) {
|
|
30
|
+
const t = text.trim().replace(/;\s*$/, '');
|
|
31
|
+
return t.includes(';') ? null : t;
|
|
32
|
+
}
|
|
33
|
+
const ident = (raw) => raw.replace(/^"|"$/g, '');
|
|
34
|
+
/** `schema.table` → the table part; the catalog lookups scope to the search path. */
|
|
35
|
+
const tableOf = (raw) => ident(raw.split('.').pop() ?? raw);
|
|
36
|
+
const ALTER_TABLE = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?("?[\w.]+"?)\s+([\s\S]+)$/i;
|
|
37
|
+
const ADD_COLUMN_ACTION = /^\s*ADD\s+COLUMN\s+IF\s+NOT\s+EXISTS\s+("?\w+"?)\b/i;
|
|
38
|
+
// Actions of one ALTER TABLE are split only at a comma that starts another
|
|
39
|
+
// ADD COLUMN IF NOT EXISTS, so commas inside a type (NUMERIC(18,4)), a default
|
|
40
|
+
// or a REFERENCES list stay put.
|
|
41
|
+
const ACTION_SEPARATOR = /,(?=\s*ADD\s+COLUMN\s+IF\s+NOT\s+EXISTS\b)/i;
|
|
42
|
+
const CREATE_INDEX = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:CONCURRENTLY\s+)?IF\s+NOT\s+EXISTS\s+("?\w+"?)\s+ON\b/i;
|
|
43
|
+
const DROP_CONSTRAINT = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?("?[\w.]+"?)\s+DROP\s+CONSTRAINT\s+IF\s+EXISTS\s+("?\w+"?)\s*$/i;
|
|
44
|
+
const SET_NOT_NULL = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?("?[\w.]+"?)\s+ALTER\s+COLUMN\s+("?\w+"?)\s+SET\s+NOT\s+NULL\s*$/i;
|
|
45
|
+
const DROP_NOT_NULL = /^ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?("?[\w.]+"?)\s+ALTER\s+COLUMN\s+("?\w+"?)\s+DROP\s+NOT\s+NULL\s*$/i;
|
|
46
|
+
/** True when a comma remains once quoted strings and parenthesised groups are removed: a second action hides in there. */
|
|
47
|
+
function hasTopLevelComma(action) {
|
|
48
|
+
let s = action.replace(/'[^']*'/g, '');
|
|
49
|
+
for (let prev = ''; prev !== s;) {
|
|
50
|
+
prev = s;
|
|
51
|
+
s = s.replace(/\([^()]*\)/g, '');
|
|
52
|
+
}
|
|
53
|
+
return s.includes(',');
|
|
54
|
+
}
|
|
55
|
+
/** The column names when every action of the ALTER is ADD COLUMN IF NOT EXISTS; null otherwise. */
|
|
56
|
+
function addColumnNames(t) {
|
|
57
|
+
const m = t.match(ALTER_TABLE);
|
|
58
|
+
if (!m)
|
|
59
|
+
return null;
|
|
60
|
+
const columns = [];
|
|
61
|
+
for (const action of m[2].split(ACTION_SEPARATOR)) {
|
|
62
|
+
const a = action.match(ADD_COLUMN_ACTION);
|
|
63
|
+
if (!a || hasTopLevelComma(action))
|
|
64
|
+
return null;
|
|
65
|
+
columns.push(ident(a[1]));
|
|
66
|
+
}
|
|
67
|
+
return columns.length > 0 ? { table: tableOf(m[1]), columns } : null;
|
|
68
|
+
}
|
|
69
|
+
async function columnNullable(client, table, column) {
|
|
70
|
+
const r = await client.query(`SELECT is_nullable FROM information_schema.columns
|
|
71
|
+
WHERE table_schema = ANY(current_schemas(false)) AND table_name = $1 AND column_name = $2`, [table, column]);
|
|
72
|
+
return r.rows[0]?.is_nullable ?? null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Decide whether a statement's effect already exists. Returns the reason to
|
|
76
|
+
* skip it, or null to send it to Postgres.
|
|
77
|
+
*/
|
|
78
|
+
export async function alreadyApplied(client, text) {
|
|
79
|
+
const t = single(text);
|
|
80
|
+
if (!t)
|
|
81
|
+
return null;
|
|
82
|
+
const add = addColumnNames(t);
|
|
83
|
+
if (add) {
|
|
84
|
+
// Skip only when every column exists; Postgres handles a mix itself.
|
|
85
|
+
for (const column of add.columns) {
|
|
86
|
+
if ((await columnNullable(client, add.table, column)) === null)
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return `column${add.columns.length > 1 ? 's' : ''} ${add.table}.${add.columns.join(', ')} exist${add.columns.length > 1 ? '' : 's'}`;
|
|
90
|
+
}
|
|
91
|
+
let m = t.match(CREATE_INDEX);
|
|
92
|
+
if (m) {
|
|
93
|
+
const r = await client.query(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
94
|
+
WHERE c.relkind = 'i' AND c.relname = $1 AND n.nspname = ANY(current_schemas(false))`, [ident(m[1])]);
|
|
95
|
+
return r.rows.length > 0 ? `index ${ident(m[1])} exists` : null;
|
|
96
|
+
}
|
|
97
|
+
m = t.match(DROP_CONSTRAINT);
|
|
98
|
+
if (m) {
|
|
99
|
+
const r = await client.query(`SELECT 1 FROM pg_constraint con JOIN pg_class c ON c.oid = con.conrelid
|
|
100
|
+
WHERE con.conname = $1 AND c.relname = $2`, [ident(m[2]), tableOf(m[1])]);
|
|
101
|
+
return r.rows.length === 0 ? `constraint ${ident(m[2])} already absent` : null;
|
|
102
|
+
}
|
|
103
|
+
m = t.match(SET_NOT_NULL);
|
|
104
|
+
if (m) {
|
|
105
|
+
return (await columnNullable(client, tableOf(m[1]), ident(m[2]))) === 'NO' ? `${tableOf(m[1])}.${ident(m[2])} already NOT NULL` : null;
|
|
106
|
+
}
|
|
107
|
+
m = t.match(DROP_NOT_NULL);
|
|
108
|
+
if (m) {
|
|
109
|
+
return (await columnNullable(client, tableOf(m[1]), ident(m[2]))) === 'YES' ? `${tableOf(m[1])}.${ident(m[2])} already nullable` : null;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const SKIPPED = { rows: [], rowCount: 0, command: 'SKIP', oid: 0, fields: [] };
|
|
114
|
+
/**
|
|
115
|
+
* A client whose idempotent schema statements are answered from the catalog
|
|
116
|
+
* when their effect already exists, so they never ask Postgres for a lock.
|
|
117
|
+
*/
|
|
118
|
+
export function guardSchemaClient(client) {
|
|
119
|
+
const skipped = [];
|
|
120
|
+
return {
|
|
121
|
+
skipped,
|
|
122
|
+
release: () => client.release(),
|
|
123
|
+
async query(text, params) {
|
|
124
|
+
if (!params || params.length === 0) {
|
|
125
|
+
const why = await alreadyApplied(client, text);
|
|
126
|
+
if (why) {
|
|
127
|
+
skipped.push(why);
|
|
128
|
+
return SKIPPED;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return client.query(text, params);
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=schema-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-guard.js","sourceRoot":"","sources":["../../src/lib/schema-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-guard.test.d.ts","sourceRoot":"","sources":["../../src/lib/schema-guard.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { LOCK_NOT_AVAILABLE, alreadyApplied, guardSchemaClient, isLockTimeout } from './schema-guard.js';
|
|
3
|
+
function fakeClient(catalog) {
|
|
4
|
+
const query = vi.fn(async (text, params) => {
|
|
5
|
+
if (text.includes('information_schema.columns')) {
|
|
6
|
+
const hit = (catalog.columns ?? []).find(([t, c]) => t === params[0] && c === params[1]);
|
|
7
|
+
return { rows: hit ? [{ is_nullable: hit[2] }] : [], rowCount: hit ? 1 : 0 };
|
|
8
|
+
}
|
|
9
|
+
if (text.includes('pg_class c JOIN pg_namespace')) {
|
|
10
|
+
return { rows: (catalog.indexes ?? []).includes(params[0]) ? [{}] : [], rowCount: 0 };
|
|
11
|
+
}
|
|
12
|
+
if (text.includes('pg_constraint')) {
|
|
13
|
+
const hit = (catalog.constraints ?? []).some(([n, t]) => n === params[0] && t === params[1]);
|
|
14
|
+
return { rows: hit ? [{}] : [], rowCount: 0 };
|
|
15
|
+
}
|
|
16
|
+
return { rows: [], rowCount: 0, command: 'SENT' };
|
|
17
|
+
});
|
|
18
|
+
return { query, release: vi.fn() };
|
|
19
|
+
}
|
|
20
|
+
describe('alreadyApplied', () => {
|
|
21
|
+
it('answers an existing column, index, absent constraint and settled NOT NULL from the catalog', async () => {
|
|
22
|
+
const c = fakeClient({
|
|
23
|
+
columns: [['links', 'append_click_id', 'YES'], ['links', 'warn_at', 'YES'], ['users', 'password_hash', 'YES']],
|
|
24
|
+
indexes: ['idx_clicks_link_id'],
|
|
25
|
+
constraints: [['present_key', 'events']],
|
|
26
|
+
});
|
|
27
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS append_click_id BOOLEAN DEFAULT false')).toMatch(/exists/);
|
|
28
|
+
expect(await alreadyApplied(c, ' ALTER TABLE "links" ADD COLUMN IF NOT EXISTS "append_click_id" BOOLEAN;\n')).toMatch(/exists/);
|
|
29
|
+
expect(await alreadyApplied(c, 'ALTER TABLE public.links ADD COLUMN IF NOT EXISTS warn_at TIMESTAMPTZ')).toMatch(/exists/);
|
|
30
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links\n ADD COLUMN IF NOT EXISTS append_click_id BOOLEAN,\n ADD COLUMN IF NOT EXISTS warn_at TIMESTAMPTZ')).toBe('columns links.append_click_id, warn_at exist');
|
|
31
|
+
expect(await alreadyApplied(c, 'CREATE INDEX IF NOT EXISTS idx_clicks_link_id ON click_events(link_id)')).toMatch(/exists/);
|
|
32
|
+
expect(await alreadyApplied(c, 'CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS idx_clicks_link_id ON click_events(link_id)')).toMatch(/exists/);
|
|
33
|
+
expect(await alreadyApplied(c, 'ALTER TABLE events DROP CONSTRAINT IF EXISTS gone_key')).toMatch(/absent/);
|
|
34
|
+
expect(await alreadyApplied(c, 'ALTER TABLE users ALTER COLUMN password_hash DROP NOT NULL')).toMatch(/already nullable/);
|
|
35
|
+
});
|
|
36
|
+
it('sends statements whose effect is missing, and anything it does not understand', async () => {
|
|
37
|
+
const c = fakeClient({ columns: [['users', 'password_hash', 'NO'], ['links', 'warn_at', 'YES']], constraints: [['present_key', 'events']] });
|
|
38
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS brand_new TEXT')).toBeNull();
|
|
39
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS warn_at TIMESTAMPTZ, ADD COLUMN IF NOT EXISTS brand_new INTEGER NOT NULL DEFAULT 0')).toBeNull();
|
|
40
|
+
expect(await alreadyApplied(c, 'CREATE INDEX IF NOT EXISTS idx_missing ON links(id)')).toBeNull();
|
|
41
|
+
expect(await alreadyApplied(c, 'ALTER TABLE events DROP CONSTRAINT IF EXISTS present_key')).toBeNull();
|
|
42
|
+
expect(await alreadyApplied(c, 'ALTER TABLE users ALTER COLUMN password_hash DROP NOT NULL')).toBeNull();
|
|
43
|
+
expect(await alreadyApplied(c, 'ALTER TABLE users ALTER COLUMN password_hash SET NOT NULL')).toMatch(/already NOT NULL/);
|
|
44
|
+
// A comma inside a type or default does not split the action.
|
|
45
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS warn_at NUMERIC(18,4) DEFAULT 0')).toMatch(/exist/);
|
|
46
|
+
// Shapes that are not idempotent are never guessed at.
|
|
47
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN brand_new TEXT')).toBeNull();
|
|
48
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS warn_at TIMESTAMPTZ, ALTER COLUMN warn_at SET DEFAULT NULL')).toBeNull();
|
|
49
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ALTER COLUMN x SET DEFAULT 1')).toBeNull();
|
|
50
|
+
expect(await alreadyApplied(c, 'CREATE TABLE IF NOT EXISTS t (id int)')).toBeNull();
|
|
51
|
+
expect(await alreadyApplied(c, "DO $$ BEGIN ALTER TABLE links ADD COLUMN IF NOT EXISTS warn_at TEXT; END $$")).toBeNull();
|
|
52
|
+
expect(await alreadyApplied(c, 'ALTER TABLE links ADD COLUMN IF NOT EXISTS a TEXT; ALTER TABLE links ADD COLUMN IF NOT EXISTS b TEXT')).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('guardSchemaClient', () => {
|
|
56
|
+
it('skips what exists, passes the rest through, records why, and releases the real client', async () => {
|
|
57
|
+
const raw = fakeClient({ columns: [['links', 'warn_at', 'YES']] });
|
|
58
|
+
const client = guardSchemaClient(raw);
|
|
59
|
+
expect((await client.query('ALTER TABLE links ADD COLUMN IF NOT EXISTS warn_at TIMESTAMPTZ')).command).toBe('SKIP');
|
|
60
|
+
expect((await client.query('ALTER TABLE links ADD COLUMN IF NOT EXISTS brand_new TEXT')).command).toBe('SENT');
|
|
61
|
+
await client.query('SELECT pg_advisory_lock($1)', [1]);
|
|
62
|
+
expect(client.skipped).toEqual(['column links.warn_at exists']);
|
|
63
|
+
expect(raw.query.mock.calls.map((c) => String(c[0]).slice(0, 30))).toEqual([
|
|
64
|
+
'SELECT is_nullable FROM inform',
|
|
65
|
+
'SELECT is_nullable FROM inform',
|
|
66
|
+
'ALTER TABLE links ADD COLUMN I',
|
|
67
|
+
'SELECT pg_advisory_lock($1)',
|
|
68
|
+
]);
|
|
69
|
+
client.release();
|
|
70
|
+
expect(raw.release).toHaveBeenCalledTimes(1);
|
|
71
|
+
});
|
|
72
|
+
it('never inspects parameterised statements', async () => {
|
|
73
|
+
const raw = fakeClient({ columns: [['links', 'x', 'YES']] });
|
|
74
|
+
await guardSchemaClient(raw).query('ALTER TABLE links ADD COLUMN IF NOT EXISTS x TEXT', [1]);
|
|
75
|
+
expect(raw.query).toHaveBeenCalledTimes(1);
|
|
76
|
+
});
|
|
77
|
+
it('recognises a lock timeout by SQLSTATE', () => {
|
|
78
|
+
expect(isLockTimeout(Object.assign(new Error('x'), { code: LOCK_NOT_AVAILABLE }))).toBe(true);
|
|
79
|
+
expect(isLockTimeout(new Error('x'))).toBe(false);
|
|
80
|
+
expect(isLockTimeout(null)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=schema-guard.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-guard.test.js","sourceRoot":"","sources":["../../src/lib/schema-guard.test.ts"],"names":[],"mappings":"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"}
|