@vibeorm/migrate 1.3.1 → 2.0.0-alpha.2

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 (61) 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/sqlite.d.ts +62 -0
  11. package/dist/ddl/sqlite.d.ts.map +1 -0
  12. package/dist/differ.d.ts +33 -0
  13. package/dist/differ.d.ts.map +1 -0
  14. package/dist/down.d.ts +55 -0
  15. package/dist/down.d.ts.map +1 -0
  16. package/dist/enum-values.d.ts +19 -0
  17. package/dist/enum-values.d.ts.map +1 -0
  18. package/dist/execute.d.ts +41 -0
  19. package/dist/execute.d.ts.map +1 -0
  20. package/dist/extensions.d.ts +74 -0
  21. package/dist/extensions.d.ts.map +1 -0
  22. package/dist/index.d.ts +26 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +3858 -0
  25. package/dist/index.js.map +31 -0
  26. package/dist/introspect/mysql.d.ts +31 -0
  27. package/dist/introspect/mysql.d.ts.map +1 -0
  28. package/dist/introspect/postgres.d.ts +25 -0
  29. package/dist/introspect/postgres.d.ts.map +1 -0
  30. package/dist/introspect/shared.d.ts +76 -0
  31. package/dist/introspect/shared.d.ts.map +1 -0
  32. package/dist/introspect/sqlite.d.ts +53 -0
  33. package/dist/introspect/sqlite.d.ts.map +1 -0
  34. package/dist/mysql-types.d.ts +66 -0
  35. package/dist/mysql-types.d.ts.map +1 -0
  36. package/dist/normalize.d.ts +115 -0
  37. package/dist/normalize.d.ts.map +1 -0
  38. package/dist/postgres-types.d.ts +95 -0
  39. package/dist/postgres-types.d.ts.map +1 -0
  40. package/dist/push.d.ts +45 -0
  41. package/dist/push.d.ts.map +1 -0
  42. package/dist/relations.d.ts +40 -0
  43. package/dist/relations.d.ts.map +1 -0
  44. package/dist/runner.d.ts +120 -0
  45. package/dist/runner.d.ts.map +1 -0
  46. package/dist/sqlite-types.d.ts +87 -0
  47. package/dist/sqlite-types.d.ts.map +1 -0
  48. package/dist/types.d.ts +217 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/package.json +33 -23
  51. package/src/cascade-actions.ts +0 -88
  52. package/src/ddl-builder.ts +0 -415
  53. package/src/index.ts +0 -41
  54. package/src/introspector.ts +0 -684
  55. package/src/migration-runner.ts +0 -127
  56. package/src/relation-utils.ts +0 -79
  57. package/src/schema-differ.ts +0 -865
  58. package/src/schema-printer.ts +0 -259
  59. package/src/snapshot.ts +0 -141
  60. package/src/sql-utils.ts +0 -45
  61. package/src/types.ts +0 -13
@@ -0,0 +1,120 @@
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` takes an advisory lock for the whole run —
6
+ * `pg_advisory_lock(1447645253)` on postgres ("VIBE" in ASCII, blocking,
7
+ * released in a finally), `GET_LOCK('vibeorm_migrate', 60)` on mysql (throws
8
+ * VIBE_MIGRATION on timeout). sqlite needs none: it is single-writer and
9
+ * `BEGIN` serializes. Locks are session-scoped — the SqlExecutor contract
10
+ * (types.ts) requires one session for the whole operation.
11
+ *
12
+ * Execution strategy per dialect (`DIALECT_CAPABILITIES[dialect]`):
13
+ *
14
+ * - transactionalDdl (postgres, sqlite): each migration runs inside
15
+ * BEGIN/COMMIT with its bookkeeping INSERT — atomic. EXCEPT sqlite scripts
16
+ * containing a table-rebuild block, which manage their own transactions
17
+ * (execute.ts `usesSelfManagedTransactions`); those run unwrapped and are
18
+ * re-runnable (the rebuild recipe is effectively idempotent), with the
19
+ * record written after the script completes.
20
+ * - mysql (transactionalDdl: false — DDL auto-commits): the runner records
21
+ * PER-STATEMENT progress instead. The row is inserted up front
22
+ * (statement_index 0), advanced after every statement, and on failure the
23
+ * error lands in the `error` column. Re-running RESUMES from the recorded
24
+ * statement_index — and REFUSES if the migration's checksum changed since
25
+ * the partial application. A row is "complete" when its statement_index
26
+ * reaches the statement count (or its checksum is empty — resolveMigration
27
+ * records, which store statement_index 2147483647).
28
+ *
29
+ * Checksums (sha256 over the joined SQL) pin a migration's content:
30
+ * re-applying a renamed-or-edited migration is a VIBE_MIGRATION error, never
31
+ * a silent divergence.
32
+ */
33
+ import type { Dialect, SchemaIR, VibeExtension } from "@vibeorm/schema";
34
+ import type { AppliedResult, MigrationFile, MigrationStatus, SqlExecutor } from "./types.ts";
35
+ /** Name of the migrations bookkeeping table (skipped by introspection). */
36
+ export declare const MIGRATIONS_TABLE_NAME: string;
37
+ /** Create the bookkeeping table when missing. */
38
+ export declare function ensureMigrationsTable(params: {
39
+ executor: SqlExecutor;
40
+ dialect?: Dialect;
41
+ }): Promise<void>;
42
+ /** sha256 hex over the migration's statements — its identity across runs. */
43
+ export declare function migrationChecksum(params: {
44
+ sql: readonly string[];
45
+ }): string;
46
+ /**
47
+ * Diff two IRs and render a named migration for a dialect (postgres if
48
+ * omitted). `destructive` aggregates the steps' flags so callers can gate
49
+ * confirmation before applying.
50
+ */
51
+ export declare function generateMigration(params: {
52
+ from: SchemaIR;
53
+ to: SchemaIR;
54
+ name: string;
55
+ /** Rendering dialect; postgres if omitted. */
56
+ dialect?: Dialect;
57
+ /** Configured extension instances — their artifacts land in the migration. */
58
+ extensions?: readonly VibeExtension[];
59
+ }): MigrationFile;
60
+ /**
61
+ * Apply migrations in order under an advisory lock (see module doc).
62
+ * Already-recorded migrations are checksum-verified and skipped; a mismatch
63
+ * throws VIBE_MIGRATION (a recorded migration whose SQL changed is
64
+ * corruption, not drift to paper over). On mysql, a partially-applied
65
+ * migration RESUMES from its recorded statement_index. Records created by
66
+ * `resolveMigration` (empty checksum) skip verification.
67
+ */
68
+ export declare function applyMigrations(params: {
69
+ executor: SqlExecutor;
70
+ migrations: readonly MigrationFile[];
71
+ /** Execution dialect; postgres if omitted. */
72
+ dialect?: Dialect;
73
+ }): Promise<AppliedResult>;
74
+ /** Compare known migrations against the bookkeeping table. */
75
+ export declare function migrationStatus(params: {
76
+ executor: SqlExecutor;
77
+ migrations: readonly MigrationFile[];
78
+ /** Bookkeeping dialect; postgres if omitted. */
79
+ dialect?: Dialect;
80
+ }): Promise<MigrationStatus>;
81
+ /**
82
+ * Repair the bookkeeping table without running SQL: mark a migration as
83
+ * `"applied"` (upsert its record; pass `checksum` to also pin its content —
84
+ * omitted, the record stores an empty checksum and later runs skip
85
+ * verification for it) or `"rolled-back"` (delete its record).
86
+ */
87
+ export declare function resolveMigration(params: {
88
+ executor: SqlExecutor;
89
+ name: string;
90
+ as: "applied" | "rolled-back";
91
+ checksum?: string;
92
+ /** Bookkeeping dialect; postgres if omitted. */
93
+ dialect?: Dialect;
94
+ }): Promise<void>;
95
+ /**
96
+ * Roll back ONE applied migration by executing its `downSql` and deleting its
97
+ * bookkeeping row, under the same advisory lock as `applyMigrations`.
98
+ *
99
+ * Guards, in order: the migration must carry `downSql` (older migrations
100
+ * predate down-migration support), must be recorded as applied, and — when
101
+ * the record pins a checksum — its up SQL must still match (rolling back with
102
+ * drifted files would run a down that no longer mirrors what was applied).
103
+ *
104
+ * Dialect behavior mirrors apply: postgres/sqlite run the down inside
105
+ * BEGIN/COMMIT with the bookkeeping DELETE (atomic; sqlite rebuild scripts
106
+ * run unwrapped, see module doc). mysql DDL auto-commits, so progress is
107
+ * recorded per-statement in the existing `statement_index` column, NEGATIVE
108
+ * to mark the rollback direction: after k down statements, the row stores
109
+ * -(k+1). A failed mysql rollback resumes from the recorded statement on the
110
+ * next call; `applyMigrations` refuses a mid-rollback record. A partially
111
+ * APPLIED mysql migration cannot be rolled back — its down mirrors the full
112
+ * up; finish applying (apply resumes) or repair with `resolveMigration`.
113
+ */
114
+ export declare function rollbackMigration(params: {
115
+ executor: SqlExecutor;
116
+ migration: MigrationFile;
117
+ /** Execution dialect; postgres if omitted. */
118
+ dialect?: Dialect;
119
+ }): Promise<void>;
120
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAexE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI7F,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,EAAE,MAA2B,CAAC;AAsChE,iDAAiD;AACjD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,QAAQ,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhB;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,MAAM,CAE5E;AAID;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACvC,GAAG,aAAa,CA6BhB;AAID;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IACrC,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,aAAa,CAAC,CA6DzB;AAID,8DAA8D;AAC9D,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IACrC,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqC3B;AAID;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,WAAW,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,SAAS,GAAG,aAAa,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE;IAC9C,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,aAAa,CAAC;IACzB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDhB"}
@@ -0,0 +1,87 @@
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
+ /**
80
+ * Recover enum columns from a table's `sqlite_master.sql` text. Only checks
81
+ * following OUR naming convention are recognized; foreign CHECK constraints
82
+ * are ignored (and — documented limitation — do not survive a table rebuild).
83
+ */
84
+ export declare function parseSqliteEnumChecks(params: {
85
+ tableSql: string;
86
+ }): ParsedEnumCheck[];
87
+ //# 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;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,EAAE,CAYrF"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Public types of @vibeorm/migrate: the executor contract, the dialect-neutral
3
+ * migration step model, and the runner's file/result shapes.
4
+ *
5
+ * Steps carry Schema-IR fragments (FieldIR, EnumIR) — never SQL text. SQL is
6
+ * produced exclusively by the per-dialect renderers (ddl-postgres.ts), so every
7
+ * SQL-text decision stays reviewable in one place (constitution rule 3/4).
8
+ */
9
+ import type { CascadeAction, EnumIR, FieldIR } from "@vibeorm/schema";
10
+ /**
11
+ * Minimal SQL execution contract the migrate engine runs on. Structurally
12
+ * identical to @vibeorm/runtime's `SqlExecutor` (its `toSqlExecutor` bridges a
13
+ * DatabaseAdapter to this shape) — declared here so the dependency direction
14
+ * stays schema ← sql ← migrate.
15
+ *
16
+ * SESSION AFFINITY: the migrate engine issues session-scoped statements
17
+ * through this contract (BEGIN/COMMIT, `PRAGMA foreign_keys`, advisory locks
18
+ * `pg_advisory_lock` / `GET_LOCK`), so every call MUST hit the same database
19
+ * session. Single-connection adapters (pglite, sqlite) satisfy this by
20
+ * construction; pool-backed executors must pin one connection for the whole
21
+ * migrate operation.
22
+ */
23
+ export type SqlExecutor = (params: {
24
+ text: string;
25
+ values?: unknown[];
26
+ }) => Promise<Record<string, unknown>[]>;
27
+ /** Which aspects of a column an `alterColumn` step changes. */
28
+ export type AlterColumnAspect = "type" | "nullability" | "default";
29
+ /** One column of an index, with its sort direction. */
30
+ export type IndexColumn = {
31
+ readonly name: string;
32
+ readonly desc: boolean;
33
+ /**
34
+ * The field is a Decimal (SQLITE-2, SQL review round 2). Inert everywhere
35
+ * except the sqlite DDL renderer: Decimal stores as TEXT there and every
36
+ * compare/order site reads `CAST(col AS REAL)` (B4), which a plain-column
37
+ * index can never serve (EQP-proven SCAN) — sqlite renders an EXPRESSION
38
+ * index over the same cast instead. Not part of the index comparison key:
39
+ * both sides compare by column name + direction.
40
+ */
41
+ readonly decimal?: boolean;
42
+ };
43
+ /** One side of an implicit many-to-many join table. */
44
+ export type JoinTableEnd = {
45
+ /** Referenced table (db name). */
46
+ readonly table: string;
47
+ /** Referenced primary-key column (db name). */
48
+ readonly column: string;
49
+ /** The referenced primary-key field — its type renders the join column's type. */
50
+ readonly field: FieldIR;
51
+ };
52
+ /**
53
+ * A dialect-neutral migration step produced by `diffSchemas`. `destructive`
54
+ * marks steps that can lose data (dropTable / dropJoinTable / dropColumn /
55
+ * dropEnum / narrowing type changes) — `push` refuses them without
56
+ * `acceptDataLoss`, and `generateMigration` surfaces the flag.
57
+ */
58
+ export type MigrationStep = {
59
+ readonly kind: "createEnum";
60
+ readonly enumDef: EnumIR;
61
+ readonly destructive: false;
62
+ } | {
63
+ readonly kind: "dropEnum";
64
+ readonly enumName: string;
65
+ readonly destructive: true;
66
+ } | {
67
+ readonly kind: "addEnumValue";
68
+ readonly enumName: string;
69
+ readonly value: string;
70
+ readonly destructive: false;
71
+ } | {
72
+ readonly kind: "createTable";
73
+ readonly table: string;
74
+ readonly columns: readonly FieldIR[];
75
+ /** Primary-key column db names (empty = no PK). */
76
+ readonly primaryKey: readonly string[];
77
+ readonly destructive: false;
78
+ } | {
79
+ readonly kind: "dropTable";
80
+ readonly table: string;
81
+ readonly destructive: true;
82
+ } | {
83
+ readonly kind: "addColumn";
84
+ readonly table: string;
85
+ readonly column: FieldIR;
86
+ readonly destructive: false;
87
+ } | {
88
+ readonly kind: "dropColumn";
89
+ readonly table: string;
90
+ readonly column: string;
91
+ readonly destructive: true;
92
+ } | {
93
+ readonly kind: "alterColumn";
94
+ readonly table: string;
95
+ /** Column db name. */
96
+ readonly column: string;
97
+ readonly from: FieldIR;
98
+ readonly to: FieldIR;
99
+ readonly changes: readonly AlterColumnAspect[];
100
+ readonly destructive: boolean;
101
+ } | {
102
+ readonly kind: "createIndex";
103
+ readonly table: string;
104
+ readonly name: string;
105
+ /** IR index kind ("btree", "gin", …) — `unique` indexes are always btree. */
106
+ readonly indexKind: string;
107
+ readonly unique: boolean;
108
+ readonly columns: readonly IndexColumn[];
109
+ /** Partial-index predicate, raw SQL. */
110
+ readonly where?: string;
111
+ readonly destructive: false;
112
+ } | {
113
+ readonly kind: "dropIndex";
114
+ readonly name: string;
115
+ /**
116
+ * Table the index belongs to. Optional for postgres/sqlite (their DROP
117
+ * INDEX is schema-global) but REQUIRED by the mysql renderer
118
+ * (`DROP INDEX … ON table`); the differ always fills it.
119
+ */
120
+ readonly table?: string;
121
+ readonly destructive: false;
122
+ } | {
123
+ readonly kind: "addForeignKey";
124
+ readonly table: string;
125
+ readonly constraintName: string;
126
+ readonly columns: readonly string[];
127
+ readonly refTable: string;
128
+ readonly refColumns: readonly string[];
129
+ readonly onDelete: CascadeAction;
130
+ readonly onUpdate: CascadeAction;
131
+ readonly destructive: false;
132
+ } | {
133
+ readonly kind: "dropForeignKey";
134
+ readonly table: string;
135
+ readonly constraintName: string;
136
+ readonly destructive: false;
137
+ } | {
138
+ readonly kind: "createJoinTable";
139
+ readonly table: string;
140
+ readonly a: JoinTableEnd;
141
+ readonly b: JoinTableEnd;
142
+ readonly destructive: false;
143
+ } | {
144
+ readonly kind: "dropJoinTable";
145
+ readonly table: string;
146
+ readonly destructive: true;
147
+ } | {
148
+ readonly kind: "addPrimaryKey";
149
+ readonly table: string;
150
+ readonly columns: readonly string[];
151
+ readonly destructive: false;
152
+ } | {
153
+ readonly kind: "dropPrimaryKey";
154
+ readonly table: string;
155
+ readonly destructive: false;
156
+ } | {
157
+ /**
158
+ * Drop a view present in the live database but absent from the target
159
+ * schema (board #26). Ordered FIRST — postgres refuses dropping a column
160
+ * a leftover view depends on (2BP01), so removed views must go before
161
+ * the table/column changes they block. Destructive: the view definition
162
+ * is not stored in the IR, so the drop cannot be reversed.
163
+ */
164
+ readonly kind: "dropView";
165
+ /** View db name. */
166
+ readonly table: string;
167
+ readonly destructive: true;
168
+ };
169
+ /** One-line human description of a step (refusal messages, CLI output). */
170
+ export declare function describeStep(params: {
171
+ step: MigrationStep;
172
+ }): string;
173
+ /** A named migration: ordered SQL statements plus its aggregate destructiveness. */
174
+ export type MigrationFile = {
175
+ readonly name: string;
176
+ /** One SQL string per statement, in execution order. */
177
+ readonly sql: readonly string[];
178
+ /** True when any underlying step can lose data. */
179
+ readonly destructive: boolean;
180
+ /**
181
+ * Reverse statements (`down.sql`), when the migration carries them.
182
+ * Migrations generated before down-migration support have none —
183
+ * `rollbackMigration` refuses those with a clear error.
184
+ */
185
+ readonly downSql?: readonly string[];
186
+ };
187
+ /** Result of `applyMigrations`. */
188
+ export type AppliedResult = {
189
+ /** Migrations executed by this call, in order. */
190
+ readonly applied: readonly string[];
191
+ /** Migrations already recorded and verified, skipped. */
192
+ readonly skipped: readonly string[];
193
+ };
194
+ /** Result of `migrationStatus`. */
195
+ export type MigrationStatus = {
196
+ /** Recorded migrations whose checksum matches. */
197
+ readonly applied: readonly string[];
198
+ /** Migrations with no record yet. */
199
+ readonly pending: readonly string[];
200
+ /** Recorded migrations whose checksum no longer matches their SQL. */
201
+ readonly mismatched: readonly string[];
202
+ /**
203
+ * Migrations whose rollback started but did not finish (mysql only — its
204
+ * DDL is non-transactional, so `rollbackMigration` records per-statement
205
+ * progress). Re-run the rollback to resume, or repair with
206
+ * `resolveMigration`.
207
+ */
208
+ readonly rollingBack: readonly string[];
209
+ };
210
+ /** Result of `push`. */
211
+ export type PushResult = {
212
+ /** The diff that was applied (empty = database already matched). */
213
+ readonly steps: readonly MigrationStep[];
214
+ /** The SQL statements that were executed, in order. */
215
+ readonly applied: readonly string[];
216
+ };
217
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,42 +1,52 @@
1
1
  {
2
2
  "name": "@vibeorm/migrate",
3
- "version": "1.3.1",
4
- "description": "Migration, introspection, and schema diff toolkit for VibeORM",
5
- "license": "MIT",
3
+ "version": "2.0.0-alpha.2",
4
+ "description": "Migration engine for VibeORM v2 — IR differ, per-dialect DDL, migration runner, introspection",
6
5
  "keywords": [
7
6
  "orm",
8
- "migrations",
9
- "postgresql",
10
- "bun",
11
7
  "typescript",
12
- "introspection"
8
+ "sql",
9
+ "database",
10
+ "bun",
11
+ "type-safe",
12
+ "migrations",
13
+ "ddl",
14
+ "introspection",
15
+ "schema-diff",
16
+ "postgres",
17
+ "mysql",
18
+ "sqlite"
13
19
  ],
20
+ "homepage": "https://github.com/vibeorm/vibeorm/tree/master/packages/migrate#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/vibeorm/vibeorm/issues"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/vibeorm/vibeorm.git",
27
+ "directory": "packages/migrate"
28
+ },
29
+ "license": "MIT",
30
+ "author": "VibeORM contributors",
14
31
  "type": "module",
15
32
  "exports": {
16
33
  ".": {
17
- "default": "./src/index.ts",
18
- "types": "./src/index.ts"
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
19
36
  }
20
37
  },
21
38
  "files": [
22
- "src"
39
+ "dist",
40
+ "README.md"
23
41
  ],
24
- "repository": {
25
- "type": "git",
26
- "url": "https://github.com/vibeorm/vibeorm.git",
27
- "directory": "packages/migrate"
42
+ "engines": {
43
+ "bun": ">=1.2.0"
28
44
  },
29
- "homepage": "https://github.com/vibeorm/vibeorm/tree/master/packages/migrate",
30
- "bugs": {
31
- "url": "https://github.com/vibeorm/vibeorm/issues"
45
+ "dependencies": {
46
+ "@vibeorm/schema": "2.0.0-alpha.1",
47
+ "@vibeorm/sql": "2.0.0-alpha.1"
32
48
  },
33
49
  "publishConfig": {
34
50
  "access": "public"
35
- },
36
- "engines": {
37
- "bun": ">=1.1.0"
38
- },
39
- "dependencies": {
40
- "@vibeorm/parser": "1.3.1"
41
51
  }
42
52
  }
@@ -1,88 +0,0 @@
1
- /**
2
- * Cascade-action resolution and SQL serialisation.
3
- *
4
- * Translates a `CascadeAction` from the parser IR into a Postgres
5
- * `ON DELETE`/`ON UPDATE` clause, applying Prisma-compatible defaults when
6
- * the schema doesn't specify an action explicitly.
7
- *
8
- * Defaults (matching Prisma's Postgres behaviour):
9
- * - `onDelete`: required FK → `Restrict`, optional FK → `SetNull`
10
- * - `onUpdate`: always → `Cascade`
11
- */
12
-
13
- import type { CascadeAction, RelationField } from "@vibeorm/parser";
14
-
15
- const ACTION_TO_SQL: Record<CascadeAction, string> = {
16
- Cascade: "CASCADE",
17
- Restrict: "RESTRICT",
18
- NoAction: "NO ACTION",
19
- SetNull: "SET NULL",
20
- SetDefault: "SET DEFAULT",
21
- };
22
-
23
- /**
24
- * Inverse of {@link ACTION_TO_SQL} — used by the introspector when reading
25
- * `pg_constraint.confdeltype`/`confupdtype`. The single-char codes are
26
- * Postgres's catalog representation.
27
- */
28
- export const PG_CHAR_TO_CASCADE_ACTION: Record<string, CascadeAction> = {
29
- a: "NoAction",
30
- r: "Restrict",
31
- c: "Cascade",
32
- n: "SetNull",
33
- d: "SetDefault",
34
- };
35
-
36
- /**
37
- * Resolve the effective onDelete action for a relation, applying the Prisma
38
- * default when the schema didn't say anything explicit.
39
- *
40
- * `isRequired` is the FK column's nullability (Prisma's "required relation").
41
- */
42
- export function resolveOnDelete(params: {
43
- explicit: CascadeAction | undefined;
44
- isRequired: boolean;
45
- }): CascadeAction {
46
- if (params.explicit) return params.explicit;
47
- return params.isRequired ? "Restrict" : "SetNull";
48
- }
49
-
50
- /** Resolve the effective onUpdate action. Prisma's Postgres default is Cascade. */
51
- export function resolveOnUpdate(params: {
52
- explicit: CascadeAction | undefined;
53
- }): CascadeAction {
54
- return params.explicit ?? "Cascade";
55
- }
56
-
57
- /** Convenience: serialise a CascadeAction to its Postgres clause body. */
58
- export function cascadeActionSql(params: { action: CascadeAction }): string {
59
- return ACTION_TO_SQL[params.action];
60
- }
61
-
62
- /**
63
- * Build the full `ON DELETE X ON UPDATE Y` clause for a relation field,
64
- * applying defaults as needed.
65
- */
66
- export function buildFkActionClause(params: { rel: RelationField }): string {
67
- const { rel } = params;
68
- const onDelete = resolveOnDelete({
69
- explicit: rel.relation.onDelete,
70
- isRequired: rel.isRequired,
71
- });
72
- const onUpdate = resolveOnUpdate({ explicit: rel.relation.onUpdate });
73
- return `ON DELETE ${ACTION_TO_SQL[onDelete]} ON UPDATE ${ACTION_TO_SQL[onUpdate]}`;
74
- }
75
-
76
- /**
77
- * Stable comparison key for whether two relations have the same effective
78
- * cascade behaviour. Used by the differ to detect drift even when the schema
79
- * was written without explicit actions (defaults must still be considered).
80
- */
81
- export function fkActionFingerprint(params: { rel: RelationField }): string {
82
- const onDelete = resolveOnDelete({
83
- explicit: params.rel.relation.onDelete,
84
- isRequired: params.rel.isRequired,
85
- });
86
- const onUpdate = resolveOnUpdate({ explicit: params.rel.relation.onUpdate });
87
- return `${onDelete}|${onUpdate}`;
88
- }