@metaobjectsdev/migrate-ts 0.5.0-rc.1

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 (98) hide show
  1. package/LICENSE +189 -0
  2. package/README.md +73 -0
  3. package/dist/diff/index.d.ts +30 -0
  4. package/dist/diff/index.d.ts.map +1 -0
  5. package/dist/diff/index.js +226 -0
  6. package/dist/diff/index.js.map +1 -0
  7. package/dist/diff/rename-heuristic.d.ts +23 -0
  8. package/dist/diff/rename-heuristic.d.ts.map +1 -0
  9. package/dist/diff/rename-heuristic.js +236 -0
  10. package/dist/diff/rename-heuristic.js.map +1 -0
  11. package/dist/diff/status.d.ts +8 -0
  12. package/dist/diff/status.d.ts.map +1 -0
  13. package/dist/diff/status.js +53 -0
  14. package/dist/diff/status.js.map +1 -0
  15. package/dist/emit/index.d.ts +17 -0
  16. package/dist/emit/index.d.ts.map +1 -0
  17. package/dist/emit/index.js +18 -0
  18. package/dist/emit/index.js.map +1 -0
  19. package/dist/emit/postgres.d.ts +3 -0
  20. package/dist/emit/postgres.d.ts.map +1 -0
  21. package/dist/emit/postgres.js +181 -0
  22. package/dist/emit/postgres.js.map +1 -0
  23. package/dist/emit/sqlite.d.ts +3 -0
  24. package/dist/emit/sqlite.d.ts.map +1 -0
  25. package/dist/emit/sqlite.js +302 -0
  26. package/dist/emit/sqlite.js.map +1 -0
  27. package/dist/errors.d.ts +8 -0
  28. package/dist/errors.d.ts.map +1 -0
  29. package/dist/errors.js +54 -0
  30. package/dist/errors.js.map +1 -0
  31. package/dist/expected-schema.d.ts +15 -0
  32. package/dist/expected-schema.d.ts.map +1 -0
  33. package/dist/expected-schema.js +243 -0
  34. package/dist/expected-schema.js.map +1 -0
  35. package/dist/index.d.ts +18 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +25 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/introspect/index.d.ts +6 -0
  40. package/dist/introspect/index.d.ts.map +1 -0
  41. package/dist/introspect/index.js +11 -0
  42. package/dist/introspect/index.js.map +1 -0
  43. package/dist/introspect/postgres.d.ts +57 -0
  44. package/dist/introspect/postgres.d.ts.map +1 -0
  45. package/dist/introspect/postgres.js +339 -0
  46. package/dist/introspect/postgres.js.map +1 -0
  47. package/dist/introspect/sqlite.d.ts +4 -0
  48. package/dist/introspect/sqlite.d.ts.map +1 -0
  49. package/dist/introspect/sqlite.js +192 -0
  50. package/dist/introspect/sqlite.js.map +1 -0
  51. package/dist/source-aware-diff.d.ts +20 -0
  52. package/dist/source-aware-diff.d.ts.map +1 -0
  53. package/dist/source-aware-diff.js +24 -0
  54. package/dist/source-aware-diff.js.map +1 -0
  55. package/dist/sql-type.d.ts +45 -0
  56. package/dist/sql-type.d.ts.map +1 -0
  57. package/dist/sql-type.js +76 -0
  58. package/dist/sql-type.js.map +1 -0
  59. package/dist/types.d.ts +223 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +2 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/view-ddl-postgres.d.ts +4 -0
  64. package/dist/view-ddl-postgres.d.ts.map +1 -0
  65. package/dist/view-ddl-postgres.js +13 -0
  66. package/dist/view-ddl-postgres.js.map +1 -0
  67. package/dist/view-ddl-sqlite.d.ts +3 -0
  68. package/dist/view-ddl-sqlite.d.ts.map +1 -0
  69. package/dist/view-ddl-sqlite.js +7 -0
  70. package/dist/view-ddl-sqlite.js.map +1 -0
  71. package/dist/view-diff.d.ts +13 -0
  72. package/dist/view-diff.d.ts.map +1 -0
  73. package/dist/view-diff.js +42 -0
  74. package/dist/view-diff.js.map +1 -0
  75. package/dist/write-migration.d.ts +19 -0
  76. package/dist/write-migration.d.ts.map +1 -0
  77. package/dist/write-migration.js +34 -0
  78. package/dist/write-migration.js.map +1 -0
  79. package/package.json +50 -0
  80. package/src/diff/index.ts +294 -0
  81. package/src/diff/rename-heuristic.ts +265 -0
  82. package/src/diff/status.ts +55 -0
  83. package/src/emit/index.ts +38 -0
  84. package/src/emit/postgres.ts +189 -0
  85. package/src/emit/sqlite.ts +322 -0
  86. package/src/errors.ts +58 -0
  87. package/src/expected-schema.ts +326 -0
  88. package/src/index.ts +49 -0
  89. package/src/introspect/index.ts +14 -0
  90. package/src/introspect/postgres.ts +428 -0
  91. package/src/introspect/sqlite.ts +216 -0
  92. package/src/source-aware-diff.ts +49 -0
  93. package/src/sql-type.ts +91 -0
  94. package/src/types.ts +174 -0
  95. package/src/view-ddl-postgres.ts +15 -0
  96. package/src/view-ddl-sqlite.ts +7 -0
  97. package/src/view-diff.ts +55 -0
  98. package/src/write-migration.ts +64 -0
@@ -0,0 +1,192 @@
1
+ import { sql } from "kysely";
2
+ export async function introspectSqlite(db) {
3
+ const k = db;
4
+ const versionRow = await sql `SELECT sqlite_version() AS v`.execute(k);
5
+ const meta = { sqliteVersion: versionRow.rows[0]?.v ?? "0.0.0" };
6
+ const tableNamesRows = await sql `
7
+ SELECT name, sql FROM sqlite_master
8
+ WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__new_%'
9
+ ORDER BY name
10
+ `.execute(k);
11
+ const tables = [];
12
+ for (const t of tableNamesRows.rows) {
13
+ const cols = await readSqliteColumns(k, t.name);
14
+ const pk = await readSqlitePrimaryKey(k, t.name);
15
+ // Detect AUTOINCREMENT via the CREATE TABLE statement (sqlite has no PRAGMA for it).
16
+ const hasAutoincrement = (t.sql ?? "").toUpperCase().includes("AUTOINCREMENT");
17
+ if (hasAutoincrement && pk.length === 1) {
18
+ const pkCol = cols.find((c) => c.name === pk[0]);
19
+ if (pkCol)
20
+ pkCol.identity = "increment";
21
+ }
22
+ tables.push({
23
+ name: t.name,
24
+ columns: cols,
25
+ indexes: await readSqliteIndexes(k, t.name),
26
+ foreignKeys: await readSqliteForeignKeys(k, t.name),
27
+ primaryKey: pk,
28
+ });
29
+ }
30
+ const views = await readSqliteViews(k);
31
+ return { tables, views, meta };
32
+ }
33
+ async function readSqliteViews(k) {
34
+ const rows = await sql `
35
+ SELECT name FROM sqlite_master WHERE type='view' AND name NOT LIKE 'sqlite_%'
36
+ ORDER BY name
37
+ `.execute(k);
38
+ return rows.rows.map((r) => ({ name: r.name }));
39
+ }
40
+ async function readSqliteColumns(k, table) {
41
+ // SELECT * avoids "notnull" being treated as a reserved keyword by libsql.
42
+ const rows = await sql `SELECT * FROM pragma_table_info(${table}) ORDER BY cid`.execute(k);
43
+ return rows.rows.map((r) => {
44
+ const col = {
45
+ name: r.name,
46
+ sqlType: sqliteTypeToSqlType(r.type),
47
+ nullable: r.notnull === 0 && r.pk === 0,
48
+ };
49
+ const def = parseSqliteDefault(r.dflt_value);
50
+ if (def)
51
+ col.default = def;
52
+ return col;
53
+ });
54
+ }
55
+ async function readSqlitePrimaryKey(k, table) {
56
+ // SELECT * avoids the "notnull" reserved-keyword issue in libsql.
57
+ const rows = await sql `
58
+ SELECT * FROM pragma_table_info(${table}) WHERE pk > 0 ORDER BY pk
59
+ `.execute(k);
60
+ return rows.rows.map((r) => r.name);
61
+ }
62
+ function sqliteTypeToSqlType(declaredType) {
63
+ const t = declaredType.trim().toUpperCase();
64
+ // SQLite's type affinity is loose; we honor the declared type literally for round-trip stability.
65
+ // Affinity rules per sqlite.org/datatype3.html — adapted to canonical SqlType.
66
+ // text affinity
67
+ const varcharMatch = /^(?:VARCHAR|CHAR|CHARACTER|TEXT)\((\d+)\)$/.exec(t);
68
+ if (varcharMatch)
69
+ return { kind: "text", maxLength: parseInt(varcharMatch[1] ?? "0", 10) };
70
+ if (/TEXT|CLOB|VARCHAR|CHAR/.test(t))
71
+ return { kind: "text" };
72
+ // numeric affinity
73
+ const numMatch = /^(?:NUMERIC|DECIMAL)\((\d+)(?:,\s*(\d+))?\)$/.exec(t);
74
+ if (numMatch) {
75
+ const out = { kind: "numeric" };
76
+ if (numMatch[1])
77
+ out.precision = parseInt(numMatch[1], 10);
78
+ if (numMatch[2])
79
+ out.scale = parseInt(numMatch[2], 10);
80
+ return out;
81
+ }
82
+ if (t === "BOOLEAN" || t === "BOOL")
83
+ return { kind: "boolean" };
84
+ if (t === "DATE")
85
+ return { kind: "date" };
86
+ if (t === "DATETIME" || t === "TIMESTAMP")
87
+ return { kind: "timestamp", withTimezone: false };
88
+ // integer affinity (SQLite stores all INTEGER as 64-bit internally).
89
+ // Distinguish INT (32-bit) from INTEGER/BIGINT (64-bit) for round-trip fidelity:
90
+ // the emitter uses "INT" for integer{32} and "INTEGER" for integer{64}.
91
+ if (t === "INT" || t === "SMALLINT" || t === "TINYINT")
92
+ return { kind: "integer", bits: 32 };
93
+ if (/INT/.test(t))
94
+ return { kind: "integer", bits: 64 };
95
+ // real affinity
96
+ if (/REAL|FLOA|DOUB/.test(t))
97
+ return { kind: "real" };
98
+ // blob affinity
99
+ if (t === "BLOB" || t === "")
100
+ return { kind: "blob" };
101
+ // numeric affinity fallback
102
+ if (/NUMERIC|DECIMAL/.test(t))
103
+ return { kind: "numeric" };
104
+ // json (libsql/sqlite have JSON1)
105
+ if (t === "JSON")
106
+ return { kind: "json" };
107
+ return { kind: "text" };
108
+ }
109
+ const SQLITE_EXPR_DEFAULT_PATTERNS = [
110
+ /^current_timestamp$/i,
111
+ /^current_date$/i,
112
+ /^current_time$/i,
113
+ /\(.*\)/, // anything function-like
114
+ ];
115
+ function parseSqliteDefault(raw) {
116
+ if (raw === null || raw === undefined || raw === "")
117
+ return undefined;
118
+ const isExpr = SQLITE_EXPR_DEFAULT_PATTERNS.some((re) => re.test(raw));
119
+ if (isExpr)
120
+ return { kind: "expr", value: raw };
121
+ // SQLite stores literal string defaults with surrounding quotes.
122
+ const cleaned = raw.replace(/^'(.*)'$/, "$1");
123
+ return { kind: "literal", value: cleaned };
124
+ }
125
+ async function readSqliteIndexes(k, table) {
126
+ // SELECT * avoids "unique" being treated as a reserved keyword by libsql.
127
+ const listRows = await sql `
128
+ SELECT * FROM pragma_index_list(${table})
129
+ `.execute(k);
130
+ const indexes = [];
131
+ for (const ix of listRows.rows) {
132
+ if (ix.origin === "pk")
133
+ continue; // PK index — excluded (lives in TableDescriptor.primaryKey)
134
+ if (ix.partial === 1)
135
+ continue; // partial indexes deferred to v0.3
136
+ const cols = await sql `
137
+ SELECT seqno, cid, name FROM pragma_index_info(${ix.name}) ORDER BY seqno
138
+ `.execute(k);
139
+ indexes.push({
140
+ name: ix.name,
141
+ columns: cols.rows.map((c) => c.name),
142
+ unique: ix.unique === 1,
143
+ });
144
+ }
145
+ return indexes;
146
+ }
147
+ async function readSqliteForeignKeys(k, table) {
148
+ // SELECT * avoids reserved-word column names ("table", "from", "to", "match") in libsql.
149
+ const rows = await sql `
150
+ SELECT * FROM pragma_foreign_key_list(${table}) ORDER BY id, seq
151
+ `.execute(k);
152
+ const byId = new Map();
153
+ for (const r of rows.rows) {
154
+ let entry = byId.get(r.id);
155
+ if (!entry) {
156
+ entry = {
157
+ refTable: r.table,
158
+ cols: [],
159
+ refCols: [],
160
+ onDelete: sqliteRuleToAction(r.on_delete),
161
+ onUpdate: sqliteRuleToAction(r.on_update),
162
+ };
163
+ byId.set(r.id, entry);
164
+ }
165
+ entry.cols.push(r.from);
166
+ entry.refCols.push(r.to);
167
+ }
168
+ return Array.from(byId.entries()).map(([_id, v]) => {
169
+ const fk = {
170
+ name: `${table}_${v.cols.join("_")}_fk`, // SQLite has no FK name; synthesize to match expected-schema convention
171
+ columns: v.cols,
172
+ refTable: v.refTable,
173
+ refColumns: v.refCols,
174
+ };
175
+ if (v.onDelete !== "no-action")
176
+ fk.onDelete = v.onDelete;
177
+ if (v.onUpdate !== "no-action")
178
+ fk.onUpdate = v.onUpdate;
179
+ return fk;
180
+ });
181
+ }
182
+ function sqliteRuleToAction(rule) {
183
+ const r = rule.toUpperCase();
184
+ if (r === "CASCADE")
185
+ return "cascade";
186
+ if (r === "SET NULL")
187
+ return "set-null";
188
+ if (r === "RESTRICT")
189
+ return "restrict";
190
+ return "no-action";
191
+ }
192
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/introspect/sqlite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type ViewShape } from "./view-diff.js";
2
+ export interface ViewMigrationInput {
3
+ readonly viewName: string;
4
+ /** Previous view shape (from migration log / prior generation). undefined = new view. */
5
+ readonly prevShape?: ViewShape;
6
+ readonly nextShape: ViewShape;
7
+ /** Full `CREATE VIEW ... AS ...;` SQL for nextShape. */
8
+ readonly createSql: string;
9
+ }
10
+ export interface ViewMigrationsOpts {
11
+ readonly dialect: "postgres" | "sqlite";
12
+ readonly allowBreaking: boolean;
13
+ readonly views: readonly ViewMigrationInput[];
14
+ }
15
+ export interface ViewMigrationsResult {
16
+ readonly migrations: readonly string[];
17
+ readonly errors: readonly string[];
18
+ }
19
+ export declare function computeViewMigrations(opts: ViewMigrationsOpts): ViewMigrationsResult;
20
+ //# sourceMappingURL=source-aware-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-aware-diff.d.ts","sourceRoot":"","sources":["../src/source-aware-diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIlE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,GAAG,oBAAoB,CAwBpF"}
@@ -0,0 +1,24 @@
1
+ import { classifyViewDiff } from "./view-diff.js";
2
+ import { emitPostgresViewMigration } from "./view-ddl-postgres.js";
3
+ import { emitSqliteViewMigration } from "./view-ddl-sqlite.js";
4
+ export function computeViewMigrations(opts) {
5
+ const migrations = [];
6
+ const errors = [];
7
+ for (const view of opts.views) {
8
+ const diffClass = view.prevShape
9
+ ? classifyViewDiff(view.prevShape, view.nextShape)
10
+ : "safe-append"; // new view = treated like safe-append
11
+ if (diffClass === "breaking" && !opts.allowBreaking) {
12
+ errors.push(`View ${view.viewName} has a breaking change. Pass --allow-breaking to allow drop+recreate.`);
13
+ continue;
14
+ }
15
+ const emit = opts.dialect === "postgres"
16
+ ? emitPostgresViewMigration
17
+ : emitSqliteViewMigration;
18
+ const sql = emit({ diffClass, viewName: view.viewName, createSql: view.createSql });
19
+ if (sql)
20
+ migrations.push(sql);
21
+ }
22
+ return { migrations, errors };
23
+ }
24
+ //# sourceMappingURL=source-aware-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-aware-diff.js","sourceRoot":"","sources":["../src/source-aware-diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAkB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAsB/D,MAAM,UAAU,qBAAqB,CAAC,IAAwB;IAC5D,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;YAC9B,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC;YAClD,CAAC,CAAC,aAAa,CAAC,CAAE,sCAAsC;QAE1D,IAAI,SAAS,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CACT,QAAQ,IAAI,CAAC,QAAQ,uEAAuE,CAC7F,CAAC;YACF,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,KAAK,UAAU;YACtC,CAAC,CAAC,yBAAyB;YAC3B,CAAC,CAAC,uBAAuB,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACpF,IAAI,GAAG;YAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Canonical, dialect-neutral SQL type. Both buildExpectedSchema (metadata→snapshot)
3
+ * and introspect (db→snapshot) produce this shape; diff compares canonical to
4
+ * canonical; emit re-renders to dialect-specific SQL.
5
+ *
6
+ * Per spec §5.2.
7
+ */
8
+ export type SqlType = {
9
+ kind: "text";
10
+ maxLength?: number;
11
+ } | {
12
+ kind: "integer";
13
+ bits: 32 | 64;
14
+ } | {
15
+ kind: "real";
16
+ } | {
17
+ kind: "numeric";
18
+ precision?: number;
19
+ scale?: number;
20
+ } | {
21
+ kind: "boolean";
22
+ } | {
23
+ kind: "timestamp";
24
+ withTimezone: boolean;
25
+ } | {
26
+ kind: "date";
27
+ } | {
28
+ kind: "json";
29
+ } | {
30
+ kind: "blob";
31
+ } | {
32
+ kind: "uuid";
33
+ };
34
+ /** Structural equality on SqlType. */
35
+ export declare function sqlTypeEquals(a: SqlType, b: SqlType): boolean;
36
+ /**
37
+ * Returns true if changing column type from `from` to `to` is provably non-lossy.
38
+ * Per spec §6.5. Conservative on purpose — false negatives just mean the user has
39
+ * to pass `allow.typeChange`; false positives could silently corrupt data.
40
+ *
41
+ * Returns false for identical types (caller should not emit a change-column-type
42
+ * in that case at all; this is defensive).
43
+ */
44
+ export declare function isWidening(from: SqlType, to: SqlType): boolean;
45
+ //# sourceMappingURL=sql-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-type.d.ts","sourceRoot":"","sources":["../src/sql-type.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,EAAE,GAAG,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAqB7D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,CAuC9D"}
@@ -0,0 +1,76 @@
1
+ /** Structural equality on SqlType. */
2
+ export function sqlTypeEquals(a, b) {
3
+ if (a.kind !== b.kind)
4
+ return false;
5
+ switch (a.kind) {
6
+ case "text":
7
+ return a.maxLength === b.maxLength;
8
+ case "integer":
9
+ return a.bits === b.bits;
10
+ case "numeric": {
11
+ const bn = b;
12
+ return a.precision === bn.precision && a.scale === bn.scale;
13
+ }
14
+ case "timestamp":
15
+ return a.withTimezone === b.withTimezone;
16
+ case "real":
17
+ case "boolean":
18
+ case "date":
19
+ case "json":
20
+ case "blob":
21
+ case "uuid":
22
+ return true;
23
+ }
24
+ }
25
+ /**
26
+ * Returns true if changing column type from `from` to `to` is provably non-lossy.
27
+ * Per spec §6.5. Conservative on purpose — false negatives just mean the user has
28
+ * to pass `allow.typeChange`; false positives could silently corrupt data.
29
+ *
30
+ * Returns false for identical types (caller should not emit a change-column-type
31
+ * in that case at all; this is defensive).
32
+ */
33
+ export function isWidening(from, to) {
34
+ if (sqlTypeEquals(from, to))
35
+ return false;
36
+ if (from.kind !== to.kind)
37
+ return false; // cross-kind: always lossy
38
+ switch (from.kind) {
39
+ case "text": {
40
+ const t = to;
41
+ // unbounded → bounded: lossy
42
+ if (from.maxLength === undefined)
43
+ return false;
44
+ // bounded → unbounded: widening
45
+ if (t.maxLength === undefined)
46
+ return true;
47
+ // bounded both: widening iff new ≥ old
48
+ return t.maxLength >= from.maxLength;
49
+ }
50
+ case "integer": {
51
+ const t = to;
52
+ return t.bits >= from.bits;
53
+ }
54
+ case "numeric": {
55
+ const t = to;
56
+ const fp = from.precision ?? 0;
57
+ const fs = from.scale ?? 0;
58
+ const tp = t.precision ?? 0;
59
+ const ts = t.scale ?? 0;
60
+ // widening iff p2 ≥ p1 AND s2 = s1 AND (p2 - s2) ≥ (p1 - s1)
61
+ return tp >= fp && ts === fs && (tp - ts) >= (fp - fs);
62
+ }
63
+ // real/boolean/date/json/blob/uuid: same kind already handled by sqlTypeEquals;
64
+ // any difference here means the discriminant matched but structural equality failed
65
+ // (impossible given SqlType has no other variants for these kinds). Defensive false.
66
+ case "real":
67
+ case "boolean":
68
+ case "date":
69
+ case "json":
70
+ case "blob":
71
+ case "uuid":
72
+ case "timestamp":
73
+ return false;
74
+ }
75
+ }
76
+ //# sourceMappingURL=sql-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-type.js","sourceRoot":"","sources":["../src/sql-type.ts"],"names":[],"mappings":"AAmBA,sCAAsC;AACtC,MAAM,UAAU,aAAa,CAAC,CAAU,EAAE,CAAU;IAClD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACpC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,CAAC,CAAC,SAAS,KAAM,CAAwC,CAAC,SAAS,CAAC;QAC7E,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,IAAI,KAAM,CAA2C,CAAC,IAAI,CAAC;QACtE,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,GAAG,CAA0C,CAAC;YACtD,OAAO,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC;QAC9D,CAAC;QACD,KAAK,WAAW;YACd,OAAO,CAAC,CAAC,YAAY,KAAM,CAA6C,CAAC,YAAY,CAAC;QACxF,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa,EAAE,EAAW;IACnD,IAAI,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,CAAO,2BAA2B;IAE1E,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,GAAG,EAAwC,CAAC;YACnD,6BAA6B;YAC7B,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YAC/C,gCAAgC;YAChC,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YAC3C,uCAAuC;YACvC,OAAO,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC;QACvC,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,EAA2C,CAAC;YACtD,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC;QAC7B,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,EAA2C,CAAC;YACtD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;YAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3B,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;YAC5B,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YACxB,6DAA6D;YAC7D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,gFAAgF;QAChF,oFAAoF;QACpF,qFAAqF;QACrF,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,WAAW;YACd,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,223 @@
1
+ import type { SqlType } from "./sql-type.js";
2
+ export interface SchemaSnapshot {
3
+ tables: TableDescriptor[];
4
+ /** Always empty in v0.1; populated by introspect for v0.3 future-proofing. */
5
+ views: ViewDescriptor[];
6
+ /**
7
+ * Dialect-specific metadata captured at introspect time. Used by emit
8
+ * (e.g., SQLite version → choose native ALTER vs recreate-and-copy fallback).
9
+ */
10
+ meta?: SnapshotMeta;
11
+ }
12
+ export interface SnapshotMeta {
13
+ sqliteVersion?: string;
14
+ }
15
+ export interface TableDescriptor {
16
+ name: string;
17
+ /**
18
+ * DB schema this table lives in. Undefined for SQLite (no schema concept).
19
+ * For Postgres, undefined is normalized to "public" at SnapshotMeta boundaries;
20
+ * the diff and emit layers treat undefined === "public" as equivalent.
21
+ */
22
+ schema?: string;
23
+ columns: ColumnDescriptor[];
24
+ indexes: IndexDescriptor[];
25
+ foreignKeys: FkDescriptor[];
26
+ primaryKey: string[];
27
+ }
28
+ export interface ColumnDescriptor {
29
+ name: string;
30
+ sqlType: SqlType;
31
+ nullable: boolean;
32
+ default?: ColumnDefault;
33
+ identity?: "increment" | "uuid";
34
+ }
35
+ export interface ColumnDefault {
36
+ kind: "literal" | "expr";
37
+ value: string;
38
+ }
39
+ export interface IndexDescriptor {
40
+ name: string;
41
+ columns: string[];
42
+ unique: boolean;
43
+ }
44
+ export interface FkDescriptor {
45
+ name: string;
46
+ columns: string[];
47
+ refTable: string;
48
+ refColumns: string[];
49
+ onDelete?: FkAction;
50
+ onUpdate?: FkAction;
51
+ }
52
+ export type FkAction = "cascade" | "set-null" | "restrict" | "no-action";
53
+ export interface ViewDescriptor {
54
+ name: string;
55
+ /** Same semantics as TableDescriptor.schema. */
56
+ schema?: string;
57
+ }
58
+ /**
59
+ * Every variant with a `table: string` (or `table: TableDescriptor`) field also
60
+ * carries an optional `schema?: string`. For the descriptor-bearing variants
61
+ * (create-table, drop-table source is just a name) the schema is redundant with
62
+ * `table.schema` but kept in parallel so the emit layer has a single, uniform
63
+ * place to read schema regardless of variant.
64
+ *
65
+ * For Postgres, undefined is treated as equivalent to "public" by both diff
66
+ * (table identity normalization) and emit (qualified-name suppression).
67
+ * SQLite has no schema concept; the field is always undefined there.
68
+ */
69
+ export type Change = {
70
+ kind: "create-table";
71
+ table: TableDescriptor;
72
+ schema?: string;
73
+ status: ChangeStatus;
74
+ } | {
75
+ kind: "drop-table";
76
+ table: string;
77
+ schema?: string;
78
+ status: ChangeStatus;
79
+ } | {
80
+ kind: "rename-table";
81
+ from: string;
82
+ to: string;
83
+ schema?: string;
84
+ status: ChangeStatus;
85
+ } | {
86
+ kind: "add-column";
87
+ table: string;
88
+ schema?: string;
89
+ column: ColumnDescriptor;
90
+ status: ChangeStatus;
91
+ } | {
92
+ kind: "drop-column";
93
+ table: string;
94
+ schema?: string;
95
+ column: string;
96
+ status: ChangeStatus;
97
+ } | {
98
+ kind: "rename-column";
99
+ table: string;
100
+ schema?: string;
101
+ from: string;
102
+ to: string;
103
+ status: ChangeStatus;
104
+ } | {
105
+ kind: "change-column-type";
106
+ table: string;
107
+ schema?: string;
108
+ column: string;
109
+ from: SqlType;
110
+ to: SqlType;
111
+ status: ChangeStatus;
112
+ } | {
113
+ kind: "change-column-nullable";
114
+ table: string;
115
+ schema?: string;
116
+ column: string;
117
+ from: boolean;
118
+ to: boolean;
119
+ status: ChangeStatus;
120
+ } | {
121
+ kind: "change-column-default";
122
+ table: string;
123
+ schema?: string;
124
+ column: string;
125
+ from?: ColumnDefault;
126
+ to?: ColumnDefault;
127
+ status: ChangeStatus;
128
+ } | {
129
+ kind: "add-index";
130
+ table: string;
131
+ schema?: string;
132
+ index: IndexDescriptor;
133
+ status: ChangeStatus;
134
+ } | {
135
+ kind: "drop-index";
136
+ table: string;
137
+ schema?: string;
138
+ index: string;
139
+ status: ChangeStatus;
140
+ } | {
141
+ kind: "add-fk";
142
+ table: string;
143
+ schema?: string;
144
+ fk: FkDescriptor;
145
+ status: ChangeStatus;
146
+ } | {
147
+ kind: "drop-fk";
148
+ table: string;
149
+ schema?: string;
150
+ fk: string;
151
+ status: ChangeStatus;
152
+ } | {
153
+ kind: "create-view";
154
+ view: ViewDescriptor;
155
+ status: ChangeStatus;
156
+ } | {
157
+ kind: "drop-view";
158
+ view: string;
159
+ status: ChangeStatus;
160
+ } | {
161
+ kind: "replace-view";
162
+ view: ViewDescriptor;
163
+ status: ChangeStatus;
164
+ };
165
+ export type ChangeKind = Change["kind"];
166
+ export interface ChangeStatus {
167
+ state: "allowed" | "blocked";
168
+ blockedReason?: string;
169
+ }
170
+ export interface AllowOptions {
171
+ dropColumn?: boolean;
172
+ dropTable?: boolean;
173
+ /** Narrowing/lossy types only; widening always allowed regardless of this flag. */
174
+ typeChange?: boolean;
175
+ dropIndex?: boolean;
176
+ dropFk?: boolean;
177
+ /** Existing data must satisfy NOT NULL; diff cannot verify this. */
178
+ nullableToNotNull?: boolean;
179
+ }
180
+ export type AmbiguousChange = {
181
+ kind: "possible-column-rename";
182
+ table: string;
183
+ from: {
184
+ name: string;
185
+ sqlType: SqlType;
186
+ };
187
+ to: {
188
+ name: string;
189
+ sqlType: SqlType;
190
+ };
191
+ } | {
192
+ kind: "possible-table-rename";
193
+ from: {
194
+ name: string;
195
+ columnCount: number;
196
+ };
197
+ to: {
198
+ name: string;
199
+ columnCount: number;
200
+ };
201
+ columnOverlap: number;
202
+ };
203
+ export type AmbiguousResolution = "rename" | "drop+add" | "abort";
204
+ export type AmbiguousCallback = (q: AmbiguousChange) => Promise<AmbiguousResolution>;
205
+ export interface DiffResult {
206
+ changes: Change[];
207
+ /** Subset of `changes` where status.state === "blocked"; convenience for CLI error messaging. */
208
+ blocked: Change[];
209
+ }
210
+ export interface EmitResult {
211
+ up: string;
212
+ down: string;
213
+ /**
214
+ * Tables rebuilt via the SQLite recreate-and-copy pattern. Empty for
215
+ * postgres (in-place ALTER). The CLI uses this to pre-drop only the
216
+ * views whose source tables are being recreated — SQLite's RENAME re-
217
+ * parses dependent view definitions and errors if any reference the
218
+ * mid-recreate source table.
219
+ */
220
+ recreatedTables: ReadonlySet<string>;
221
+ }
222
+ export type Dialect = "postgres" | "sqlite";
223
+ //# 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/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { ViewMigrationOpts } from "./view-diff.js";
2
+ export { type ViewMigrationOpts } from "./view-diff.js";
3
+ export declare function emitPostgresViewMigration(opts: ViewMigrationOpts): string;
4
+ //# sourceMappingURL=view-ddl-postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-ddl-postgres.d.ts","sourceRoot":"","sources":["../src/view-ddl-postgres.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAUzE"}
@@ -0,0 +1,13 @@
1
+ export {} from "./view-diff.js";
2
+ export function emitPostgresViewMigration(opts) {
3
+ switch (opts.diffClass) {
4
+ case "no-change": return "";
5
+ case "safe-append":
6
+ case "safe-replace":
7
+ // Replace CREATE VIEW with CREATE OR REPLACE VIEW.
8
+ return opts.createSql.replace(/^CREATE VIEW\b/i, "CREATE OR REPLACE VIEW");
9
+ case "breaking":
10
+ return `DROP VIEW IF EXISTS ${opts.viewName} CASCADE;\n${opts.createSql}`;
11
+ }
12
+ }
13
+ //# sourceMappingURL=view-ddl-postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-ddl-postgres.js","sourceRoot":"","sources":["../src/view-ddl-postgres.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,MAAM,gBAAgB,CAAC;AAExD,MAAM,UAAU,yBAAyB,CAAC,IAAuB;IAC/D,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,KAAK,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;QAC5B,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc;YACjB,mDAAmD;YACnD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,wBAAwB,CAAC,CAAC;QAC7E,KAAK,UAAU;YACb,OAAO,uBAAuB,IAAI,CAAC,QAAQ,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ViewMigrationOpts } from "./view-diff.js";
2
+ export declare function emitSqliteViewMigration(opts: ViewMigrationOpts): string;
3
+ //# sourceMappingURL=view-ddl-sqlite.d.ts.map