pipework 0.17.0 → 0.18.0
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/CHANGELOG.md +21 -0
- package/dist/REFERENCE.md +1190 -0
- package/dist/core/config/app-pool.d.ts +17 -0
- package/dist/core/config/app-pool.d.ts.map +1 -0
- package/dist/core/config/app-pool.js +18 -0
- package/dist/core/config/app-pool.js.map +1 -0
- package/dist/core/config/load.js +5 -5
- package/dist/core/config/load.js.map +1 -1
- package/dist/core/config/resolve.d.ts +12 -2
- package/dist/core/config/resolve.d.ts.map +1 -1
- package/dist/core/config/resolve.js +27 -9
- package/dist/core/config/resolve.js.map +1 -1
- package/dist/core/validation/rls-role.d.ts.map +1 -1
- package/dist/core/validation/rls-role.js +2 -1
- package/dist/core/validation/rls-role.js.map +1 -1
- package/dist/data/migrate/apply.d.ts +5 -7
- package/dist/data/migrate/apply.d.ts.map +1 -1
- package/dist/data/migrate/apply.js +7 -95
- package/dist/data/migrate/apply.js.map +1 -1
- package/dist/data/migrate/post-process.d.ts.map +1 -1
- package/dist/data/migrate/post-process.js +15 -5
- package/dist/data/migrate/post-process.js.map +1 -1
- package/dist/data/migrate/safety.d.ts.map +1 -1
- package/dist/data/migrate/safety.js +12 -7
- package/dist/data/migrate/safety.js.map +1 -1
- package/dist/data/migrate/statements.d.ts +50 -0
- package/dist/data/migrate/statements.d.ts.map +1 -0
- package/dist/data/migrate/statements.js +225 -0
- package/dist/data/migrate/statements.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IsolationStrategy } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether the test harness ever creates the app-role pool under `strategy`.
|
|
4
|
+
*
|
|
5
|
+
* Transaction isolation registers its single rolled-back connection as the pool
|
|
6
|
+
* override under the database's *base* key (`src/test/plugin.ts`), and
|
|
7
|
+
* `getOrCreate(config, 'app')` falls back to that base override when no
|
|
8
|
+
* role-specific one is registered (`src/core/pipework.ts`) — so the app-role
|
|
9
|
+
* pool is never constructed and `appUrl`/`appTestUrl` are never dialed by it.
|
|
10
|
+
* Every other strategy resolves roles normally (`appUrl ?? url`) and creates it.
|
|
11
|
+
*
|
|
12
|
+
* This is the single statement of that fact: both the app-pair value-identity
|
|
13
|
+
* carve-out (`resolveDbUrl`) and the RLS probe target (`rlsProbeTarget`) are
|
|
14
|
+
* expressed in terms of it, so the two cannot drift apart.
|
|
15
|
+
*/
|
|
16
|
+
export declare function appPoolCreated(strategy: IsolationStrategy): boolean;
|
|
17
|
+
//# sourceMappingURL=app-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-pool.d.ts","sourceRoot":"","sources":["../../../src/core/config/app-pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAEnE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the test harness ever creates the app-role pool under `strategy`.
|
|
3
|
+
*
|
|
4
|
+
* Transaction isolation registers its single rolled-back connection as the pool
|
|
5
|
+
* override under the database's *base* key (`src/test/plugin.ts`), and
|
|
6
|
+
* `getOrCreate(config, 'app')` falls back to that base override when no
|
|
7
|
+
* role-specific one is registered (`src/core/pipework.ts`) — so the app-role
|
|
8
|
+
* pool is never constructed and `appUrl`/`appTestUrl` are never dialed by it.
|
|
9
|
+
* Every other strategy resolves roles normally (`appUrl ?? url`) and creates it.
|
|
10
|
+
*
|
|
11
|
+
* This is the single statement of that fact: both the app-pair value-identity
|
|
12
|
+
* carve-out (`resolveDbUrl`) and the RLS probe target (`rlsProbeTarget`) are
|
|
13
|
+
* expressed in terms of it, so the two cannot drift apart.
|
|
14
|
+
*/
|
|
15
|
+
export function appPoolCreated(strategy) {
|
|
16
|
+
return strategy !== 'transaction';
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=app-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-pool.js","sourceRoot":"","sources":["../../../src/core/config/app-pool.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,QAA2B;IACxD,OAAO,QAAQ,KAAK,aAAa,CAAA;AACnC,CAAC"}
|
package/dist/core/config/load.js
CHANGED
|
@@ -19,10 +19,13 @@ export function loadConfig(raw) {
|
|
|
19
19
|
}
|
|
20
20
|
function buildResolved(config, environment, baseDir) {
|
|
21
21
|
const dbMap = new Map();
|
|
22
|
+
// Defined here, not inline in the accessor, so the app-pair carve-out below
|
|
23
|
+
// and `isolationStrategy()` cannot answer the same question differently.
|
|
24
|
+
const isolationStrategyFor = (dbName) => config.test?.databases?.[dbName]?.isolation ?? config.test?.isolation ?? 'transaction';
|
|
22
25
|
for (const [name, dbConfig] of Object.entries(config.databases)) {
|
|
23
26
|
const url = resolveDbUrl(dbConfig.url, dbConfig.testUrl, environment, name);
|
|
24
27
|
const appUrl = dbConfig.appUrl !== undefined
|
|
25
|
-
? resolveDbUrl(dbConfig.appUrl, dbConfig.appTestUrl, environment, name)
|
|
28
|
+
? resolveDbUrl(dbConfig.appUrl, dbConfig.appTestUrl, environment, name, { strategy: isolationStrategyFor(name) })
|
|
26
29
|
: undefined;
|
|
27
30
|
dbMap.set(name, resolveDatabase(name, dbConfig, url, appUrl, baseDir));
|
|
28
31
|
}
|
|
@@ -101,10 +104,7 @@ function buildResolved(config, environment, baseDir) {
|
|
|
101
104
|
throw new ConfigError('Multiple databases configured — you must specify which one.', `Declared databases: ${declaredNames.join(', ')}\n\n Set defaultDatabase in pipework.config.ts to pick one.`);
|
|
102
105
|
},
|
|
103
106
|
isolationStrategy(dbName) {
|
|
104
|
-
|
|
105
|
-
if (perDb)
|
|
106
|
-
return perDb;
|
|
107
|
-
return config.test?.isolation ?? 'transaction';
|
|
107
|
+
return isolationStrategyFor(dbName);
|
|
108
108
|
},
|
|
109
109
|
};
|
|
110
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/core/config/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAiF,MAAM,aAAa,CAAA;AAC9H,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAsEpD,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,6EAA6E;IAC7E,2BAA2B;IAC3B,MAAM,OAAO,GAAG,oBAAoB,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACvD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/F,MAAM,IAAI,WAAW,CACnB,gCAAgC,MAAM,EAAE,EACxC,4DAA4D,CAC7D,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;IAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAA;IAC9D,OAAO,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;AACpD,CAAC;AAED,SAAS,aAAa,CAAC,MAAiB,EAAE,WAAwB,EAAE,OAAe;IACjF,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAA;IAEjD,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;QAC3E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,SAAS;YAC1C,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/core/config/load.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import type { Environment } from './schema.js';
|
|
1
|
+
import type { Environment, IsolationStrategy } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Passed when resolving the app-role pair (`appUrl`/`appTestUrl`), which carries
|
|
4
|
+
* the transaction-isolation carve-out on value-identity. Absent when resolving
|
|
5
|
+
* the owner pair (`url`/`testUrl`), which has no carve-out: that connection is
|
|
6
|
+
* dialed under every strategy.
|
|
7
|
+
*/
|
|
8
|
+
export interface AppRolePair {
|
|
9
|
+
/** This database's resolved test-isolation strategy. */
|
|
10
|
+
readonly strategy: IsolationStrategy;
|
|
11
|
+
}
|
|
2
12
|
export declare function resolveEnvironment(): Environment;
|
|
3
|
-
export declare function resolveDbUrl(envVarName: string, testEnvVarName: string | undefined, environment: Environment, dbName?: string): string;
|
|
13
|
+
export declare function resolveDbUrl(envVarName: string, testEnvVarName: string | undefined, environment: Environment, dbName?: string, appRolePair?: AppRolePair): string;
|
|
4
14
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/core/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/core/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAIjE;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;CACrC;AAED,wBAAgB,kBAAkB,IAAI,WAAW,CAWhD;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,WAAW,EACxB,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,WAAW,GACxB,MAAM,CAgFR"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConfigError } from './errors.js';
|
|
2
|
+
import { appPoolCreated } from './app-pool.js';
|
|
2
3
|
export function resolveEnvironment() {
|
|
3
4
|
const explicit = process.env['PIPEWORK_ENV'];
|
|
4
5
|
if (explicit === 'test' || explicit === 'development' || explicit === 'production') {
|
|
@@ -11,14 +12,18 @@ export function resolveEnvironment() {
|
|
|
11
12
|
return 'production';
|
|
12
13
|
return 'development';
|
|
13
14
|
}
|
|
14
|
-
export function resolveDbUrl(envVarName, testEnvVarName, environment, dbName) {
|
|
15
|
+
export function resolveDbUrl(envVarName, testEnvVarName, environment, dbName, appRolePair) {
|
|
15
16
|
if (environment === 'test') {
|
|
17
|
+
// The pair being resolved, so every refusal below names the fields the
|
|
18
|
+
// reader actually has to edit rather than always saying url/testUrl.
|
|
19
|
+
const urlField = appRolePair !== undefined ? 'appUrl' : 'url';
|
|
20
|
+
const testUrlField = appRolePair !== undefined ? 'appTestUrl' : 'testUrl';
|
|
16
21
|
if (testEnvVarName === undefined) {
|
|
17
|
-
throw new ConfigError(`Database "${dbName ?? envVarName}" has no
|
|
22
|
+
throw new ConfigError(`Database "${dbName ?? envVarName}" has no ${testUrlField} configured, but environment is "test".`, `Add ${testUrlField} to your database config:\n\n` +
|
|
18
23
|
` databases: {\n` +
|
|
19
24
|
` ${dbName ?? 'app'}: {\n` +
|
|
20
|
-
`
|
|
21
|
-
`
|
|
25
|
+
` ${urlField}: '${envVarName}',\n` +
|
|
26
|
+
` ${testUrlField}: '${envVarName}_TEST', // <-- add this\n` +
|
|
22
27
|
` },\n` +
|
|
23
28
|
` }\n\n` +
|
|
24
29
|
`Then set ${envVarName}_TEST in your environment.`);
|
|
@@ -30,11 +35,11 @@ export function resolveDbUrl(envVarName, testEnvVarName, environment, dbName) {
|
|
|
30
35
|
// first: both fields reading one variable is a config-shape defect,
|
|
31
36
|
// regardless of what the variable holds.
|
|
32
37
|
if (testEnvVarName === envVarName) {
|
|
33
|
-
throw new ConfigError(`Database "${dbName ?? envVarName}" uses the same environment variable "${envVarName}" for
|
|
38
|
+
throw new ConfigError(`Database "${dbName ?? envVarName}" uses the same environment variable "${envVarName}" for ${urlField} and ${testUrlField} — test isolation is defeated.`, `${testUrlField} must be its own variable pointing at a separate database:\n\n` +
|
|
34
39
|
` databases: {\n` +
|
|
35
40
|
` ${dbName ?? 'app'}: {\n` +
|
|
36
|
-
`
|
|
37
|
-
`
|
|
41
|
+
` ${urlField}: '${envVarName}',\n` +
|
|
42
|
+
` ${testUrlField}: '${envVarName}_TEST', // <-- its own variable\n` +
|
|
38
43
|
` },\n` +
|
|
39
44
|
` }\n\n` +
|
|
40
45
|
`Then set ${envVarName}_TEST to a separate database's connection string.`);
|
|
@@ -42,9 +47,22 @@ export function resolveDbUrl(envVarName, testEnvVarName, environment, dbName) {
|
|
|
42
47
|
const value = process.env[testEnvVarName];
|
|
43
48
|
if (value !== undefined && value !== '') {
|
|
44
49
|
const urlValue = process.env[envVarName];
|
|
45
|
-
|
|
50
|
+
// 0.17.1: value-identity on the app-role pair is a false positive under a
|
|
51
|
+
// strategy that never creates the app-role pool — the value satisfies
|
|
52
|
+
// config resolution and is then never dialed by it. The refusal stands
|
|
53
|
+
// wherever the pool IS created, and for the owner pair in every mode.
|
|
54
|
+
// Name-identity above is NOT carved out: one env var serving both fields
|
|
55
|
+
// carries no intent and cannot be told from a typo.
|
|
56
|
+
const inert = appRolePair !== undefined && !appPoolCreated(appRolePair.strategy);
|
|
57
|
+
if (!inert && urlValue !== undefined && urlValue !== '' && urlValue === value) {
|
|
46
58
|
throw new ConfigError(`Database "${dbName ?? envVarName}": "${testEnvVarName}" and "${envVarName}" hold the identical connection string — test isolation is defeated.`, `Tests would run against the same database "${envVarName}" points at. ` +
|
|
47
|
-
`Point ${testEnvVarName} at a separate database.`
|
|
59
|
+
`Point ${testEnvVarName} at a separate database.` +
|
|
60
|
+
(appRolePair !== undefined
|
|
61
|
+
? `\n\nIdentical app-role values are accepted only under "transaction" isolation, ` +
|
|
62
|
+
`where the harness overrides every role onto one rolled-back connection and the ` +
|
|
63
|
+
`app-role pool is never created. This database resolves to "${appRolePair.strategy}" ` +
|
|
64
|
+
`isolation, which creates it — so ${testEnvVarName} is genuinely dialed here.`
|
|
65
|
+
: ''));
|
|
48
66
|
}
|
|
49
67
|
return value;
|
|
50
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/config/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/config/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls-role.d.ts","sourceRoot":"","sources":["../../../src/core/validation/rls-role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"rls-role.d.ts","sourceRoot":"","sources":["../../../src/core/validation/rls-role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAQ5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAQ5E;AAED,oOAAoO;AACpO,wBAAgB,cAAc,CAAC,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAExF;AAED,4GAA4G;AAC5G,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBvF;AAED,4IAA4I;AAC5I,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAChD,SAAS,SAAO,GACf,OAAO,CAAC,eAAe,EAAE,CAAC,CAoB5B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { appPoolCreated } from '../config/app-pool.js';
|
|
1
2
|
export function rlsRoleMessage(database, probe) {
|
|
2
3
|
const flag = probe.superuser ? 'SUPERUSER' : 'BYPASSRLS';
|
|
3
4
|
return (`database "${database}" has rls configured, but its runtime role "${probe.role}" is ${flag} — ` +
|
|
@@ -7,7 +8,7 @@ export function rlsRoleMessage(database, probe) {
|
|
|
7
8
|
}
|
|
8
9
|
/** The connection whose role actually executes queries under the harness: transaction isolation collapses every role onto the resolved `url` connection; database/container isolation resolves roles normally (`appUrl ?? url`). */
|
|
9
10
|
export function rlsProbeTarget(db, strategy) {
|
|
10
|
-
return strategy
|
|
11
|
+
return appPoolCreated(strategy) ? (db.appUrl ?? db.url) : db.url;
|
|
11
12
|
}
|
|
12
13
|
/** Role flags for `current_user` at `url`. Short-lived probe connection, mirroring validateConnectivity. */
|
|
13
14
|
export async function probeRlsRole(url, timeoutMs = 5000) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rls-role.js","sourceRoot":"","sources":["../../../src/core/validation/rls-role.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rls-role.js","sourceRoot":"","sources":["../../../src/core/validation/rls-role.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAatD,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,KAAmB;IAClE,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAA;IACxD,OAAO,CACL,aAAa,QAAQ,+CAA+C,KAAK,CAAC,IAAI,QAAQ,IAAI,KAAK;QAC/F,+EAA+E;QAC/E,mGAAmG;QACnG,4EAA4E,CAC7E,CAAA;AACH,CAAC;AAED,oOAAoO;AACpO,MAAM,UAAU,cAAc,CAAC,EAAoB,EAAE,QAA2B;IAC9E,OAAO,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAA;AAClE,CAAC;AAED,4GAA4G;AAC5G,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,SAAS,GAAG,IAAI;IAC9D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAA;IACtD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE;QACxB,GAAG,EAAE,CAAC;QACN,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAC5C,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;KACnB,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAA,gGAAgG,CAAA;QACtH,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAA2E,CAAA;QAC7F,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACvD,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,YAAY,EAAE,CAAA;IACjF,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;IAC/B,CAAC;AACH,CAAC;AAED,4IAA4I;AAC5I,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAgD,EAChD,SAAS,GAAG,IAAI;IAEhB,MAAM,MAAM,GAAsB,EAAE,CAAA;IAEpC,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;SACpC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC;SACxC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACxB,IAAI,KAAmB,CAAA;QACvB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,YAAY,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;YAC7D,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC,CAAC,CAAA;IAEJ,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -20,14 +20,12 @@ export interface Migration {
|
|
|
20
20
|
export declare function applyMigrations(options: ApplyOptions): Promise<number>;
|
|
21
21
|
export declare function readMigrations(options: ApplyOptions): Migration[];
|
|
22
22
|
/**
|
|
23
|
-
* Split migration SQL into individual statements
|
|
24
|
-
*
|
|
25
|
-
* stripped; `--> statement-breakpoint` is honored as an explicit separator.
|
|
23
|
+
* Split migration SQL into individual statements, honoring drizzle's
|
|
24
|
+
* `--> statement-breakpoint` as an explicit separator.
|
|
26
25
|
*
|
|
27
|
-
* The
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* definition into unrunnable fragments. Issue #317.
|
|
26
|
+
* The scanning rules live in `statements.ts`, shared with the safety gate so
|
|
27
|
+
* the runner and the gate cannot disagree about where a statement begins —
|
|
28
|
+
* they did, and the gate was the one that was wrong (#334).
|
|
31
29
|
*/
|
|
32
30
|
export declare function parseStatements(raw: string): string[];
|
|
33
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/apply.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AASD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA2F5E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,EAAE,CA4CjE;AAED
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/apply.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AASD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CA2F5E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,EAAE,CA4CjE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAErD;AAMD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'node:fs';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import postgres from 'postgres';
|
|
4
|
+
import { scanStatements } from './statements.js';
|
|
4
5
|
const NO_TRANSACTION_PRAGMA = '-- pipework:no-transaction';
|
|
5
|
-
const STATEMENT_BREAKPOINT = '--> statement-breakpoint';
|
|
6
6
|
export async function applyMigrations(options) {
|
|
7
7
|
const migrations = readMigrations(options);
|
|
8
8
|
if (migrations.length === 0)
|
|
@@ -107,103 +107,15 @@ export function readMigrations(options) {
|
|
|
107
107
|
return migrations;
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
|
-
* Split migration SQL into individual statements
|
|
111
|
-
*
|
|
112
|
-
* stripped; `--> statement-breakpoint` is honored as an explicit separator.
|
|
110
|
+
* Split migration SQL into individual statements, honoring drizzle's
|
|
111
|
+
* `--> statement-breakpoint` as an explicit separator.
|
|
113
112
|
*
|
|
114
|
-
* The
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* definition into unrunnable fragments. Issue #317.
|
|
113
|
+
* The scanning rules live in `statements.ts`, shared with the safety gate so
|
|
114
|
+
* the runner and the gate cannot disagree about where a statement begins —
|
|
115
|
+
* they did, and the gate was the one that was wrong (#334).
|
|
118
116
|
*/
|
|
119
117
|
export function parseStatements(raw) {
|
|
120
|
-
|
|
121
|
-
let current = '';
|
|
122
|
-
const flush = () => {
|
|
123
|
-
if (current.trim().length > 0)
|
|
124
|
-
statements.push(current.trim());
|
|
125
|
-
current = '';
|
|
126
|
-
};
|
|
127
|
-
let i = 0;
|
|
128
|
-
while (i < raw.length) {
|
|
129
|
-
const ch = raw[i];
|
|
130
|
-
// `--` line comment: stripped to end of line. `--> statement-breakpoint` is
|
|
131
|
-
// the one comment that also terminates the current statement.
|
|
132
|
-
if (ch === '-' && raw[i + 1] === '-') {
|
|
133
|
-
const nl = raw.indexOf('\n', i);
|
|
134
|
-
const end = nl === -1 ? raw.length : nl;
|
|
135
|
-
if (raw.slice(i, end).trim() === STATEMENT_BREAKPOINT)
|
|
136
|
-
flush();
|
|
137
|
-
i = end;
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
// `'...'` literal — `''` is an escaped quote. Copied verbatim.
|
|
141
|
-
if (ch === "'") {
|
|
142
|
-
const end = scanSingleQuote(raw, i);
|
|
143
|
-
current += raw.slice(i, end);
|
|
144
|
-
i = end;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
// `$tag$ ... $tag$` dollar-quoted block. Copied verbatim — inner `;`/`--`
|
|
148
|
-
// are body content, not separators.
|
|
149
|
-
if (ch === '$') {
|
|
150
|
-
const tag = dollarQuoteTag(raw, i);
|
|
151
|
-
if (tag !== null) {
|
|
152
|
-
const close = raw.indexOf(tag, i + tag.length);
|
|
153
|
-
const end = close === -1 ? raw.length : close + tag.length;
|
|
154
|
-
current += raw.slice(i, end);
|
|
155
|
-
i = end;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (ch === ';') {
|
|
160
|
-
flush();
|
|
161
|
-
i += 1;
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
current += ch;
|
|
165
|
-
i += 1;
|
|
166
|
-
}
|
|
167
|
-
flush();
|
|
168
|
-
return statements;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* `start` indexes the opening `'`. Returns the index just past the closing `'`,
|
|
172
|
-
* treating a doubled `''` as an escaped quote. An unterminated literal returns
|
|
173
|
-
* the end of input — the statement is emitted as-is so Postgres reports it.
|
|
174
|
-
*/
|
|
175
|
-
function scanSingleQuote(raw, start) {
|
|
176
|
-
let i = start + 1;
|
|
177
|
-
while (i < raw.length) {
|
|
178
|
-
if (raw[i] === "'") {
|
|
179
|
-
if (raw[i + 1] === "'") {
|
|
180
|
-
i += 2;
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
return i + 1;
|
|
184
|
-
}
|
|
185
|
-
i += 1;
|
|
186
|
-
}
|
|
187
|
-
return raw.length;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* If `start` indexes the opening `$` of a dollar-quote tag (`$$` or `$label$`,
|
|
191
|
-
* where a label is a SQL identifier), returns the full tag text; otherwise
|
|
192
|
-
* `null`. A `$` followed by a digit (`$1`) or non-identifier character is not
|
|
193
|
-
* a tag.
|
|
194
|
-
*/
|
|
195
|
-
function dollarQuoteTag(raw, start) {
|
|
196
|
-
let i = start + 1;
|
|
197
|
-
while (i < raw.length) {
|
|
198
|
-
const c = raw[i];
|
|
199
|
-
if (c === '$')
|
|
200
|
-
return raw.slice(start, i + 1);
|
|
201
|
-
const valid = i === start + 1 ? /[A-Za-z_]/.test(c) : /[A-Za-z0-9_]/.test(c);
|
|
202
|
-
if (!valid)
|
|
203
|
-
return null;
|
|
204
|
-
i += 1;
|
|
205
|
-
}
|
|
206
|
-
return null;
|
|
118
|
+
return scanStatements(raw, { breakpointSeparator: true });
|
|
207
119
|
}
|
|
208
120
|
function quoteIdent(name) {
|
|
209
121
|
return `"${name.replace(/"/g, '""')}"`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/data/migrate/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,QAAQ,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/data/migrate/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AA8B1D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAqB;IACzD,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAErC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAA;IAE9E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;QAEjD,sEAAsE;QACtE,uEAAuE;QACvE,wEAAwE;QACxE,qEAAqE;QACrE,oEAAoE;QACpE,iEAAiE;QACjE,MAAM,MAAM,CAAC,MAAM,CAAC;mCACW,KAAK;;;;;;KAMnC,CAAC,CAAA;QACF,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,2CAA2C;QAC3C,MAAM,MAAM,CAAC,MAAM,CAAC,eAAe,KAAK,oCAAoC,CAAC,CAAA;QAC7E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,MAAM,CAAC,MAAM,CACjB,UAAU,KAAK;2CACoB,KAAK,mCAAmC,EAC3E,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,CAChC,CAAA;QACH,CAAC;QACD,MAAM,MAAM,CAAC,MAAM,CACjB,qCAAqC,UAAU,CAAC,GAAG,OAAO,CAAC,eAAe,UAAU,CAAC,OAAO,KAAK,QAAQ,CAC1G,CAAA;QAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAC9B,yBAAyB,KAAK,wBAAwB,CACvD,CAAA;QACD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEzE,IAAI,OAAO,GAAG,CAAC,CAAA;QAEf,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;YACvD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,IAAI,WAAW,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;oBACnC,MAAM,IAAI,KAAK,CACb,cAAc,SAAS,CAAC,GAAG,+BAA+B,OAAO,CAAC,eAAe,YAAY;wBAC3F,6CAA6C,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB;wBACtF,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,4DAA4D;wBAC1F,+FAA+F;wBAC/F,sEAAsE,SAAS,CAAC,GAAG,aAAa;wBAChG,+FAA+F;wBAC/F,uBAAuB,CAC1B,CAAA;gBACH,CAAC;gBACD,SAAQ;YACV,CAAC;YAED,IAAI,SAAS,CAAC,aAAa,EAAE,CAAC;gBAC5B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;oBACxC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC3B,CAAC;gBACD,MAAM,MAAM,CAAC,MAAM,CACjB,eAAe,KAAK,oDAAoD,EACxE,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,CACxD,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;oBAC9B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;wBACxC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;oBACvB,CAAC;oBACD,MAAM,EAAE,CAAC,MAAM,CACb,eAAe,KAAK,oDAAoD,EACxE,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,CACxD,CAAA;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC;YAED,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,GAAG,EAAE,CAAA;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,MAAM,WAAW,GAAG,GAAG,OAAO,CAAC,gBAAgB,qBAAqB,CAAA;IACpE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,iCAAiC,WAAW,OAAO;YACnD,qDAAqD,CACtD,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAE5D,CAAA;IAED,MAAM,UAAU,GAAgB,EAAE,CAAA;IAElC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,gBAAgB,IAAI,KAAK,CAAC,GAAG,MAAM,CAAA;QAC/D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAA;QACxD,CAAC;QAED,IAAI,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QACzC,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAA;QAEzD,IAAI,OAAO,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YACvC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAA;QAC9C,CAAC;QAED,IAAI,OAAO,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACpC,GAAG,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAA;QAC/B,CAAC;QAED,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;QAEvC,UAAU,CAAC,IAAI,CAAC;YACd,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAChF,YAAY,EAAE,KAAK,CAAC,IAAI;YACxB,UAAU;YACV,aAAa;SACd,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,cAAc,CAAC,GAAG,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAA;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,sBAAsB,EAAE,uBAAuB,CAAC,CAAA;AACrE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-process.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/post-process.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"post-process.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/post-process.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoDxD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripComments, codeStartOffset } from './statements.js';
|
|
1
2
|
const CREATE_INDEX_RE = /\bCREATE\s+(UNIQUE\s+)?INDEX\b(?!\s+CONCURRENTLY)/i;
|
|
2
3
|
const CONCURRENTLY_RE = /\bCONCURRENTLY\b/i;
|
|
3
4
|
const NO_TRANSACTION_PRAGMA = '-- pipework:no-transaction';
|
|
@@ -21,18 +22,27 @@ export function postProcessMigration(sql) {
|
|
|
21
22
|
const outputStatements = [];
|
|
22
23
|
let hasConcurrently = false;
|
|
23
24
|
for (const raw of rawStatements) {
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
// Match against the SQL with comments removed, not against the raw
|
|
26
|
+
// fragment. A statement and the comment above it share a `;`-fragment, so
|
|
27
|
+
// skipping fragments that *start with* `--` skipped the statement too and
|
|
28
|
+
// a commented CREATE INDEX silently kept its exclusive lock (#334).
|
|
29
|
+
// Comment text is equally unable to fake a match it should not have.
|
|
30
|
+
const code = stripComments(raw);
|
|
31
|
+
if (code.trim().length === 0) {
|
|
26
32
|
outputStatements.push(raw);
|
|
27
33
|
continue;
|
|
28
34
|
}
|
|
29
|
-
if (CREATE_INDEX_RE.test(
|
|
30
|
-
|
|
35
|
+
if (CREATE_INDEX_RE.test(code)) {
|
|
36
|
+
// Rewrite only from where the SQL actually starts, so a leading comment
|
|
37
|
+
// that happens to say "CREATE INDEX" is not the thing rewritten.
|
|
38
|
+
const offset = codeStartOffset(raw);
|
|
39
|
+
const rewritten = raw.slice(0, offset) +
|
|
40
|
+
raw.slice(offset).replace(/\b(CREATE\s+(?:UNIQUE\s+)?)(INDEX)\b/i, '$1$2 CONCURRENTLY');
|
|
31
41
|
outputStatements.push(rewritten);
|
|
32
42
|
hasConcurrently = true;
|
|
33
43
|
continue;
|
|
34
44
|
}
|
|
35
|
-
if (CONCURRENTLY_RE.test(
|
|
45
|
+
if (CONCURRENTLY_RE.test(code)) {
|
|
36
46
|
hasConcurrently = true;
|
|
37
47
|
}
|
|
38
48
|
outputStatements.push(raw);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-process.js","sourceRoot":"","sources":["../../../src/data/migrate/post-process.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,oDAAoD,CAAA;AAC5E,MAAM,eAAe,GAAG,mBAAmB,CAAA;AAE3C,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAExC,MAAM,gBAAgB,GAAa,EAAE,CAAA;IACrC,IAAI,eAAe,GAAG,KAAK,CAAA;IAE3B,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,
|
|
1
|
+
{"version":3,"file":"post-process.js","sourceRoot":"","sources":["../../../src/data/migrate/post-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEhE,MAAM,eAAe,GAAG,oDAAoD,CAAA;AAC5E,MAAM,eAAe,GAAG,mBAAmB,CAAA;AAE3C,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAExC,MAAM,gBAAgB,GAAa,EAAE,CAAA;IACrC,IAAI,eAAe,GAAG,KAAK,CAAA;IAE3B,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,mEAAmE;QACnE,0EAA0E;QAC1E,0EAA0E;QAC1E,oEAAoE;QACpE,qEAAqE;QACrE,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC1B,SAAQ;QACV,CAAC;QAED,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,wEAAwE;YACxE,iEAAiE;YACjE,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;YACnC,MAAM,SAAS,GACb,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC;gBACpB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,uCAAuC,EAAE,mBAAmB,CAAC,CAAA;YACzF,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAChC,eAAe,GAAG,IAAI,CAAA;YACtB,SAAQ;QACV,CAAC;QAED,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,eAAe,GAAG,IAAI,CAAA;QACxB,CAAC;QAED,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,IAAI,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;IAE7C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,QAAQ,CAAA;IACpB,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC;YAC/C,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,GAAG,qBAAqB,KAAK,MAAM,EAAE,CAAA;IAC3C,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,MAAM,CAAA;AAEzD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAyFD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAmBzD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB9E"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { scanStatements } from './statements.js';
|
|
1
2
|
const RULES = [
|
|
2
3
|
// ── Destructive (data loss / backward-incompatible) ───────────────────
|
|
3
4
|
{
|
|
@@ -63,9 +64,19 @@ const RULES = [
|
|
|
63
64
|
operation: 'ADD FOREIGN KEY (without NOT VALID)',
|
|
64
65
|
suggestion: 'Add the constraint with NOT VALID, then VALIDATE CONSTRAINT in a separate statement.',
|
|
65
66
|
},
|
|
67
|
+
{
|
|
68
|
+
// Locking rather than destructive: on a non-empty table this fails loudly
|
|
69
|
+
// instead of losing data, so it aborts the deploy rather than silently
|
|
70
|
+
// damaging it. It is still a gate-worthy hazard, hence the rule (#334).
|
|
71
|
+
pattern: /\bADD\s+COLUMN\b[^;]*\bNOT\s+NULL\b/i,
|
|
72
|
+
severity: 'locking',
|
|
73
|
+
operation: 'ADD COLUMN NOT NULL (without DEFAULT)',
|
|
74
|
+
suggestion: 'Add the column nullable, backfill, then SET NOT NULL — or give it a DEFAULT so existing rows can be filled.',
|
|
75
|
+
except: /\bDEFAULT\b/i,
|
|
76
|
+
},
|
|
66
77
|
];
|
|
67
78
|
export function analyzeSQL(sql) {
|
|
68
|
-
const statements =
|
|
79
|
+
const statements = scanStatements(sql);
|
|
69
80
|
const hazards = [];
|
|
70
81
|
for (const stmt of statements) {
|
|
71
82
|
for (const rule of RULES) {
|
|
@@ -83,12 +94,6 @@ export function analyzeSQL(sql) {
|
|
|
83
94
|
}
|
|
84
95
|
return hazards;
|
|
85
96
|
}
|
|
86
|
-
function splitStatements(sql) {
|
|
87
|
-
return sql
|
|
88
|
-
.split(/;/)
|
|
89
|
-
.map(s => s.trim())
|
|
90
|
-
.filter(s => s.length > 0 && !s.startsWith('--'));
|
|
91
|
-
}
|
|
92
97
|
export function formatHazards(hazards, file) {
|
|
93
98
|
const destructive = hazards.filter(h => h.severity === 'destructive');
|
|
94
99
|
const locking = hazards.filter(h => h.severity === 'locking');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../../src/data/migrate/safety.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One SQL scanner, shared by everything in the migrate pipeline that has to
|
|
3
|
+
* reason about statement boundaries.
|
|
4
|
+
*
|
|
5
|
+
* There were two hand-rolled splitters before this, and they disagreed. The
|
|
6
|
+
* runner (`parseStatements`) learned string literals and dollar-quoted bodies
|
|
7
|
+
* in #317 so a plpgsql function body would survive; the safety gate kept a
|
|
8
|
+
* `sql.split(';')` that then discarded any fragment starting with `--`. Since
|
|
9
|
+
* a statement and the comment above it land in the *same* fragment, the gate
|
|
10
|
+
* dropped comment-led statements entirely and reported migrations clean that
|
|
11
|
+
* dropped tables (#334). Neither splitter knew about block comments or quoted
|
|
12
|
+
* identifiers.
|
|
13
|
+
*
|
|
14
|
+
* The rules, in one place:
|
|
15
|
+
*
|
|
16
|
+
* - `--` runs to end of line; block comments nest, per Postgres.
|
|
17
|
+
* - Comments are removed, replaced by whitespace so they still separate tokens.
|
|
18
|
+
* - `'…'`, `"…"` and `$tag$…$tag$` are copied verbatim — a `;` or `--` inside
|
|
19
|
+
* them is content, not syntax. Backslash escapes apply only in `E'…'`.
|
|
20
|
+
* - Comment state and quote state are decided in the same pass. That ordering
|
|
21
|
+
* is load-bearing: an apostrophe in a comment (`-- the migration's ancestors`)
|
|
22
|
+
* must not open a string literal, and a `--` inside a literal must not open
|
|
23
|
+
* a comment. Either check running first, alone, gets the other case wrong.
|
|
24
|
+
* - An unterminated comment or literal runs to end of input; the SQL is invalid
|
|
25
|
+
* either way and Postgres is what should say so.
|
|
26
|
+
*/
|
|
27
|
+
export interface ScanOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Honor drizzle's `--> statement-breakpoint` as an explicit statement
|
|
30
|
+
* separator. The runner needs this (it decides what is sent to Postgres as
|
|
31
|
+
* one statement); the safety gate does not care.
|
|
32
|
+
*/
|
|
33
|
+
breakpointSeparator?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Splits SQL into statements, stripping comments. */
|
|
36
|
+
export declare function scanStatements(sql: string, options?: ScanOptions): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Removes comments, leaving literals and dollar-quoted bodies intact and
|
|
39
|
+
* statement separators where they were. For callers that need to test SQL
|
|
40
|
+
* against a pattern without a comment supplying a false match or hiding a
|
|
41
|
+
* real one.
|
|
42
|
+
*/
|
|
43
|
+
export declare function stripComments(sql: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Index of the first character of actual SQL in `sql` — i.e. past any leading
|
|
46
|
+
* whitespace and comments. Lets a text rewriter skip a leading comment block
|
|
47
|
+
* without rewriting words inside it.
|
|
48
|
+
*/
|
|
49
|
+
export declare function codeStartOffset(sql: string): number;
|
|
50
|
+
//# sourceMappingURL=statements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../../src/data/migrate/statements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,EAAE,CAqE/E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmCjD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBnD"}
|