@vibeorm/migrate 1.3.1 → 2.0.0-alpha.10

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.
Files changed (73) hide show
  1. package/README.md +33 -66
  2. package/dist/ddl/drop-order.d.ts +25 -0
  3. package/dist/ddl/drop-order.d.ts.map +1 -0
  4. package/dist/ddl/mysql.d.ts +46 -0
  5. package/dist/ddl/mysql.d.ts.map +1 -0
  6. package/dist/ddl/postgres.d.ts +24 -0
  7. package/dist/ddl/postgres.d.ts.map +1 -0
  8. package/dist/ddl/render.d.ts +25 -0
  9. package/dist/ddl/render.d.ts.map +1 -0
  10. package/dist/ddl/rls.d.ts +40 -0
  11. package/dist/ddl/rls.d.ts.map +1 -0
  12. package/dist/ddl/sqlite.d.ts +79 -0
  13. package/dist/ddl/sqlite.d.ts.map +1 -0
  14. package/dist/differ.d.ts +41 -0
  15. package/dist/differ.d.ts.map +1 -0
  16. package/dist/down.d.ts +57 -0
  17. package/dist/down.d.ts.map +1 -0
  18. package/dist/enum-values.d.ts +32 -0
  19. package/dist/enum-values.d.ts.map +1 -0
  20. package/dist/execute.d.ts +124 -0
  21. package/dist/execute.d.ts.map +1 -0
  22. package/dist/execution.d.ts +168 -0
  23. package/dist/execution.d.ts.map +1 -0
  24. package/dist/extensions.d.ts +74 -0
  25. package/dist/extensions.d.ts.map +1 -0
  26. package/dist/index.d.ts +32 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +5688 -0
  29. package/dist/index.js.map +37 -0
  30. package/dist/introspect/mysql.d.ts +31 -0
  31. package/dist/introspect/mysql.d.ts.map +1 -0
  32. package/dist/introspect/postgres-rls.d.ts +41 -0
  33. package/dist/introspect/postgres-rls.d.ts.map +1 -0
  34. package/dist/introspect/postgres.d.ts +12 -0
  35. package/dist/introspect/postgres.d.ts.map +1 -0
  36. package/dist/introspect/shared.d.ts +78 -0
  37. package/dist/introspect/shared.d.ts.map +1 -0
  38. package/dist/introspect/sqlite.d.ts +53 -0
  39. package/dist/introspect/sqlite.d.ts.map +1 -0
  40. package/dist/journal-table.d.ts +15 -0
  41. package/dist/journal-table.d.ts.map +1 -0
  42. package/dist/mysql-types.d.ts +66 -0
  43. package/dist/mysql-types.d.ts.map +1 -0
  44. package/dist/normalize.d.ts +143 -0
  45. package/dist/normalize.d.ts.map +1 -0
  46. package/dist/postgres-types.d.ts +95 -0
  47. package/dist/postgres-types.d.ts.map +1 -0
  48. package/dist/push.d.ts +51 -0
  49. package/dist/push.d.ts.map +1 -0
  50. package/dist/recovery.d.ts +41 -0
  51. package/dist/recovery.d.ts.map +1 -0
  52. package/dist/relations.d.ts +40 -0
  53. package/dist/relations.d.ts.map +1 -0
  54. package/dist/renames.d.ts +58 -0
  55. package/dist/renames.d.ts.map +1 -0
  56. package/dist/runner.d.ts +181 -0
  57. package/dist/runner.d.ts.map +1 -0
  58. package/dist/sqlite-types.d.ts +101 -0
  59. package/dist/sqlite-types.d.ts.map +1 -0
  60. package/dist/types.d.ts +329 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/package.json +34 -23
  63. package/src/cascade-actions.ts +0 -88
  64. package/src/ddl-builder.ts +0 -415
  65. package/src/index.ts +0 -41
  66. package/src/introspector.ts +0 -684
  67. package/src/migration-runner.ts +0 -127
  68. package/src/relation-utils.ts +0 -79
  69. package/src/schema-differ.ts +0 -865
  70. package/src/schema-printer.ts +0 -259
  71. package/src/snapshot.ts +0 -141
  72. package/src/sql-utils.ts +0 -45
  73. package/src/types.ts +0 -13
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Establishing what actually happened, before a nontransactional migration
3
+ * re-runs anything.
4
+ *
5
+ * A migration that runs outside a transaction can die between a statement
6
+ * committing and the journal recording it. The only honest recovery is to ask
7
+ * the database what the world looks like now and compare it against the
8
+ * statement's DECLARED postcondition (execution.ts). Three answers exist:
9
+ *
10
+ * - `"satisfied"` — the live catalog already matches the declaration. Skip it.
11
+ * - `"runnable"` — the declaration is demonstrably not in effect, and running
12
+ * the statement is the way to get there.
13
+ * - a thrown `VibeError` — the state is neither, and no automatic action is
14
+ * safe. Nothing is dropped, nothing is re-run: the operator decides.
15
+ *
16
+ * There is deliberately NO fourth answer of the form "probably fine, re-run
17
+ * it". This module never claims exactly-once execution of arbitrary SQL; it
18
+ * only decides the cases a declared postcondition can actually settle.
19
+ *
20
+ * Comparison is conservative by design. Expressions must match verbatim apart
21
+ * from surrounding whitespace. Quotes and whitespace inside literals can change
22
+ * meaning; any difference is a CONFLICT — a false conflict costs an operator one
23
+ * look, a false match corrupts a schema.
24
+ */
25
+ import type { Dialect } from "@vibeorm/schema";
26
+ import type { MigrationOperation } from "./execution.ts";
27
+ import type { SqlExecutor } from "./types.ts";
28
+ /** Whether a declared operation's postcondition already holds. */
29
+ export type OperationState = "satisfied" | "runnable";
30
+ /**
31
+ * Ask the database whether a declared operation is already in effect.
32
+ *
33
+ * PostgreSQL only: it is the one dialect with a nontransactional migration
34
+ * regime here, and every probe reads its catalogs.
35
+ */
36
+ export declare function establishOperationState(params: {
37
+ executor: SqlExecutor;
38
+ dialect: Dialect;
39
+ operation: MigrationOperation;
40
+ }): Promise<OperationState>;
41
+ //# sourceMappingURL=recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAS/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,CAAC;AA6BtD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE;IACpD,QAAQ,EAAE,WAAW,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,kBAAkB,CAAC;CAC/B,GAAG,OAAO,CAAC,cAAc,CAAC,CAkG1B"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Implicit many-to-many detection on Schema IR.
3
+ *
4
+ * ONE structural rule in @vibeorm/schema, also used by RLS validation and
5
+ * matching the parser's ambiguity rule (see LEARNINGS): two fields form an
6
+ * implicit M:N **iff** both are lists that declare no FK columns, they are
7
+ * distinct fields (self-exclusion — a 1:N self-relation must never pair with
8
+ * itself), their relation names match symmetrically (both unnamed, or both
9
+ * the same name), and each side is the OTHER'S SOLE counterpart under that
10
+ * name key. Detection never reads `relation.type`, because an introspected
11
+ * schema represents a real join table as two unnamed `oneToMany` list sides —
12
+ * trusting the type would break round-trip stability.
13
+ *
14
+ * The sole-counterpart requirement is the phantom-join-table fix, round two:
15
+ * two models holding foreign keys INTO EACH OTHER introspect as an unnamed
16
+ * fieldless list on each side (every FK synthesizes one on its target), and
17
+ * name-matching alone would marry those lists into a join table that exists
18
+ * nowhere. Counting EVERY relation under the name key — FK-owning sides
19
+ * included — disambiguates: the parser rejects the same shape as
20
+ * `ambiguous-relation` at parse time, so parsed and introspected schemas
21
+ * resolve identically.
22
+ *
23
+ * The join-table naming itself comes from the ONE shared convention in
24
+ * `@vibeorm/schema` (`implicitJoinTable`) — never re-derived here.
25
+ */
26
+ import type { SchemaIR } from "@vibeorm/schema";
27
+ /** A detected implicit many-to-many relation. `modelA` sorts before `modelB`. */
28
+ export type ImplicitM2MPair = {
29
+ readonly modelA: string;
30
+ readonly modelB: string;
31
+ /** Shared explicit relation name, when both sides declare one. */
32
+ readonly relationName?: string;
33
+ /** Join table name per the shared convention (`_PostToTag`, `_tags`). */
34
+ readonly tableName: string;
35
+ };
36
+ /** Detect every implicit many-to-many pair in a schema. */
37
+ export declare function detectImplicitM2MPairs(params: {
38
+ schema: SchemaIR;
39
+ }): ImplicitM2MPair[];
40
+ //# sourceMappingURL=relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,iFAAiF;AACjF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GAAG,eAAe,EAAE,CA4BtF"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * EXPLICIT physical renames.
3
+ *
4
+ * The differ deliberately has no rename detection: two schemas that differ by
5
+ * a name are indistinguishable from a drop plus a create, and guessing between
6
+ * them from "similar shapes" is how a migration tool silently destroys a
7
+ * column. A rename therefore only ever happens because someone WROTE one down,
8
+ * as an old physical name and a new physical name, and it is validated against
9
+ * both schemas before a single statement is rendered.
10
+ *
11
+ * `@map` / `@@map` remains the no-DDL option: mapping a model or field to the
12
+ * name the database already uses changes generated code only. Use a rename
13
+ * intent when the DATABASE object must actually move.
14
+ *
15
+ * What a physical rename preserves, on every dialect that supports it: the
16
+ * rows, the column defaults, the indexes and constraints attached to the
17
+ * object, and inbound foreign keys — the object keeps its identity, only its
18
+ * name changes. PostgreSQL policy expressions follow the rename too, because
19
+ * they are stored parsed and reference the object by identity, not by text.
20
+ *
21
+ * What refuses instead of guessing: renaming a table and one of its columns in
22
+ * the same plan (the second intent's table name is then ambiguous), an intent
23
+ * whose endpoints do not both check out against the two schemas, and two
24
+ * intents pointing at the same object.
25
+ */
26
+ import type { Dialect, SchemaIR } from "@vibeorm/schema";
27
+ import type { MigrationStep } from "./types.ts";
28
+ /** One deliberately written rename, in PHYSICAL (database) names. */
29
+ export type RenameIntent = {
30
+ readonly kind: "table";
31
+ readonly from: string;
32
+ readonly to: string;
33
+ } | {
34
+ readonly kind: "column";
35
+ readonly table: string;
36
+ readonly from: string;
37
+ readonly to: string;
38
+ };
39
+ /**
40
+ * Validate rename intents against the two schemas and turn them into steps,
41
+ * returning the SOURCE schema rewritten as if the renames had happened.
42
+ *
43
+ * The rewrite is what keeps the rest of the diff honest: once the source model
44
+ * carries the new physical name, the ordinary differ sees one table on both
45
+ * sides and emits no drop/create pair for it. Only `dbName` moves — the
46
+ * logical IR graph (relations, index field lists) is untouched, so nothing
47
+ * downstream has to know a rename happened.
48
+ */
49
+ export declare function planRenames(params: {
50
+ from: SchemaIR;
51
+ to: SchemaIR;
52
+ renames: readonly RenameIntent[];
53
+ dialect: Dialect;
54
+ }): {
55
+ readonly steps: readonly MigrationStep[];
56
+ readonly from: SchemaIR;
57
+ };
58
+ //# sourceMappingURL=renames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renames.d.ts","sourceRoot":"","sources":["../src/renames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAW,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qEAAqE;AACrE,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAuBpG;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,QAAQ,CAAC;IACb,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAkGxE"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Migration runner: generate named migrations from IR diffs, apply them with
3
+ * bookkeeping in `_vibe_migrations`, report status, and repair records.
4
+ *
5
+ * Concurrency: `applyMigrations` and `rollbackMigration` take an advisory lock
6
+ * for the whole run — `pg_advisory_lock(1447645253)` on postgres ("VIBE" in
7
+ * ASCII, blocking, released in a finally), `GET_LOCK('vibeorm_migrate', 60)`
8
+ * on mysql (throws VIBE_MIGRATION on timeout). sqlite needs none: it is
9
+ * single-writer and `BEGIN` serializes. Locks are session-scoped — the
10
+ * SqlExecutor contract (types.ts) requires one session for the whole
11
+ * operation.
12
+ *
13
+ * Lock ORDER matters: the lock is taken BEFORE `ensureMigrationsTable`, never
14
+ * after. Two concurrent first-time runs against a fresh postgres database
15
+ * would otherwise both issue `CREATE TABLE IF NOT EXISTS _vibe_migrations`,
16
+ * which is a catalog race on postgres (a duplicate-key error on
17
+ * `pg_type_typname_nsp_index`, not a no-op). `migrationStatus` and
18
+ * `resolveMigration` deliberately take NO lock — wrapping reads in the
19
+ * migration lock would make `status` block behind a running migrate — so two
20
+ * concurrent FIRST-EVER `status`/`resolve` calls on a fresh database can still
21
+ * hit that race; retrying either is enough, since the table then exists.
22
+ *
23
+ * Execution strategy per dialect (`DIALECT_CAPABILITIES[dialect]`) AND per
24
+ * script:
25
+ *
26
+ * - transactionalDdl (postgres, sqlite): each migration runs inside
27
+ * BEGIN/COMMIT with its bookkeeping INSERT — atomic.
28
+ * - EXCEPT sqlite scripts containing a table-rebuild block, which manage their
29
+ * own transactions (execute.ts `usesSelfManagedTransactions`) and therefore
30
+ * cannot be wrapped. Those take the SAME per-statement bookkeeping as mysql
31
+ * (below). They are NOT simply "re-runnable": a pure rebuild block is
32
+ * effectively idempotent, but any plain statement in the same script
33
+ * auto-commits on its own, so without a recorded statement_index a crash
34
+ * wedged the migration forever (every later run replayed statements that had
35
+ * already run). Resuming into a rebuild block rewinds to that block's
36
+ * `PRAGMA foreign_keys=OFF` (execute.ts `selfManagedResumeStart`): the block
37
+ * is transactional, so nothing of it survived, and the pragma is
38
+ * session-scoped and gone after a crash.
39
+ * - mysql (transactionalDdl: false — DDL auto-commits): the runner records
40
+ * PER-STATEMENT progress instead. The row is inserted up front
41
+ * (statement_index 0), advanced after every statement, and on failure the
42
+ * error lands in the `error` column. Re-running RESUMES from the recorded
43
+ * statement_index — and REFUSES if the migration's checksum changed since
44
+ * the partial application. A row is "complete" when its statement_index
45
+ * reaches the statement count (or its checksum is empty — resolveMigration
46
+ * records, which store statement_index 2147483647).
47
+ *
48
+ * `usesStatementBookkeeping` is the ONE predicate deciding which of the two
49
+ * regimes a (dialect, script) pair is in; apply, status and rollback all read
50
+ * it, so they can never disagree about whether a record is complete.
51
+ *
52
+ * Checksums (sha256 over the joined SQL) pin a migration's content:
53
+ * re-applying a renamed-or-edited migration is a VIBE_MIGRATION error, never
54
+ * a silent divergence.
55
+ */
56
+ import type { Dialect, SchemaIR, VibeExtension } from "@vibeorm/schema";
57
+ import type { MigrationExecution } from "./execution.ts";
58
+ import type { RenameIntent } from "./renames.ts";
59
+ import type { AppliedResult, MigrationFile, MigrationStatus, RecordedMigration, SqlExecutor } from "./types.ts";
60
+ export { MIGRATIONS_TABLE_NAME } from "./journal-table.ts";
61
+ /** Create the bookkeeping table when missing. */
62
+ export declare function ensureMigrationsTable(params: {
63
+ executor: SqlExecutor;
64
+ dialect?: Dialect;
65
+ }): Promise<void>;
66
+ /**
67
+ * sha256 hex over the migration's statements — its identity across runs.
68
+ *
69
+ * A NON-default execution block (execution.ts) folds a canonical description
70
+ * of itself in, so changing how a migration executes after it was applied is
71
+ * caught by the same checksum refusal that catches changing its SQL. A default
72
+ * or absent block contributes NOTHING, which is what keeps every migration
73
+ * written before this feature — and every journal row recording one — valid.
74
+ */
75
+ export declare function migrationChecksum(params: {
76
+ sql: readonly string[];
77
+ execution?: MigrationExecution;
78
+ }): string;
79
+ /**
80
+ * Diff two IRs and render a named migration for a dialect (postgres if
81
+ * omitted). `destructive` aggregates the steps' flags so callers can gate
82
+ * confirmation before applying.
83
+ */
84
+ export declare function generateMigration(params: {
85
+ from: SchemaIR;
86
+ to: SchemaIR;
87
+ name: string;
88
+ /** Rendering dialect; postgres if omitted. */
89
+ dialect?: Dialect;
90
+ /** Configured extension instances — their artifacts land in the migration. */
91
+ extensions?: readonly VibeExtension[];
92
+ /** Explicit physical renames (renames.ts); never inferred from the diff. */
93
+ renames?: readonly RenameIntent[];
94
+ /** Explicit execution semantics for the generated file. */
95
+ execution?: MigrationExecution;
96
+ }): MigrationFile;
97
+ /**
98
+ * Apply migrations in order under an advisory lock (see module doc).
99
+ * Already-recorded migrations are checksum-verified and skipped; a mismatch
100
+ * throws VIBE_MIGRATION (a recorded migration whose SQL changed is
101
+ * corruption, not drift to paper over). Where progress is recorded per
102
+ * statement (mysql, and self-managed sqlite scripts), a partially-applied
103
+ * migration RESUMES from its recorded statement_index. Records created by
104
+ * `resolveMigration` (empty checksum) skip verification.
105
+ */
106
+ export declare function applyMigrations(params: {
107
+ executor: SqlExecutor;
108
+ migrations: readonly MigrationFile[];
109
+ acceptSecurityChanges?: boolean;
110
+ /** Execution dialect; postgres if omitted. */
111
+ dialect?: Dialect;
112
+ }): Promise<AppliedResult>;
113
+ /** Compare known migrations against the bookkeeping table. */
114
+ export declare function migrationStatus(params: {
115
+ executor: SqlExecutor;
116
+ migrations: readonly MigrationFile[];
117
+ /** Bookkeeping dialect; postgres if omitted. */
118
+ dialect?: Dialect;
119
+ /** Trusted current deployment; policy state is verified independently of migration records. */
120
+ schema?: SchemaIR;
121
+ }): Promise<MigrationStatus>;
122
+ /**
123
+ * The bookkeeping journal itself, in the order rows were written — i.e. the
124
+ * order migrations were actually applied, which is what a rollback must walk
125
+ * backwards. Every row is returned and classified, including the ones
126
+ * `migrationStatus` folds away: a mismatched record, a partially applied one
127
+ * and a record whose file is gone all still occupy a position in history, and
128
+ * a caller that skips them rolls back the WRONG migration (F28).
129
+ *
130
+ * Takes no lock, exactly like `migrationStatus`.
131
+ */
132
+ export declare function recordedMigrations(params: {
133
+ executor: SqlExecutor;
134
+ /** Known migration files — classification needs their SQL. */
135
+ migrations: readonly MigrationFile[];
136
+ /** Bookkeeping dialect; postgres if omitted. */
137
+ dialect?: Dialect;
138
+ }): Promise<RecordedMigration[]>;
139
+ /**
140
+ * Repair the bookkeeping table without running SQL: mark a migration as
141
+ * `"applied"` (upsert its record; pass `checksum` to also pin its content —
142
+ * omitted, the record stores an empty checksum and later runs skip
143
+ * verification for it) or `"rolled-back"` (delete its record).
144
+ */
145
+ export declare function resolveMigration(params: {
146
+ executor: SqlExecutor;
147
+ name: string;
148
+ as: "applied" | "rolled-back";
149
+ checksum?: string;
150
+ /** Bookkeeping dialect; postgres if omitted. */
151
+ dialect?: Dialect;
152
+ }): Promise<void>;
153
+ /**
154
+ * Roll back ONE applied migration by executing its `downSql` and deleting its
155
+ * bookkeeping row, under the same advisory lock as `applyMigrations`.
156
+ *
157
+ * Guards, in order: the migration must carry `downSql` (older migrations
158
+ * predate down-migration support), must be recorded as applied, and — when
159
+ * the record pins a checksum — its up SQL must still match (rolling back with
160
+ * drifted files would run a down that no longer mirrors what was applied).
161
+ *
162
+ * Dialect behavior mirrors apply exactly (same `usesStatementBookkeeping`
163
+ * predicate, read over the DOWN script): postgres/sqlite run the down inside
164
+ * BEGIN/COMMIT with the bookkeeping DELETE (atomic). mysql DDL auto-commits,
165
+ * and a sqlite down containing a table-rebuild block cannot be wrapped, so
166
+ * both record progress per-statement in the existing `statement_index`
167
+ * column, NEGATIVE to mark the rollback direction: after k down statements,
168
+ * the row stores -(k+1). A failed rollback resumes from the recorded
169
+ * statement on the next call; `applyMigrations` refuses a mid-rollback record
170
+ * (that check reads the sign only, so it holds for every dialect). A
171
+ * partially APPLIED migration cannot be rolled back — its down mirrors the
172
+ * full up; finish applying (apply resumes) or repair with `resolveMigration`.
173
+ */
174
+ export declare function rollbackMigration(params: {
175
+ executor: SqlExecutor;
176
+ migration: MigrationFile;
177
+ acceptSecurityChanges?: boolean;
178
+ /** Execution dialect; postgres if omitted. */
179
+ dialect?: Dialect;
180
+ }): Promise<void>;
181
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * SQLite column-type mapping (IR → storage class and back), comparison keys,
3
+ * default rendering/fingerprints, and the enum CHECK-constraint convention.
4
+ *
5
+ * dialect-matrix §2: sqlite columns use the four storage classes only —
6
+ * String/DateTime/Decimal/Json → TEXT, Boolean/Int/BigInt → INTEGER,
7
+ * Float → REAL, Bytes → BLOB. Enums are TEXT plus a named CHECK constraint
8
+ * (`CONSTRAINT "<table>_<column>_enum_<Enum>" CHECK ("<column>" IN (…))`) —
9
+ * the constraint NAME is the marker that lets introspection recover the enum's
10
+ * name, and the IN list recovers its values. Scalar lists are unsupported
11
+ * (refused by the differ; this module throws as the render-time backstop).
12
+ *
13
+ * THE TEXT AMBIGUITY, stated honestly: DateTime, Decimal and Json all live in
14
+ * TEXT, and Boolean/BigInt live in INTEGER — a pulled schema reports such
15
+ * columns as String/Int (there is no marker to say otherwise). Column
16
+ * comparison is therefore STORAGE-CLASS based on sqlite (`sqliteColumnTypeKey`
17
+ * compares what the database actually stores), so `diff(introspect(push(X)),
18
+ * X)` stays [] even though the introspected IR says String where X said
19
+ * DateTime.
20
+ */
21
+ import type { FieldIR, ScalarType } from "@vibeorm/schema";
22
+ import type { EnumIR } from "@vibeorm/schema";
23
+ /** IR scalar → sqlite storage class. */
24
+ export declare const SCALAR_TO_SQLITE: Readonly<Record<ScalarType, string>>;
25
+ /** Render-time backstop for scalar-list columns (the differ refuses earlier). */
26
+ export declare function refuseSqliteScalarList(params: {
27
+ field: FieldIR;
28
+ }): never;
29
+ /**
30
+ * Storage class for a column. Unsupported columns render their nativeType
31
+ * verbatim (fidelity over guessing); enums are TEXT (the CHECK is separate).
32
+ */
33
+ export declare function sqliteStorageType(params: {
34
+ field: FieldIR;
35
+ }): string;
36
+ /**
37
+ * Comparison key for a column on sqlite: the STORAGE CLASS, not the IR type —
38
+ * String and DateTime are both `t:TEXT` because the database cannot tell them
39
+ * apart. Enum columns key on their VALUE LIST (`e:A|B`), never their name
40
+ * (the name only lives in our CHECK-constraint convention): adding an enum
41
+ * value changes the key and flows through `alterColumn` → table rebuild with
42
+ * the widened CHECK.
43
+ */
44
+ export declare function sqliteColumnTypeKey(params: {
45
+ field: FieldIR;
46
+ enums: ReadonlyMap<string, EnumIR>;
47
+ }): string;
48
+ /**
49
+ * Default fingerprint on sqlite: postgres rules, except booleans compare as
50
+ * their INTEGER storage (`true` → `num:1`) — an introspected sqlite schema can
51
+ * only ever report `DEFAULT 1`, and the fingerprint must not churn on that.
52
+ */
53
+ export declare function sqliteDefaultFingerprint(params: {
54
+ field: FieldIR;
55
+ }): string | null;
56
+ /**
57
+ * Render the `DEFAULT` expression for a field on sqlite, or `undefined` when
58
+ * the column takes none (app-level generators, autoincrement — which renders
59
+ * as `INTEGER PRIMARY KEY AUTOINCREMENT` instead). Booleans store as 1/0.
60
+ */
61
+ export declare function sqliteDefaultSql(params: {
62
+ field: FieldIR;
63
+ }): string | undefined;
64
+ /**
65
+ * Name of the enum CHECK constraint for a column — the `_enum_` infix is the
66
+ * introspection marker that recovers the enum's name from `sqlite_master.sql`.
67
+ */
68
+ export declare function sqliteEnumCheckName(params: {
69
+ table: string;
70
+ column: string;
71
+ enumName: string;
72
+ }): string;
73
+ /** One parsed enum CHECK constraint from a table's `sqlite_master.sql`. */
74
+ export type ParsedEnumCheck = {
75
+ readonly column: string;
76
+ readonly enumName: string;
77
+ readonly values: readonly string[];
78
+ };
79
+ /** One parsed NAMED user CHECK from a table's `sqlite_master.sql`. */
80
+ export type ParsedNamedCheck = {
81
+ readonly name: string;
82
+ readonly expression: string;
83
+ };
84
+ /**
85
+ * Every `CONSTRAINT "name" CHECK (…)` in a table's `sqlite_master.sql`, with
86
+ * a balanced-paren walk for the expression (a regex capture would stop at the
87
+ * first `)`). The caller filters out the enum-convention names — those are
88
+ * column machinery, not user checks.
89
+ */
90
+ export declare function parseSqliteNamedChecks(params: {
91
+ tableSql: string;
92
+ }): ParsedNamedCheck[];
93
+ /**
94
+ * Recover enum columns from a table's `sqlite_master.sql` text. Only checks
95
+ * following OUR naming convention are recognized; foreign CHECK constraints
96
+ * are ignored (and — documented limitation — do not survive a table rebuild).
97
+ */
98
+ export declare function parseSqliteEnumChecks(params: {
99
+ tableSql: string;
100
+ }): ParsedEnumCheck[];
101
+ //# sourceMappingURL=sqlite-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-types.d.ts","sourceRoot":"","sources":["../src/sqlite-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAI9C,wCAAwC;AACxC,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAUjE,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAMxE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAepE;AAID;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,GAAG,MAAM,CAWT;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAOlF;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAuB/E;AAID;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAET;AAED,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,CAAC;AAKF,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,EAAE,CAuBvF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,EAAE,CAYrF"}