@vibeorm/migrate 2.0.0-alpha.5 → 2.0.0-alpha.7
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/dist/execute.d.ts +26 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/index.js +48 -19
- package/dist/index.js.map +4 -4
- package/dist/runner.d.ts +48 -22
- package/dist/runner.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/execute.d.ts
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* `usesSelfManagedTransactions` detects them. Plain statements in a
|
|
11
11
|
* self-managed script auto-commit individually (documented sqlite
|
|
12
12
|
* limitation: a mixed script is not atomic as a whole; each rebuild block
|
|
13
|
-
* is).
|
|
13
|
+
* is). Because of that, the migration runner records per-statement progress
|
|
14
|
+
* for these scripts and resumes with `selfManagedResumeStart`, which rewinds
|
|
15
|
+
* INTO the enclosing block so the session-scoped `PRAGMA foreign_keys=OFF`
|
|
16
|
+
* is re-issued before the block replays.
|
|
14
17
|
* - `PRAGMA foreign_key_check` RETURNS VIOLATION ROWS instead of failing —
|
|
15
18
|
* `executeStatement` runs it row-returning (`values: []`, the adapter-sqlite
|
|
16
19
|
* contract for reads) and throws VIBE_MIGRATION when any come back.
|
|
@@ -21,6 +24,28 @@ import type { SqlExecutor } from "./types.ts";
|
|
|
21
24
|
export declare function usesSelfManagedTransactions(params: {
|
|
22
25
|
sql: readonly string[];
|
|
23
26
|
}): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Where a resume of a self-managed sqlite script must actually restart.
|
|
29
|
+
*
|
|
30
|
+
* A recorded statement_index can point INSIDE a rebuild block: the progress
|
|
31
|
+
* UPDATE issued after `PRAGMA foreign_keys=OFF;` auto-commits (no transaction
|
|
32
|
+
* is open yet), while every UPDATE after the block's `BEGIN;` is rolled back
|
|
33
|
+
* with the crash — so the persisted index lands on the block's `BEGIN;`, one
|
|
34
|
+
* past a pragma that is SESSION-scoped and gone in the new session. Resuming
|
|
35
|
+
* there would run the rebuild — `DROP TABLE` of a possibly-referenced parent
|
|
36
|
+
* included — with foreign keys ON.
|
|
37
|
+
*
|
|
38
|
+
* This rewinds `start` to the nearest preceding `PRAGMA foreign_keys=OFF` that
|
|
39
|
+
* is not already closed by a `PRAGMA foreign_keys=ON`. Replaying from a
|
|
40
|
+
* block's start is safe: the block is transactional (nothing of it survived a
|
|
41
|
+
* crash) and re-running a COMPLETED block is the idempotence the recipe
|
|
42
|
+
* already relies on. Scripts with no marker before `start` are returned
|
|
43
|
+
* unchanged.
|
|
44
|
+
*/
|
|
45
|
+
export declare function selfManagedResumeStart(params: {
|
|
46
|
+
sql: readonly string[];
|
|
47
|
+
start: number;
|
|
48
|
+
}): number;
|
|
24
49
|
/**
|
|
25
50
|
* Execute one migration statement. On sqlite, `PRAGMA foreign_key_check` is
|
|
26
51
|
* executed row-returning and its violations become a VIBE_MIGRATION error.
|
package/dist/execute.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAU9C,2EAA2E;AAC3E,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,OAAO,CAEvF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAST;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhG"}
|
package/dist/index.js
CHANGED
|
@@ -1957,10 +1957,22 @@ function artifactCreateSql(params) {
|
|
|
1957
1957
|
// packages/migrate/src/execute.ts
|
|
1958
1958
|
import { VibeError as VibeError8 } from "@vibeorm/schema";
|
|
1959
1959
|
var SELF_MANAGED_MARKER = "PRAGMA foreign_keys=OFF";
|
|
1960
|
+
var SELF_MANAGED_RESTORE_MARKER = "PRAGMA foreign_keys=ON";
|
|
1960
1961
|
var FK_CHECK_PREFIX = "PRAGMA foreign_key_check";
|
|
1961
1962
|
function usesSelfManagedTransactions(params) {
|
|
1962
1963
|
return params.sql.some((statement) => statement.startsWith(SELF_MANAGED_MARKER));
|
|
1963
1964
|
}
|
|
1965
|
+
function selfManagedResumeStart(params) {
|
|
1966
|
+
const { sql, start } = params;
|
|
1967
|
+
for (let index = start - 1;index >= 0; index -= 1) {
|
|
1968
|
+
const statement = sql[index];
|
|
1969
|
+
if (statement.startsWith(SELF_MANAGED_RESTORE_MARKER))
|
|
1970
|
+
return start;
|
|
1971
|
+
if (statement.startsWith(SELF_MANAGED_MARKER))
|
|
1972
|
+
return index;
|
|
1973
|
+
}
|
|
1974
|
+
return start;
|
|
1975
|
+
}
|
|
1964
1976
|
async function executeStatement(params) {
|
|
1965
1977
|
const { executor, statement, dialect } = params;
|
|
1966
1978
|
if (dialect === "sqlite" && statement.startsWith(FK_CHECK_PREFIX)) {
|
|
@@ -2057,10 +2069,9 @@ function generateMigration(params) {
|
|
|
2057
2069
|
async function applyMigrations(params) {
|
|
2058
2070
|
const { executor, migrations } = params;
|
|
2059
2071
|
const dialect = params.dialect ?? "postgres";
|
|
2060
|
-
const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
|
|
2061
|
-
await ensureMigrationsTable({ executor, dialect });
|
|
2062
2072
|
await acquireLock({ executor, dialect });
|
|
2063
2073
|
try {
|
|
2074
|
+
await ensureMigrationsTable({ executor, dialect });
|
|
2064
2075
|
const recorded = await recordedRows({ executor, dialect });
|
|
2065
2076
|
const applied = [];
|
|
2066
2077
|
const skipped = [];
|
|
@@ -2074,8 +2085,7 @@ async function applyMigrations(params) {
|
|
|
2074
2085
|
meta: { migration: migration.name, statementIndex: stored.statementIndex }
|
|
2075
2086
|
});
|
|
2076
2087
|
}
|
|
2077
|
-
|
|
2078
|
-
if (complete) {
|
|
2088
|
+
if (isCompleteRecord({ dialect, migration, stored })) {
|
|
2079
2089
|
assertChecksumMatches({ migration, stored: stored.checksum });
|
|
2080
2090
|
skipped.push(migration.name);
|
|
2081
2091
|
continue;
|
|
@@ -2091,10 +2101,10 @@ async function applyMigrations(params) {
|
|
|
2091
2101
|
applied.push(migration.name);
|
|
2092
2102
|
continue;
|
|
2093
2103
|
}
|
|
2094
|
-
if (
|
|
2095
|
-
await runTransactional({ executor, dialect, migration });
|
|
2096
|
-
} else {
|
|
2104
|
+
if (usesStatementBookkeeping({ dialect, sql: migration.sql })) {
|
|
2097
2105
|
await runNonTransactional({ executor, dialect, migration, start: 0, insertRecord: true });
|
|
2106
|
+
} else {
|
|
2107
|
+
await runTransactional({ executor, dialect, migration });
|
|
2098
2108
|
}
|
|
2099
2109
|
applied.push(migration.name);
|
|
2100
2110
|
}
|
|
@@ -2106,7 +2116,6 @@ async function applyMigrations(params) {
|
|
|
2106
2116
|
async function migrationStatus(params) {
|
|
2107
2117
|
const { executor, migrations } = params;
|
|
2108
2118
|
const dialect = params.dialect ?? "postgres";
|
|
2109
|
-
const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
|
|
2110
2119
|
await ensureMigrationsTable({ executor, dialect });
|
|
2111
2120
|
const recorded = await recordedRows({ executor, dialect });
|
|
2112
2121
|
const applied = [];
|
|
@@ -2131,8 +2140,7 @@ async function migrationStatus(params) {
|
|
|
2131
2140
|
mismatched.push(migration.name);
|
|
2132
2141
|
continue;
|
|
2133
2142
|
}
|
|
2134
|
-
|
|
2135
|
-
if (complete)
|
|
2143
|
+
if (isCompleteRecord({ dialect, migration, stored }))
|
|
2136
2144
|
applied.push(migration.name);
|
|
2137
2145
|
else
|
|
2138
2146
|
pending.push(migration.name);
|
|
@@ -2157,7 +2165,6 @@ async function resolveMigration(params) {
|
|
|
2157
2165
|
async function rollbackMigration(params) {
|
|
2158
2166
|
const { executor, migration } = params;
|
|
2159
2167
|
const dialect = params.dialect ?? "postgres";
|
|
2160
|
-
const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
|
|
2161
2168
|
const downSql = migration.downSql;
|
|
2162
2169
|
if (downSql === undefined) {
|
|
2163
2170
|
throw new VibeError9({
|
|
@@ -2166,9 +2173,9 @@ async function rollbackMigration(params) {
|
|
|
2166
2173
|
meta: { migration: migration.name }
|
|
2167
2174
|
});
|
|
2168
2175
|
}
|
|
2169
|
-
await ensureMigrationsTable({ executor, dialect });
|
|
2170
2176
|
await acquireLock({ executor, dialect });
|
|
2171
2177
|
try {
|
|
2178
|
+
await ensureMigrationsTable({ executor, dialect });
|
|
2172
2179
|
const recorded = await recordedRows({ executor, dialect });
|
|
2173
2180
|
const stored = recorded.get(migration.name);
|
|
2174
2181
|
if (stored === undefined) {
|
|
@@ -2181,7 +2188,7 @@ async function rollbackMigration(params) {
|
|
|
2181
2188
|
const resumingDown = stored.statementIndex < 0;
|
|
2182
2189
|
assertChecksumMatches({ migration, stored: stored.checksum });
|
|
2183
2190
|
if (!resumingDown) {
|
|
2184
|
-
const partialUp = !
|
|
2191
|
+
const partialUp = !isCompleteRecord({ dialect, migration, stored });
|
|
2185
2192
|
if (partialUp) {
|
|
2186
2193
|
throw new VibeError9({
|
|
2187
2194
|
code: "VIBE_MIGRATION",
|
|
@@ -2190,11 +2197,11 @@ async function rollbackMigration(params) {
|
|
|
2190
2197
|
});
|
|
2191
2198
|
}
|
|
2192
2199
|
}
|
|
2193
|
-
if (
|
|
2194
|
-
await runTransactionalDown({ executor, dialect, migration, downSql });
|
|
2195
|
-
} else {
|
|
2200
|
+
if (usesStatementBookkeeping({ dialect, sql: downSql })) {
|
|
2196
2201
|
const start = resumingDown ? -stored.statementIndex - 1 : 0;
|
|
2197
2202
|
await runNonTransactionalDown({ executor, dialect, migration, downSql, start });
|
|
2203
|
+
} else {
|
|
2204
|
+
await runTransactionalDown({ executor, dialect, migration, downSql });
|
|
2198
2205
|
}
|
|
2199
2206
|
} finally {
|
|
2200
2207
|
await releaseLock({ executor, dialect });
|
|
@@ -2233,8 +2240,10 @@ async function runTransactionalDown(params) {
|
|
|
2233
2240
|
}
|
|
2234
2241
|
}
|
|
2235
2242
|
async function runNonTransactionalDown(params) {
|
|
2236
|
-
const { executor, dialect, migration, downSql
|
|
2243
|
+
const { executor, dialect, migration, downSql } = params;
|
|
2237
2244
|
const table = q4(dialect, MIGRATIONS_TABLE_NAME);
|
|
2245
|
+
const selfManaged = dialect === "sqlite" && usesSelfManagedTransactions({ sql: downSql });
|
|
2246
|
+
const start = selfManaged ? selfManagedResumeStart({ sql: downSql, start: params.start }) : params.start;
|
|
2238
2247
|
const recordProgress = async (completed) => {
|
|
2239
2248
|
await executor({
|
|
2240
2249
|
text: `UPDATE ${table} SET ${q4(dialect, "statement_index")} = ${ph(dialect, 1)}, ${q4(dialect, "error")} = NULL WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
|
|
@@ -2247,6 +2256,8 @@ async function runNonTransactionalDown(params) {
|
|
|
2247
2256
|
try {
|
|
2248
2257
|
await executeStatement({ executor, statement: downSql[index], dialect });
|
|
2249
2258
|
} catch (error) {
|
|
2259
|
+
if (selfManaged)
|
|
2260
|
+
await cleanupSelfManagedFailure({ executor });
|
|
2250
2261
|
try {
|
|
2251
2262
|
await executor({
|
|
2252
2263
|
text: `UPDATE ${table} SET ${q4(dialect, "error")} = ${ph(dialect, 1)} WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
|
|
@@ -2302,8 +2313,10 @@ async function runTransactional(params) {
|
|
|
2302
2313
|
}
|
|
2303
2314
|
}
|
|
2304
2315
|
async function runNonTransactional(params) {
|
|
2305
|
-
const { executor, dialect, migration,
|
|
2316
|
+
const { executor, dialect, migration, insertRecord } = params;
|
|
2306
2317
|
const table = q4(dialect, MIGRATIONS_TABLE_NAME);
|
|
2318
|
+
const selfManaged = dialect === "sqlite" && usesSelfManagedTransactions({ sql: migration.sql });
|
|
2319
|
+
const start = selfManaged ? selfManagedResumeStart({ sql: migration.sql, start: params.start }) : params.start;
|
|
2307
2320
|
if (insertRecord) {
|
|
2308
2321
|
await executor({
|
|
2309
2322
|
text: `INSERT INTO ${table} (${q4(dialect, "name")}, ${q4(dialect, "checksum")}, ${q4(dialect, "statement_index")}) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, 0)`,
|
|
@@ -2314,6 +2327,8 @@ async function runNonTransactional(params) {
|
|
|
2314
2327
|
try {
|
|
2315
2328
|
await executeStatement({ executor, statement: migration.sql[index], dialect });
|
|
2316
2329
|
} catch (error) {
|
|
2330
|
+
if (selfManaged)
|
|
2331
|
+
await cleanupSelfManagedFailure({ executor });
|
|
2317
2332
|
try {
|
|
2318
2333
|
await executor({
|
|
2319
2334
|
text: `UPDATE ${table} SET ${q4(dialect, "error")} = ${ph(dialect, 1)} WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
|
|
@@ -2364,6 +2379,20 @@ async function releaseLock(params) {
|
|
|
2364
2379
|
}
|
|
2365
2380
|
} catch {}
|
|
2366
2381
|
}
|
|
2382
|
+
function usesStatementBookkeeping(params) {
|
|
2383
|
+
const { dialect, sql } = params;
|
|
2384
|
+
if (!DIALECT_CAPABILITIES[dialect].transactionalDdl)
|
|
2385
|
+
return true;
|
|
2386
|
+
return dialect === "sqlite" && usesSelfManagedTransactions({ sql });
|
|
2387
|
+
}
|
|
2388
|
+
function isCompleteRecord(params) {
|
|
2389
|
+
const { dialect, migration, stored } = params;
|
|
2390
|
+
if (stored.checksum === "")
|
|
2391
|
+
return true;
|
|
2392
|
+
if (!usesStatementBookkeeping({ dialect, sql: migration.sql }))
|
|
2393
|
+
return true;
|
|
2394
|
+
return stored.statementIndex >= migration.sql.length;
|
|
2395
|
+
}
|
|
2367
2396
|
async function recordedRows(params) {
|
|
2368
2397
|
const { executor, dialect } = params;
|
|
2369
2398
|
const rows = await executor({
|
|
@@ -4057,4 +4086,4 @@ export {
|
|
|
4057
4086
|
MIGRATIONS_TABLE_NAME
|
|
4058
4087
|
};
|
|
4059
4088
|
|
|
4060
|
-
//# debugId=
|
|
4089
|
+
//# debugId=DA60A1F7881A22C064756E2164756E21
|