@vibeorm/migrate 2.0.0-alpha.6 → 2.0.0-alpha.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/ddl/render.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf,GAAG,MAAM,EAAE,CAkBX"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/ddl/render.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf,GAAG,MAAM,EAAE,CAsBX"}
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.
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../src/execute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAO9C,2EAA2E;AAC3E,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,OAAO,CAEvF;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"}
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
@@ -1771,6 +1771,8 @@ function columnDefSql3(params) {
1771
1771
  });
1772
1772
  }
1773
1773
  let def = `${name} ${mysqlColumnTypeSql({ field, enums })}`;
1774
+ if (field.collation !== undefined)
1775
+ def += ` COLLATE ${field.collation}`;
1774
1776
  if (!field.isOptional)
1775
1777
  def += " NOT NULL";
1776
1778
  if (autoincrement)
@@ -1957,10 +1959,22 @@ function artifactCreateSql(params) {
1957
1959
  // packages/migrate/src/execute.ts
1958
1960
  import { VibeError as VibeError8 } from "@vibeorm/schema";
1959
1961
  var SELF_MANAGED_MARKER = "PRAGMA foreign_keys=OFF";
1962
+ var SELF_MANAGED_RESTORE_MARKER = "PRAGMA foreign_keys=ON";
1960
1963
  var FK_CHECK_PREFIX = "PRAGMA foreign_key_check";
1961
1964
  function usesSelfManagedTransactions(params) {
1962
1965
  return params.sql.some((statement) => statement.startsWith(SELF_MANAGED_MARKER));
1963
1966
  }
1967
+ function selfManagedResumeStart(params) {
1968
+ const { sql, start } = params;
1969
+ for (let index = start - 1;index >= 0; index -= 1) {
1970
+ const statement = sql[index];
1971
+ if (statement.startsWith(SELF_MANAGED_RESTORE_MARKER))
1972
+ return start;
1973
+ if (statement.startsWith(SELF_MANAGED_MARKER))
1974
+ return index;
1975
+ }
1976
+ return start;
1977
+ }
1964
1978
  async function executeStatement(params) {
1965
1979
  const { executor, statement, dialect } = params;
1966
1980
  if (dialect === "sqlite" && statement.startsWith(FK_CHECK_PREFIX)) {
@@ -2057,10 +2071,9 @@ function generateMigration(params) {
2057
2071
  async function applyMigrations(params) {
2058
2072
  const { executor, migrations } = params;
2059
2073
  const dialect = params.dialect ?? "postgres";
2060
- const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
2061
- await ensureMigrationsTable({ executor, dialect });
2062
2074
  await acquireLock({ executor, dialect });
2063
2075
  try {
2076
+ await ensureMigrationsTable({ executor, dialect });
2064
2077
  const recorded = await recordedRows({ executor, dialect });
2065
2078
  const applied = [];
2066
2079
  const skipped = [];
@@ -2074,8 +2087,7 @@ async function applyMigrations(params) {
2074
2087
  meta: { migration: migration.name, statementIndex: stored.statementIndex }
2075
2088
  });
2076
2089
  }
2077
- const complete = stored.checksum === "" || transactional || stored.statementIndex >= migration.sql.length;
2078
- if (complete) {
2090
+ if (isCompleteRecord({ dialect, migration, stored })) {
2079
2091
  assertChecksumMatches({ migration, stored: stored.checksum });
2080
2092
  skipped.push(migration.name);
2081
2093
  continue;
@@ -2091,10 +2103,10 @@ async function applyMigrations(params) {
2091
2103
  applied.push(migration.name);
2092
2104
  continue;
2093
2105
  }
2094
- if (transactional) {
2095
- await runTransactional({ executor, dialect, migration });
2096
- } else {
2106
+ if (usesStatementBookkeeping({ dialect, sql: migration.sql })) {
2097
2107
  await runNonTransactional({ executor, dialect, migration, start: 0, insertRecord: true });
2108
+ } else {
2109
+ await runTransactional({ executor, dialect, migration });
2098
2110
  }
2099
2111
  applied.push(migration.name);
2100
2112
  }
@@ -2106,7 +2118,6 @@ async function applyMigrations(params) {
2106
2118
  async function migrationStatus(params) {
2107
2119
  const { executor, migrations } = params;
2108
2120
  const dialect = params.dialect ?? "postgres";
2109
- const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
2110
2121
  await ensureMigrationsTable({ executor, dialect });
2111
2122
  const recorded = await recordedRows({ executor, dialect });
2112
2123
  const applied = [];
@@ -2131,8 +2142,7 @@ async function migrationStatus(params) {
2131
2142
  mismatched.push(migration.name);
2132
2143
  continue;
2133
2144
  }
2134
- const complete = transactional || stored.statementIndex >= migration.sql.length;
2135
- if (complete)
2145
+ if (isCompleteRecord({ dialect, migration, stored }))
2136
2146
  applied.push(migration.name);
2137
2147
  else
2138
2148
  pending.push(migration.name);
@@ -2157,7 +2167,6 @@ async function resolveMigration(params) {
2157
2167
  async function rollbackMigration(params) {
2158
2168
  const { executor, migration } = params;
2159
2169
  const dialect = params.dialect ?? "postgres";
2160
- const transactional = DIALECT_CAPABILITIES[dialect].transactionalDdl;
2161
2170
  const downSql = migration.downSql;
2162
2171
  if (downSql === undefined) {
2163
2172
  throw new VibeError9({
@@ -2166,9 +2175,9 @@ async function rollbackMigration(params) {
2166
2175
  meta: { migration: migration.name }
2167
2176
  });
2168
2177
  }
2169
- await ensureMigrationsTable({ executor, dialect });
2170
2178
  await acquireLock({ executor, dialect });
2171
2179
  try {
2180
+ await ensureMigrationsTable({ executor, dialect });
2172
2181
  const recorded = await recordedRows({ executor, dialect });
2173
2182
  const stored = recorded.get(migration.name);
2174
2183
  if (stored === undefined) {
@@ -2181,7 +2190,7 @@ async function rollbackMigration(params) {
2181
2190
  const resumingDown = stored.statementIndex < 0;
2182
2191
  assertChecksumMatches({ migration, stored: stored.checksum });
2183
2192
  if (!resumingDown) {
2184
- const partialUp = !transactional && stored.checksum !== "" && stored.statementIndex < migration.sql.length;
2193
+ const partialUp = !isCompleteRecord({ dialect, migration, stored });
2185
2194
  if (partialUp) {
2186
2195
  throw new VibeError9({
2187
2196
  code: "VIBE_MIGRATION",
@@ -2190,11 +2199,11 @@ async function rollbackMigration(params) {
2190
2199
  });
2191
2200
  }
2192
2201
  }
2193
- if (transactional) {
2194
- await runTransactionalDown({ executor, dialect, migration, downSql });
2195
- } else {
2202
+ if (usesStatementBookkeeping({ dialect, sql: downSql })) {
2196
2203
  const start = resumingDown ? -stored.statementIndex - 1 : 0;
2197
2204
  await runNonTransactionalDown({ executor, dialect, migration, downSql, start });
2205
+ } else {
2206
+ await runTransactionalDown({ executor, dialect, migration, downSql });
2198
2207
  }
2199
2208
  } finally {
2200
2209
  await releaseLock({ executor, dialect });
@@ -2233,8 +2242,10 @@ async function runTransactionalDown(params) {
2233
2242
  }
2234
2243
  }
2235
2244
  async function runNonTransactionalDown(params) {
2236
- const { executor, dialect, migration, downSql, start } = params;
2245
+ const { executor, dialect, migration, downSql } = params;
2237
2246
  const table = q4(dialect, MIGRATIONS_TABLE_NAME);
2247
+ const selfManaged = dialect === "sqlite" && usesSelfManagedTransactions({ sql: downSql });
2248
+ const start = selfManaged ? selfManagedResumeStart({ sql: downSql, start: params.start }) : params.start;
2238
2249
  const recordProgress = async (completed) => {
2239
2250
  await executor({
2240
2251
  text: `UPDATE ${table} SET ${q4(dialect, "statement_index")} = ${ph(dialect, 1)}, ${q4(dialect, "error")} = NULL WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
@@ -2247,6 +2258,8 @@ async function runNonTransactionalDown(params) {
2247
2258
  try {
2248
2259
  await executeStatement({ executor, statement: downSql[index], dialect });
2249
2260
  } catch (error) {
2261
+ if (selfManaged)
2262
+ await cleanupSelfManagedFailure({ executor });
2250
2263
  try {
2251
2264
  await executor({
2252
2265
  text: `UPDATE ${table} SET ${q4(dialect, "error")} = ${ph(dialect, 1)} WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
@@ -2302,8 +2315,10 @@ async function runTransactional(params) {
2302
2315
  }
2303
2316
  }
2304
2317
  async function runNonTransactional(params) {
2305
- const { executor, dialect, migration, start, insertRecord } = params;
2318
+ const { executor, dialect, migration, insertRecord } = params;
2306
2319
  const table = q4(dialect, MIGRATIONS_TABLE_NAME);
2320
+ const selfManaged = dialect === "sqlite" && usesSelfManagedTransactions({ sql: migration.sql });
2321
+ const start = selfManaged ? selfManagedResumeStart({ sql: migration.sql, start: params.start }) : params.start;
2307
2322
  if (insertRecord) {
2308
2323
  await executor({
2309
2324
  text: `INSERT INTO ${table} (${q4(dialect, "name")}, ${q4(dialect, "checksum")}, ${q4(dialect, "statement_index")}) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, 0)`,
@@ -2314,6 +2329,8 @@ async function runNonTransactional(params) {
2314
2329
  try {
2315
2330
  await executeStatement({ executor, statement: migration.sql[index], dialect });
2316
2331
  } catch (error) {
2332
+ if (selfManaged)
2333
+ await cleanupSelfManagedFailure({ executor });
2317
2334
  try {
2318
2335
  await executor({
2319
2336
  text: `UPDATE ${table} SET ${q4(dialect, "error")} = ${ph(dialect, 1)} WHERE ${q4(dialect, "name")} = ${ph(dialect, 2)}`,
@@ -2364,6 +2381,20 @@ async function releaseLock(params) {
2364
2381
  }
2365
2382
  } catch {}
2366
2383
  }
2384
+ function usesStatementBookkeeping(params) {
2385
+ const { dialect, sql } = params;
2386
+ if (!DIALECT_CAPABILITIES[dialect].transactionalDdl)
2387
+ return true;
2388
+ return dialect === "sqlite" && usesSelfManagedTransactions({ sql });
2389
+ }
2390
+ function isCompleteRecord(params) {
2391
+ const { dialect, migration, stored } = params;
2392
+ if (stored.checksum === "")
2393
+ return true;
2394
+ if (!usesStatementBookkeeping({ dialect, sql: migration.sql }))
2395
+ return true;
2396
+ return stored.statementIndex >= migration.sql.length;
2397
+ }
2367
2398
  async function recordedRows(params) {
2368
2399
  const { executor, dialect } = params;
2369
2400
  const rows = await executor({
@@ -4057,4 +4088,4 @@ export {
4057
4088
  MIGRATIONS_TABLE_NAME
4058
4089
  };
4059
4090
 
4060
- //# debugId=CA4C1473A398313F64756E2164756E21
4091
+ //# debugId=70C1B35231C75DF864756E2164756E21