@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,302 @@
1
+ // Stage ordering similar to PG; recreate-and-copy bundles get inserted
2
+ // at their first triggering change's position in Task 23.
3
+ const STAGE_ORDER = {
4
+ "create-table": 1,
5
+ "add-column": 2, "drop-column": 2,
6
+ "change-column-type": 2, "change-column-nullable": 2, "change-column-default": 2,
7
+ "rename-column": 3, "rename-table": 3,
8
+ "add-index": 4, "drop-index": 4,
9
+ "add-fk": 5, "drop-fk": 5,
10
+ "drop-table": 6,
11
+ "create-view": 99, "drop-view": 99, "replace-view": 99,
12
+ };
13
+ const RECREATE_TRIGGERING_KINDS = new Set([
14
+ "change-column-type", "change-column-nullable", "change-column-default",
15
+ "add-fk", "drop-fk",
16
+ ]);
17
+ export function renderSqlite(changes, expectedSchema, actualMeta) {
18
+ const version = parseVersion(actualMeta?.sqliteVersion);
19
+ const SUPPORTS_DROP = compareVersions(version, [3, 35, 0]) >= 0;
20
+ const SUPPORTS_RENAME = compareVersions(version, [3, 25, 0]) >= 0;
21
+ // Decide per-change whether it triggers recreate-and-copy.
22
+ const triggersRecreate = (c) => {
23
+ if (RECREATE_TRIGGERING_KINDS.has(c.kind))
24
+ return true;
25
+ if (c.kind === "drop-column" && !SUPPORTS_DROP)
26
+ return true;
27
+ if (c.kind === "rename-column" && !SUPPORTS_RENAME)
28
+ return true;
29
+ return false;
30
+ };
31
+ const sorted = [...changes].sort((a, b) => STAGE_ORDER[a.kind] - STAGE_ORDER[b.kind]);
32
+ // Tables being newly created in this batch — FKs are already included in CREATE TABLE DDL,
33
+ // so add-fk / drop-fk against brand-new tables must NOT trigger recreate-and-copy.
34
+ const newlyCreatedTables = new Set();
35
+ for (const c of sorted) {
36
+ if (c.kind === "create-table")
37
+ newlyCreatedTables.add(c.table.name);
38
+ }
39
+ // Partition: which tables need a recreate?
40
+ const recreateTables = new Set();
41
+ for (const c of sorted) {
42
+ if (triggersRecreate(c)) {
43
+ const t = changeTable(c);
44
+ if (t && !newlyCreatedTables.has(t))
45
+ recreateTables.add(t);
46
+ }
47
+ }
48
+ if (recreateTables.size > 0 && !expectedSchema) {
49
+ throw new Error("expectedSchema required for SQLite recreate-and-copy (pass via emit() options)");
50
+ }
51
+ // For each recreate table, gather every change targeting it; render the recipe once.
52
+ // Other changes pass through native rendering.
53
+ const upStmts = [];
54
+ const downStmts = [];
55
+ const handledRecreate = new Set();
56
+ for (const c of sorted) {
57
+ const t = changeTable(c);
58
+ if (t && recreateTables.has(t)) {
59
+ if (handledRecreate.has(t))
60
+ continue; // already bundled at first triggering change
61
+ const tableChanges = sorted.filter((x) => changeTable(x) === t);
62
+ const newTable = expectedSchema.tables.find((tt) => tt.name === t);
63
+ if (!newTable)
64
+ throw new Error(`expectedSchema missing table "${t}" needed for recreate`);
65
+ const { up, down } = renderRecreate(t, tableChanges, newTable);
66
+ upStmts.push(up);
67
+ downStmts.push(down);
68
+ handledRecreate.add(t);
69
+ continue;
70
+ }
71
+ // add-fk / drop-fk targeting a newly-created table: FK is already in CREATE TABLE DDL — skip.
72
+ if ((c.kind === "add-fk" || c.kind === "drop-fk") && t && newlyCreatedTables.has(t)) {
73
+ continue;
74
+ }
75
+ upStmts.push(renderUpNative(c));
76
+ downStmts.push(renderDownNative(c));
77
+ }
78
+ return {
79
+ up: upStmts.join("\n\n"),
80
+ down: [...downStmts].reverse().join("\n\n"),
81
+ recreatedTables: recreateTables,
82
+ };
83
+ }
84
+ function changeTable(c) {
85
+ switch (c.kind) {
86
+ case "create-table": return c.table.name;
87
+ case "drop-table": return c.table;
88
+ case "rename-table": return c.from; // applies to source table
89
+ case "add-column":
90
+ case "drop-column":
91
+ case "rename-column":
92
+ case "change-column-type":
93
+ case "change-column-nullable":
94
+ case "change-column-default":
95
+ case "add-index":
96
+ case "drop-index":
97
+ case "add-fk":
98
+ case "drop-fk":
99
+ return c.table;
100
+ default:
101
+ return undefined;
102
+ }
103
+ }
104
+ function renderRecreate(table, tableChanges, newTable) {
105
+ // Build the column-name remapping: old_name → new_name (for renames).
106
+ const renames = new Map();
107
+ for (const c of tableChanges) {
108
+ if (c.kind === "rename-column")
109
+ renames.set(c.from, c.to);
110
+ }
111
+ // Columns added in this migration don't exist in old table — exclude from SELECT.
112
+ const addedNames = new Set();
113
+ for (const c of tableChanges) {
114
+ if (c.kind === "add-column")
115
+ addedNames.add(c.column.name);
116
+ }
117
+ // Reverse map: new_name → old_name (for SELECT source column lookup).
118
+ const renamesReverse = new Map();
119
+ for (const [from, to] of renames)
120
+ renamesReverse.set(to, from);
121
+ // carryColumns = newTable columns NOT being newly added (they exist in the old table).
122
+ const carryColumns = newTable.columns.filter((c) => !addedNames.has(c.name));
123
+ const insertCols = carryColumns.map((c) => c.name);
124
+ const selectCols = carryColumns.map((c) => renamesReverse.get(c.name) ?? c.name);
125
+ // Build the new-table CREATE using temp name.
126
+ const tmp = `__new_${table}`;
127
+ const tmpDescriptor = { ...newTable, name: tmp };
128
+ const createNew = renderCreateTable(tmpDescriptor);
129
+ const indexes = newTable.indexes; // recreated post-rename
130
+ const lines = [];
131
+ lines.push("PRAGMA foreign_keys = OFF;");
132
+ lines.push("BEGIN TRANSACTION;");
133
+ lines.push("");
134
+ lines.push(createNew);
135
+ if (insertCols.length > 0) {
136
+ lines.push(`INSERT INTO ${quote(tmp)} (${insertCols.map(quote).join(", ")}) ` +
137
+ `SELECT ${selectCols.map(quote).join(", ")} FROM ${quote(table)};`);
138
+ }
139
+ lines.push(`DROP TABLE ${quote(table)};`);
140
+ lines.push(`ALTER TABLE ${quote(tmp)} RENAME TO ${quote(table)};`);
141
+ for (const ix of indexes)
142
+ lines.push(renderCreateIndex(table, ix));
143
+ lines.push("");
144
+ lines.push("COMMIT;");
145
+ lines.push("PRAGMA foreign_keys = ON;");
146
+ lines.push("PRAGMA foreign_key_check;");
147
+ // Down: best-effort. Without the actual snapshot we can't perfectly restore,
148
+ // so emit a WARNING comment block.
149
+ const down = [
150
+ `-- WARNING: SQLite recreate-and-copy down migration is best-effort.`,
151
+ `-- Reverse the column type/nullable/default changes by hand if needed.`,
152
+ `-- Dropped data cannot be restored.`,
153
+ ].join("\n");
154
+ return { up: lines.join("\n"), down };
155
+ }
156
+ function renderUpNative(c) {
157
+ switch (c.kind) {
158
+ case "create-table": return renderCreateTable(c.table);
159
+ case "drop-table": return `DROP TABLE ${quote(c.table)};`;
160
+ case "rename-table": return `ALTER TABLE ${quote(c.from)} RENAME TO ${quote(c.to)};`;
161
+ case "add-column": return `ALTER TABLE ${quote(c.table)} ADD COLUMN ${renderColumnInline(c.column)};`;
162
+ case "drop-column": return `ALTER TABLE ${quote(c.table)} DROP COLUMN ${quote(c.column)};`;
163
+ case "rename-column": return `ALTER TABLE ${quote(c.table)} RENAME COLUMN ${quote(c.from)} TO ${quote(c.to)};`;
164
+ case "add-index": return renderCreateIndex(c.table, c.index);
165
+ case "drop-index": return `DROP INDEX ${quote(c.index)};`;
166
+ case "change-column-type":
167
+ case "change-column-nullable":
168
+ case "change-column-default":
169
+ case "add-fk":
170
+ case "drop-fk":
171
+ // These are handled by renderRecreate before reaching renderUpNative.
172
+ throw new Error(`renderUpNative: ${c.kind} should have been handled by recreate bundler`);
173
+ case "create-view":
174
+ case "drop-view":
175
+ case "replace-view":
176
+ throw new Error(`unexpected view-kind in renderSqlite: ${c.kind}`);
177
+ }
178
+ }
179
+ function renderDownNative(c) {
180
+ switch (c.kind) {
181
+ case "create-table": return `DROP TABLE ${quote(c.table.name)};`;
182
+ case "drop-table": return `-- WARNING: down migration cannot restore data\n-- TODO: restore table "${c.table}" structure manually`;
183
+ case "rename-table": return `ALTER TABLE ${quote(c.to)} RENAME TO ${quote(c.from)};`;
184
+ case "add-column": return `ALTER TABLE ${quote(c.table)} DROP COLUMN ${quote(c.column.name)};`;
185
+ case "drop-column": return `-- WARNING: down migration cannot restore data\n-- TODO: re-add dropped column "${c.column}" manually`;
186
+ case "rename-column": return `ALTER TABLE ${quote(c.table)} RENAME COLUMN ${quote(c.to)} TO ${quote(c.from)};`;
187
+ case "add-index": return `DROP INDEX ${quote(c.index.name)};`;
188
+ case "drop-index": return `-- WARNING: down migration cannot restore the original index definition`;
189
+ case "change-column-type":
190
+ case "change-column-nullable":
191
+ case "change-column-default":
192
+ case "add-fk":
193
+ case "drop-fk":
194
+ // These are handled by renderRecreate before reaching renderDownNative.
195
+ throw new Error(`renderDownNative: ${c.kind} should have been handled by recreate bundler`);
196
+ case "create-view":
197
+ case "drop-view":
198
+ case "replace-view":
199
+ throw new Error(`unexpected view-kind in renderSqlite: ${c.kind}`);
200
+ }
201
+ }
202
+ function renderCreateTable(t) {
203
+ const compositePk = t.primaryKey.length > 1;
204
+ const colDefs = t.columns.map((c) => {
205
+ const isSinglePk = !compositePk && t.primaryKey[0] === c.name;
206
+ return ` ${renderColumnInline(c, isSinglePk)}`;
207
+ });
208
+ if (compositePk) {
209
+ colDefs.push(` PRIMARY KEY (${t.primaryKey.map(quote).join(", ")})`);
210
+ }
211
+ for (const fk of t.foreignKeys) {
212
+ const cols = fk.columns.map(quote).join(", ");
213
+ const refCols = fk.refColumns.map(quote).join(", ");
214
+ let clause = ` FOREIGN KEY (${cols}) REFERENCES ${quote(fk.refTable)} (${refCols})`;
215
+ if (fk.onDelete)
216
+ clause += ` ON DELETE ${renderFkAction(fk.onDelete)}`;
217
+ if (fk.onUpdate)
218
+ clause += ` ON UPDATE ${renderFkAction(fk.onUpdate)}`;
219
+ colDefs.push(clause);
220
+ }
221
+ return `CREATE TABLE ${quote(t.name)} (\n${colDefs.join(",\n")}\n);`;
222
+ }
223
+ function renderFkAction(action) {
224
+ switch (action) {
225
+ case "cascade": return "CASCADE";
226
+ case "set-null": return "SET NULL";
227
+ case "restrict": return "RESTRICT";
228
+ case "no-action": return "NO ACTION";
229
+ }
230
+ }
231
+ function renderColumnInline(c, isSinglePk = false) {
232
+ let s = `${quote(c.name)} ${sqliteType(c.sqlType, c.identity)}`;
233
+ if (isSinglePk)
234
+ s += " PRIMARY KEY";
235
+ if (c.identity === "increment" && isSinglePk)
236
+ s += " AUTOINCREMENT";
237
+ s += c.nullable ? "" : " NOT NULL";
238
+ if (c.default !== undefined) {
239
+ s += ` DEFAULT ${renderDefault(c.default)}`;
240
+ }
241
+ else if (c.identity === "uuid") {
242
+ // SQLite has no native uuid(); approximate via lower(hex(randomblob(16))).
243
+ s += " DEFAULT (lower(hex(randomblob(16))))";
244
+ }
245
+ return s;
246
+ }
247
+ function sqliteType(t, identity) {
248
+ if (identity === "increment")
249
+ return "INTEGER";
250
+ if (identity === "uuid")
251
+ return "TEXT";
252
+ switch (t.kind) {
253
+ case "text": return t.maxLength !== undefined ? `VARCHAR(${t.maxLength})` : "TEXT";
254
+ // Use INTEGER for 64-bit and INT for 32-bit — SQLite preserves the declared type
255
+ // in pragma_table_info, enabling round-trip fidelity (see introspect/sqlite.ts).
256
+ case "integer": return t.bits === 64 ? "INTEGER" : "INT";
257
+ case "real": return "REAL";
258
+ case "numeric": {
259
+ if (t.precision !== undefined && t.scale !== undefined)
260
+ return `NUMERIC(${t.precision},${t.scale})`;
261
+ return "NUMERIC";
262
+ }
263
+ case "boolean": return "BOOLEAN"; // SQLite stores as 0/1 but preserves declared type for round-trip
264
+ case "timestamp": return "TIMESTAMP";
265
+ case "date": return "DATE";
266
+ case "json": return "TEXT"; // SQLite has JSON1 but stores as text
267
+ case "blob": return "BLOB";
268
+ case "uuid": return "TEXT";
269
+ }
270
+ }
271
+ function renderDefault(d) {
272
+ if (d.kind === "expr")
273
+ return d.value;
274
+ return `'${d.value.replace(/'/g, "''")}'`;
275
+ }
276
+ function renderCreateIndex(table, ix) {
277
+ const u = ix.unique ? "UNIQUE " : "";
278
+ return `CREATE ${u}INDEX ${quote(ix.name)} ON ${quote(table)} (${ix.columns.map(quote).join(", ")});`;
279
+ }
280
+ function quote(ident) {
281
+ if (ident.includes('"'))
282
+ throw new Error(`unsafe identifier: ${ident}`);
283
+ return `"${ident}"`;
284
+ }
285
+ function parseVersion(v) {
286
+ if (!v)
287
+ return [99, 0, 0]; // assume modern when unknown
288
+ const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
289
+ if (!m)
290
+ return [99, 0, 0];
291
+ return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];
292
+ }
293
+ function compareVersions(a, b) {
294
+ for (let i = 0; i < 3; i++) {
295
+ if (a[i] < b[i])
296
+ return -1;
297
+ if (a[i] > b[i])
298
+ return 1;
299
+ }
300
+ return 0;
301
+ }
302
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/emit/sqlite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Change } from "./types.js";
2
+ export declare class BlockedChangesError extends Error {
3
+ readonly name = "BlockedChangesError";
4
+ readonly blocked: Change[];
5
+ readonly enableHints: string[];
6
+ constructor(blocked: Change[]);
7
+ }
8
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,YAAY,CAAC;AA0CrD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAkB,IAAI,yBAAyB;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE;CAU9B"}
package/dist/errors.js ADDED
@@ -0,0 +1,54 @@
1
+ const ENABLE_FLAG_BY_KIND = {
2
+ "drop-column": "allow.dropColumn",
3
+ "drop-table": "allow.dropTable",
4
+ "change-column-type": "allow.typeChange",
5
+ "change-column-nullable": "allow.nullableToNotNull",
6
+ "drop-index": "allow.dropIndex",
7
+ "drop-fk": "allow.dropFk",
8
+ };
9
+ function changeLocator(c) {
10
+ switch (c.kind) {
11
+ case "drop-column":
12
+ case "rename-column":
13
+ case "change-column-type":
14
+ case "change-column-nullable":
15
+ case "change-column-default":
16
+ return `${c.table}.${"column" in c ? c.column : c.from}`;
17
+ case "add-column":
18
+ return `${c.table}.${c.column.name}`;
19
+ case "drop-table":
20
+ case "rename-table":
21
+ return c.kind === "drop-table" ? c.table : `${c.from}→${c.to}`;
22
+ case "create-table":
23
+ return c.table.name;
24
+ case "add-index":
25
+ return `${c.table}.${c.index.name}`;
26
+ case "drop-index":
27
+ return `${c.table}.${c.index}`;
28
+ case "add-fk":
29
+ return `${c.table}.${c.fk.name}`;
30
+ case "drop-fk":
31
+ return `${c.table}.${c.fk}`;
32
+ case "create-view":
33
+ case "replace-view":
34
+ return c.view.name;
35
+ case "drop-view":
36
+ return c.view;
37
+ }
38
+ }
39
+ export class BlockedChangesError extends Error {
40
+ name = "BlockedChangesError";
41
+ blocked;
42
+ enableHints;
43
+ constructor(blocked) {
44
+ const hints = blocked.map((c) => {
45
+ const flag = ENABLE_FLAG_BY_KIND[c.kind] ?? "(no flag enables this)";
46
+ return `${c.kind} on ${changeLocator(c)}: pass ${flag}`;
47
+ });
48
+ const msg = `${blocked.length} blocked change(s):\n - ${hints.join("\n - ")}`;
49
+ super(msg);
50
+ this.blocked = blocked;
51
+ this.enableHints = hints;
52
+ }
53
+ }
54
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAwC;IAC/D,aAAa,EAAE,kBAAkB;IACjC,YAAY,EAAE,iBAAiB;IAC/B,oBAAoB,EAAE,kBAAkB;IACxC,wBAAwB,EAAE,yBAAyB;IACnD,YAAY,EAAE,iBAAiB;IAC/B,SAAS,EAAE,cAAc;CAC1B,CAAC;AAEF,SAAS,aAAa,CAAC,CAAS;IAC9B,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,aAAa,CAAC;QACnB,KAAK,eAAe,CAAC;QACrB,KAAK,oBAAoB,CAAC;QAC1B,KAAK,wBAAwB,CAAC;QAC9B,KAAK,uBAAuB;YAC1B,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,KAAK,YAAY;YACf,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACvC,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc;YACjB,OAAO,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;QACjE,KAAK,cAAc;YACjB,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QACtB,KAAK,WAAW;YACd,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,KAAK,YAAY;YACf,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACjC,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACnC,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;QAC9B,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc;YACjB,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACrB,KAAK,WAAW;YACd,OAAO,CAAC,CAAC,IAAI,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1B,IAAI,GAAG,qBAAqB,CAAC;IACtC,OAAO,CAAW;IAClB,WAAW,CAAW;IAE/B,YAAY,OAAiB;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9B,MAAM,IAAI,GAAG,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC;YACrE,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,aAAa,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,4BAA4B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChF,KAAK,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import type { MetaData } from "@metaobjectsdev/metadata";
2
+ import type { SchemaSnapshot } from "./types.js";
3
+ export interface BuildExpectedSchemaOptions {
4
+ /**
5
+ * If set, normalize column SqlTypes for the target dialect so the diff
6
+ * matches what introspection will see. For sqlite this collapses
7
+ * boolean → integer{64} and timestamp/date/time → text, since sqlite
8
+ * has no native boolean/timestamp affinity and Drizzle's
9
+ * `integer(..., {mode:"boolean"})` / `text("ts")` patterns produce
10
+ * INTEGER / TEXT in the actual DB.
11
+ */
12
+ dialect?: "sqlite" | "postgres";
13
+ }
14
+ export declare function buildExpectedSchema(root: MetaData, opts?: BuildExpectedSchemaOptions): SchemaSnapshot;
15
+ //# sourceMappingURL=expected-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expected-schema.d.ts","sourceRoot":"","sources":["../src/expected-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAA+C,MAAM,0BAA0B,CAAC;AA+BtG,OAAO,KAAK,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,0BAA0B;IACzC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;CACjC;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE,0BAA0B,GAChC,cAAc,CAmDhB"}
@@ -0,0 +1,243 @@
1
+ import { TYPE_OBJECT, TYPE_SOURCE, TYPE_VALIDATOR, SOURCE_SUBTYPE_DB_VIEW, VALIDATOR_SUBTYPE_REQUIRED, IDENTITY_ATTR_FIELDS, IDENTITY_ATTR_GENERATION, IDENTITY_ATTR_UNIQUE, FIELD_ATTR_REQUIRED, FIELD_ATTR_DEFAULT, FIELD_ATTR_UNIQUE, FIELD_SUBTYPE_STRING, FIELD_SUBTYPE_INT, FIELD_SUBTYPE_LONG, FIELD_SUBTYPE_SHORT, FIELD_SUBTYPE_BYTE, FIELD_SUBTYPE_DOUBLE, FIELD_SUBTYPE_FLOAT, FIELD_SUBTYPE_DECIMAL, FIELD_SUBTYPE_BOOLEAN, FIELD_SUBTYPE_CURRENCY, FIELD_SUBTYPE_DATE, FIELD_SUBTYPE_TIME, FIELD_SUBTYPE_TIMESTAMP, FIELD_SUBTYPE_OBJECT, FIELD_SUBTYPE_CLASS, resolveTableName, resolveColumnName, resolveTableSchema, } from "@metaobjectsdev/metadata";
2
+ export function buildExpectedSchema(root, opts) {
3
+ // Pass 1: collect entities + their resolved table names.
4
+ // Skip:
5
+ // - abstract objects (e.g., BaseEntity)
6
+ // - value objects (no table backing)
7
+ // - projections (source.dbView — handled by the view-diff pipeline, not table diff)
8
+ const entities = [];
9
+ for (const child of root.ownChildren()) {
10
+ if (child.type !== TYPE_OBJECT)
11
+ continue;
12
+ if (child.isAbstract)
13
+ continue;
14
+ if (child.subType === "value")
15
+ continue;
16
+ const hasViewSource = child.ownChildren().some((c) => c.type === TYPE_SOURCE && c.subType === SOURCE_SUBTYPE_DB_VIEW);
17
+ if (hasViewSource)
18
+ continue;
19
+ entities.push({ entity: child, tableName: resolveTableName(child) });
20
+ }
21
+ const entityToTable = new Map(entities.map((e) => [e.entity.name, e.tableName]));
22
+ const resolveTargetTable = (entityName) => entityToTable.get(entityName);
23
+ // Pass 2: build full descriptors with FK resolution.
24
+ // Schema is resolved here (not stored in Pass 1) to avoid exactOptionalPropertyTypes
25
+ // issues with `string | undefined` vs `schema?: string`.
26
+ const tables = entities.map(({ entity, tableName }) => {
27
+ const t = buildTable(entity, tableName, resolveTargetTable, root);
28
+ const schema = resolveTableSchema(entity);
29
+ if (schema !== undefined)
30
+ t.schema = schema;
31
+ return t;
32
+ });
33
+ // Pass 3: dialect-specific SqlType normalization.
34
+ if (opts?.dialect === "sqlite") {
35
+ for (const table of tables) {
36
+ for (const col of table.columns) {
37
+ col.sqlType = normalizeForSqlite(col.sqlType);
38
+ }
39
+ }
40
+ }
41
+ // Dialect validation: SQLite has no schema concept; reject any non-default @schema.
42
+ if (opts?.dialect === "sqlite") {
43
+ for (const table of tables) {
44
+ if (table.schema !== undefined) {
45
+ throw new Error(`sqlite does not support DB schemas; entity-table "${table.name}" declares @schema "${table.schema}"`);
46
+ }
47
+ }
48
+ }
49
+ return { tables, views: [] };
50
+ }
51
+ /**
52
+ * Normalize a canonical SqlType for what sqlite introspection will actually see.
53
+ * sqlite stores all integers (including booleans) as INTEGER, and uses TEXT for
54
+ * date/time/timestamp affinities by default.
55
+ */
56
+ function normalizeForSqlite(sqlType) {
57
+ switch (sqlType.kind) {
58
+ case "boolean":
59
+ return { kind: "integer", bits: 64 };
60
+ case "timestamp":
61
+ case "date":
62
+ return { kind: "text" };
63
+ case "integer":
64
+ // SQLite stores every INTEGER as a 64-bit value and Drizzle's int() emits
65
+ // plain "INTEGER" regardless of source bit-width. Collapse 32 → 64 so the
66
+ // expected snapshot matches what introspection sees.
67
+ return { kind: "integer", bits: 64 };
68
+ default:
69
+ return sqlType;
70
+ }
71
+ }
72
+ function buildTable(entity, tableName, resolveTargetTable, root) {
73
+ // Use effective accessors so inherited fields/identities (from `extends:` /
74
+ // abstract bases like BaseEntity) are included.
75
+ const pkIdentity = entity.primaryIdentity();
76
+ const pkJsNames = pkIdentity ? readIdentityFields(pkIdentity) : [];
77
+ const pkGeneration = pkIdentity
78
+ ? pkIdentity.ownAttr(IDENTITY_ATTR_GENERATION)
79
+ : undefined;
80
+ const primaryKey = pkJsNames.map((jsName) => {
81
+ const field = findField(entity, jsName);
82
+ return field ? resolveColumnName(field) : toSnake(jsName);
83
+ });
84
+ const columns = [];
85
+ for (const field of entity.fields()) {
86
+ const isPk = pkJsNames.includes(field.name);
87
+ columns.push(buildColumn(field, isPk, isPk ? pkGeneration : undefined));
88
+ }
89
+ return {
90
+ name: tableName,
91
+ columns,
92
+ indexes: buildSecondaryIndexes(entity, tableName),
93
+ foreignKeys: buildForeignKeys(entity, tableName, resolveTargetTable, root),
94
+ primaryKey,
95
+ };
96
+ }
97
+ function buildSecondaryIndexes(entity, tableName) {
98
+ const indexes = [];
99
+ // (a) Implicit unique indexes from @unique fields. Drizzle auto-creates these
100
+ // on the DB side using the convention `<table>_<column>_unique` whenever a
101
+ // column has `.unique()`. We mirror them in the expected schema so the diff
102
+ // doesn't see them as drop-only on the actual side.
103
+ for (const field of entity.fields()) {
104
+ if (field.ownAttr(FIELD_ATTR_UNIQUE) !== true)
105
+ continue;
106
+ const colName = resolveColumnName(field);
107
+ indexes.push({
108
+ name: `${tableName}_${colName}_unique`,
109
+ columns: [colName],
110
+ unique: true,
111
+ });
112
+ }
113
+ // (b) Explicit secondary identities — unique-by-default, opt out with @unique: false.
114
+ // Drizzle emits the index using the identity's @name attr directly (no table
115
+ // prefix), so the expected name must match.
116
+ for (const identity of entity.secondaryIdentities()) {
117
+ const fieldNames = readIdentityFields(identity);
118
+ if (fieldNames.length === 0)
119
+ continue;
120
+ const cols = fieldNames.map((jsName) => {
121
+ const field = findField(entity, jsName);
122
+ return field ? resolveColumnName(field) : toSnake(jsName);
123
+ });
124
+ const uniqueAttr = identity.ownAttr(IDENTITY_ATTR_UNIQUE);
125
+ indexes.push({
126
+ name: identity.name,
127
+ columns: cols,
128
+ unique: uniqueAttr !== false,
129
+ });
130
+ }
131
+ return indexes;
132
+ }
133
+ function buildForeignKeys(entity, tableName, resolveTargetTable, root) {
134
+ const fks = [];
135
+ for (const refChild of entity.referenceIdentities()) {
136
+ // @enforce: false → logical-only reference; not a physical FK constraint.
137
+ if (!refChild.enforce)
138
+ continue;
139
+ const targetEntity = refChild.targetEntity;
140
+ if (targetEntity === undefined)
141
+ continue;
142
+ const refTable = resolveTargetTable(targetEntity);
143
+ if (!refTable)
144
+ continue;
145
+ const fkFieldJsNames = readIdentityFields(refChild);
146
+ if (fkFieldJsNames.length === 0)
147
+ continue;
148
+ const fkCols = fkFieldJsNames.map((jsName) => {
149
+ const fkField = findField(entity, jsName);
150
+ return fkField ? resolveColumnName(fkField) : toSnake(jsName);
151
+ });
152
+ // Target columns: prefer explicit multi-field dotted form, else delegate
153
+ // to MetaReferenceIdentity.resolvedTargetPkField (single field → target's
154
+ // primary identity → "id" fallback).
155
+ const explicitTargetFields = refChild.targetFields;
156
+ const refColumns = explicitTargetFields.length > 1
157
+ ? explicitTargetFields.map(toSnake)
158
+ : [toSnake(refChild.resolvedTargetPkField(root) ?? "id")];
159
+ fks.push({
160
+ name: `${tableName}_${fkCols[0]}_fk`,
161
+ columns: fkCols,
162
+ refTable,
163
+ refColumns,
164
+ });
165
+ }
166
+ return fks;
167
+ }
168
+ const EXPR_DEFAULT_PATTERNS = [
169
+ /^current_timestamp$/i,
170
+ /^now\(\)$/i,
171
+ /^current_date$/i,
172
+ /^current_time$/i,
173
+ /\(\)/, // anything function-like
174
+ ];
175
+ function buildColumn(field, isPk, pkGeneration) {
176
+ const requiredAttr = field.ownAttr(FIELD_ATTR_REQUIRED);
177
+ // BaseEntity-style metadata expresses required via a validator.required child;
178
+ // direct attr form is the alternative. Either signals NOT NULL.
179
+ const hasRequiredValidator = field.ownChildren().some((c) => c.type === TYPE_VALIDATOR && c.subType === VALIDATOR_SUBTYPE_REQUIRED);
180
+ const isRequired = requiredAttr === true || requiredAttr === "true" || hasRequiredValidator;
181
+ const defaultRaw = field.ownAttr(FIELD_ATTR_DEFAULT);
182
+ const col = {
183
+ name: resolveColumnName(field),
184
+ sqlType: subtypeToSqlType(field.subType),
185
+ nullable: !isPk && !isRequired,
186
+ };
187
+ if (typeof defaultRaw === "string" && defaultRaw.length > 0) {
188
+ const isExpr = EXPR_DEFAULT_PATTERNS.some((re) => re.test(defaultRaw));
189
+ col.default = { kind: isExpr ? "expr" : "literal", value: defaultRaw };
190
+ }
191
+ else if (typeof defaultRaw === "boolean" || typeof defaultRaw === "number") {
192
+ col.default = { kind: "literal", value: String(defaultRaw) };
193
+ }
194
+ if (isPk && (pkGeneration === "increment" || pkGeneration === "uuid")) {
195
+ col.identity = pkGeneration;
196
+ }
197
+ return col;
198
+ }
199
+ function subtypeToSqlType(subType) {
200
+ switch (subType) {
201
+ case FIELD_SUBTYPE_STRING: return { kind: "text" };
202
+ case FIELD_SUBTYPE_INT:
203
+ case FIELD_SUBTYPE_SHORT:
204
+ case FIELD_SUBTYPE_BYTE: return { kind: "integer", bits: 32 };
205
+ case FIELD_SUBTYPE_LONG:
206
+ case FIELD_SUBTYPE_CURRENCY: return { kind: "integer", bits: 64 };
207
+ case FIELD_SUBTYPE_DOUBLE:
208
+ case FIELD_SUBTYPE_FLOAT: return { kind: "real" };
209
+ case FIELD_SUBTYPE_DECIMAL: return { kind: "numeric" };
210
+ case FIELD_SUBTYPE_BOOLEAN: return { kind: "boolean" };
211
+ case FIELD_SUBTYPE_DATE: return { kind: "date" };
212
+ case FIELD_SUBTYPE_TIME: return { kind: "text" }; // SQL TIME rare; coerce to text
213
+ case FIELD_SUBTYPE_TIMESTAMP: return { kind: "timestamp", withTimezone: false };
214
+ case FIELD_SUBTYPE_OBJECT:
215
+ case FIELD_SUBTYPE_CLASS: return { kind: "json" };
216
+ default: return { kind: "text" }; // unknown → text fallback
217
+ }
218
+ }
219
+ function readIdentityFields(identity) {
220
+ const raw = identity.ownAttr(IDENTITY_ATTR_FIELDS);
221
+ if (Array.isArray(raw)) {
222
+ return raw.map(String).filter((s) => s.length > 0);
223
+ }
224
+ if (typeof raw === "string") {
225
+ // Fallback: comma-separated string form (defensive; canonical form is array)
226
+ return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
227
+ }
228
+ return [];
229
+ }
230
+ function findField(entity, name) {
231
+ for (const field of entity.fields()) {
232
+ if (field.name === name)
233
+ return field;
234
+ }
235
+ return undefined;
236
+ }
237
+ function toSnake(s) {
238
+ return s
239
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
240
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
241
+ .toLowerCase();
242
+ }
243
+ //# sourceMappingURL=expected-schema.js.map