flint-orm 0.4.1 → 0.4.3

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 (48) hide show
  1. package/dist/config.d.ts +30 -0
  2. package/dist/drivers/better-sqlite3.d.ts +38 -0
  3. package/dist/drivers/bun-sqlite.d.ts +38 -0
  4. package/dist/drivers/libsql-web.d.ts +44 -0
  5. package/dist/drivers/libsql.d.ts +40 -0
  6. package/dist/drivers/turso-sync.d.ts +44 -0
  7. package/dist/drivers/turso.d.ts +38 -0
  8. package/dist/entries/better-sqlite3.d.ts +1 -0
  9. package/dist/entries/bun-sqlite.d.ts +1 -0
  10. package/dist/entries/config.d.ts +1 -0
  11. package/dist/entries/expressions.d.ts +5 -0
  12. package/dist/entries/libsql-web.d.ts +2 -0
  13. package/dist/entries/libsql.d.ts +2 -0
  14. package/dist/entries/table.d.ts +4 -0
  15. package/dist/entries/turso-sync.d.ts +2 -0
  16. package/dist/entries/turso.d.ts +1 -0
  17. package/dist/errors.d.ts +13 -0
  18. package/dist/executor.d.ts +16 -0
  19. package/dist/flint.d.ts +120 -0
  20. package/dist/index.d.ts +11 -0
  21. package/dist/migration/diff.d.ts +15 -0
  22. package/dist/migration/generate.d.ts +18 -0
  23. package/dist/migration/index.d.ts +11 -0
  24. package/dist/migration/migrate.d.ts +52 -0
  25. package/dist/migration/migration.d.ts +5 -0
  26. package/dist/migration/operations.d.ts +14 -0
  27. package/dist/migration/serialize.d.ts +3 -0
  28. package/dist/migration/sql.d.ts +2 -0
  29. package/dist/migration/types.d.ts +98 -0
  30. package/dist/query/aggregates.d.ts +47 -0
  31. package/dist/query/builder.d.ts +257 -0
  32. package/dist/query/conditions.d.ts +176 -0
  33. package/dist/schema/columns.d.ts +146 -0
  34. package/dist/schema/table.d.ts +74 -0
  35. package/dist/sqlite/introspect.d.ts +19 -0
  36. package/dist/src/cli.js +13818 -0
  37. package/dist/src/entries/better-sqlite3.js +2050 -0
  38. package/dist/src/entries/bun-sqlite.js +1284 -0
  39. package/dist/src/entries/config.js +55 -0
  40. package/dist/src/entries/expressions.js +1252 -0
  41. package/dist/src/entries/libsql-web.js +6065 -0
  42. package/dist/src/entries/libsql.js +7208 -0
  43. package/dist/src/entries/table.js +403 -0
  44. package/dist/src/entries/turso-sync.js +3504 -0
  45. package/dist/src/entries/turso.js +2379 -0
  46. package/dist/{index.js → src/index.js} +86 -22
  47. package/dist/src/migration/index.js +1066 -0
  48. package/package.json +1 -1
@@ -0,0 +1,1066 @@
1
+ // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
+ var __require = import.meta.require;
48
+
49
+ // src/migration/serialize.ts
50
+ var exports_serialize = {};
51
+ __export(exports_serialize, {
52
+ serializeSchema: () => serializeSchema
53
+ });
54
+ function serializeColumn(col) {
55
+ const internal = col.__internal;
56
+ const result = {
57
+ name: col.name,
58
+ sqlType: internal.sqlType,
59
+ isPrimaryKey: internal.isPrimaryKey,
60
+ isNotNull: internal.isNotNull,
61
+ isUnique: internal.isUnique,
62
+ hasDefault: internal.hasDefault,
63
+ defaultValue: internal.defaultValue
64
+ };
65
+ if (internal.referencesTable && internal.referencesColumn) {
66
+ result.referencesTable = internal.referencesTable;
67
+ result.referencesColumn = internal.referencesColumn;
68
+ if (internal.onDelete && internal.onDelete !== "no action")
69
+ result.onDelete = internal.onDelete;
70
+ if (internal.onUpdate && internal.onUpdate !== "no action")
71
+ result.onUpdate = internal.onUpdate;
72
+ }
73
+ return result;
74
+ }
75
+ function serializeTable(table) {
76
+ const tableName = table._.name;
77
+ const columns = [];
78
+ const indexes = [];
79
+ for (const [key, value] of Object.entries(table)) {
80
+ if (key === "_")
81
+ continue;
82
+ if (value && typeof value === "object" && "__internal" in value) {
83
+ columns.push(serializeColumn(value));
84
+ }
85
+ }
86
+ const tableObj = table;
87
+ if (tableObj.__indexes) {
88
+ for (const idx of tableObj.__indexes) {
89
+ indexes.push({
90
+ name: idx.name,
91
+ columns: idx.columns,
92
+ unique: idx.unique
93
+ });
94
+ }
95
+ }
96
+ return { name: tableName, columns, indexes };
97
+ }
98
+ function serializeSchema(tables) {
99
+ const tableMap = {};
100
+ for (const t of tables) {
101
+ const serialized = serializeTable(t);
102
+ tableMap[serialized.name] = serialized;
103
+ }
104
+ return {
105
+ version: 1,
106
+ tables: tableMap
107
+ };
108
+ }
109
+
110
+ // src/migration/operations.ts
111
+ function addTable(table) {
112
+ return { type: "addTable", table: { ...table, indexes: table.indexes ?? [] } };
113
+ }
114
+ function dropTable(tableName, columns) {
115
+ return { type: "dropTable", tableName, columns };
116
+ }
117
+ function renameTable(from, to) {
118
+ return { type: "renameTable", from, to };
119
+ }
120
+ function addColumn(tableName, column) {
121
+ return { type: "addColumn", tableName, column };
122
+ }
123
+ function dropColumn(tableName, columnName) {
124
+ return { type: "dropColumn", tableName, columnName };
125
+ }
126
+ function renameColumn(tableName, from, to) {
127
+ return { type: "renameColumn", tableName, from, to };
128
+ }
129
+ function createIndex(tableName, index) {
130
+ return { type: "createIndex", tableName, index };
131
+ }
132
+ function dropIndex(indexName) {
133
+ return { type: "dropIndex", indexName };
134
+ }
135
+ function modifyColumn(tableName, columnName, changes) {
136
+ return { type: "modifyColumn", tableName, columnName, changes };
137
+ }
138
+ function modifyIndex(tableName, indexName, from, to) {
139
+ return { type: "modifyIndex", tableName, indexName, from, to };
140
+ }
141
+ function rebuildTable(tableName, oldTable, newTable) {
142
+ return { type: "rebuildTable", tableName, oldTable, newTable };
143
+ }
144
+
145
+ // src/migration/diff.ts
146
+ var exports_diff = {};
147
+ __export(exports_diff, {
148
+ resolveRenames: () => resolveRenames,
149
+ emptyState: () => emptyState,
150
+ diffSchemas: () => diffSchemas,
151
+ CancellationError: () => CancellationError
152
+ });
153
+ function topologicalSort(tables) {
154
+ const deps = new Map;
155
+ for (const table of tables) {
156
+ const tableDeps = new Set;
157
+ for (const col of table.columns) {
158
+ if (col.referencesTable && col.referencesTable !== table.name) {
159
+ tableDeps.add(col.referencesTable);
160
+ }
161
+ }
162
+ deps.set(table.name, tableDeps);
163
+ }
164
+ const tableByName = new Map(tables.map((t) => [t.name, t]));
165
+ const remaining = new Set(tables.map((t) => t.name));
166
+ const sorted = [];
167
+ while (remaining.size > 0) {
168
+ const ready = [...remaining].filter((name) => {
169
+ const d = deps.get(name);
170
+ return [...d].every((dep) => !remaining.has(dep));
171
+ });
172
+ if (ready.length === 0) {
173
+ const cycle = [...remaining].join(", ");
174
+ throw new Error(`Circular foreign key dependency detected: ${cycle}`);
175
+ }
176
+ for (const name of ready) {
177
+ sorted.push(tableByName.get(name));
178
+ remaining.delete(name);
179
+ }
180
+ }
181
+ return sorted;
182
+ }
183
+ function diffColumns(tableName, prevCols, currCols) {
184
+ const ops = [];
185
+ let unsafe = false;
186
+ const prevByName = new Map(prevCols.map((c) => [c.name, c]));
187
+ const currByName = new Map(currCols.map((c) => [c.name, c]));
188
+ for (const [name, col] of currByName) {
189
+ if (!prevByName.has(name)) {
190
+ ops.push(addColumn(tableName, col));
191
+ }
192
+ }
193
+ for (const [name] of prevByName) {
194
+ if (!currByName.has(name)) {
195
+ ops.push(dropColumn(tableName, name));
196
+ }
197
+ }
198
+ for (const [name, currCol] of currByName) {
199
+ const prevCol = prevByName.get(name);
200
+ if (!prevCol)
201
+ continue;
202
+ const changes = {};
203
+ let hasChanges = false;
204
+ if (prevCol.sqlType !== currCol.sqlType) {
205
+ unsafe = true;
206
+ }
207
+ if (prevCol.isPrimaryKey !== currCol.isPrimaryKey) {
208
+ unsafe = true;
209
+ }
210
+ if (prevCol.isNotNull !== currCol.isNotNull) {
211
+ if (prevCol.isNotNull && !currCol.isNotNull) {
212
+ unsafe = true;
213
+ }
214
+ if (!prevCol.isNotNull && currCol.isNotNull) {
215
+ if (!currCol.hasDefault) {
216
+ unsafe = true;
217
+ } else {
218
+ changes.isNotNull = true;
219
+ hasChanges = true;
220
+ }
221
+ }
222
+ }
223
+ if (prevCol.isUnique !== currCol.isUnique) {
224
+ unsafe = true;
225
+ }
226
+ if (prevCol.hasDefault !== currCol.hasDefault || prevCol.defaultValue !== currCol.defaultValue) {
227
+ if (prevCol.hasDefault && !currCol.hasDefault) {
228
+ unsafe = true;
229
+ }
230
+ if (!unsafe || hasChanges) {
231
+ changes.hasDefault = currCol.hasDefault;
232
+ changes.defaultValue = currCol.defaultValue;
233
+ hasChanges = true;
234
+ }
235
+ }
236
+ if (prevCol.referencesTable !== currCol.referencesTable || prevCol.referencesColumn !== currCol.referencesColumn) {
237
+ unsafe = true;
238
+ }
239
+ const hadFk = !!prevCol.referencesTable;
240
+ const hasFk = !!currCol.referencesTable;
241
+ if (hadFk !== hasFk) {
242
+ unsafe = true;
243
+ }
244
+ if (prevCol.onDelete !== currCol.onDelete || prevCol.onUpdate !== currCol.onUpdate) {
245
+ unsafe = true;
246
+ }
247
+ if (hasChanges) {
248
+ ops.push(modifyColumn(tableName, name, changes));
249
+ }
250
+ }
251
+ return { ops, unsafe };
252
+ }
253
+ function diffTable(tableName, prev, curr) {
254
+ const { ops: columnOps, unsafe } = diffColumns(tableName, prev.columns, curr.columns);
255
+ if (unsafe) {
256
+ return [rebuildTable(tableName, prev, curr)];
257
+ }
258
+ const ops = [...columnOps];
259
+ const prevIndexes = new Map(prev.indexes.map((i) => [i.name, i]));
260
+ const currIndexes = new Map(curr.indexes.map((i) => [i.name, i]));
261
+ for (const [name, idx] of currIndexes) {
262
+ if (!prevIndexes.has(name)) {
263
+ ops.push(createIndex(tableName, idx));
264
+ }
265
+ }
266
+ for (const [name] of prevIndexes) {
267
+ if (!currIndexes.has(name)) {
268
+ ops.push(dropIndex(name));
269
+ }
270
+ }
271
+ for (const [name, currIdx] of currIndexes) {
272
+ const prevIdx = prevIndexes.get(name);
273
+ if (!prevIdx)
274
+ continue;
275
+ const columnsChanged = JSON.stringify(prevIdx.columns) !== JSON.stringify(currIdx.columns);
276
+ const uniqueChanged = prevIdx.unique !== currIdx.unique;
277
+ if (columnsChanged || uniqueChanged) {
278
+ ops.push(modifyIndex(tableName, name, prevIdx, currIdx));
279
+ }
280
+ }
281
+ return ops;
282
+ }
283
+ function diffSchemas(previous, current) {
284
+ const ops = [];
285
+ const prevTables = new Map(Object.entries(previous.tables));
286
+ const currTables = new Map(Object.entries(current.tables));
287
+ const addedTables = [...currTables.entries()].filter(([name]) => !prevTables.has(name)).map(([, table]) => table);
288
+ const sortedAdded = topologicalSort(addedTables);
289
+ for (const table of sortedAdded) {
290
+ ops.push(addTable(table));
291
+ }
292
+ const droppedTables = [...prevTables.entries()].filter(([name]) => !currTables.has(name)).map(([, table]) => table);
293
+ const sortedDropped = topologicalSort(droppedTables).reverse();
294
+ for (const table of sortedDropped) {
295
+ ops.push(dropTable(table.name, table.columns));
296
+ }
297
+ for (const [name, prevTable] of prevTables) {
298
+ const currTable = currTables.get(name);
299
+ if (currTable) {
300
+ ops.push(...diffTable(name, prevTable, currTable));
301
+ }
302
+ }
303
+ return ops;
304
+ }
305
+ function emptyState() {
306
+ return { version: 1, tables: {} };
307
+ }
308
+ async function resolveRenames(operations, options) {
309
+ const interactive = options?.interactive ?? true;
310
+ const prompt = options?.prompt;
311
+ const renameGroups = new Map;
312
+ const droppedTables = operations.filter((op) => op.type === "dropTable");
313
+ const addedTables = operations.filter((op) => op.type === "addTable");
314
+ for (const dropped of droppedTables) {
315
+ for (const added of addedTables) {
316
+ const oldColNames = new Set((dropped.columns ?? []).map((c) => c.name));
317
+ if (oldColNames.size === 0)
318
+ continue;
319
+ const newColNames = added.table.columns.map((c) => c.name);
320
+ const overlap = newColNames.filter((name) => oldColNames.has(name));
321
+ if (overlap.length > 0) {
322
+ const key = `table:${added.table.name}`;
323
+ if (!renameGroups.has(key))
324
+ renameGroups.set(key, []);
325
+ renameGroups.get(key).push({
326
+ type: "table",
327
+ tableName: added.table.name,
328
+ from: dropped.tableName,
329
+ to: added.table.name
330
+ });
331
+ }
332
+ }
333
+ }
334
+ const droppedColumns = operations.filter((op) => op.type === "dropColumn");
335
+ const addedColumns = operations.filter((op) => op.type === "addColumn");
336
+ for (const added of addedColumns) {
337
+ const candidates = droppedColumns.filter((d) => d.tableName === added.tableName);
338
+ if (candidates.length > 0) {
339
+ const key = `column:${added.tableName}:${added.column.name}`;
340
+ if (!renameGroups.has(key))
341
+ renameGroups.set(key, []);
342
+ for (const dropped of candidates) {
343
+ renameGroups.get(key).push({
344
+ type: "column",
345
+ tableName: added.tableName,
346
+ from: dropped.columnName,
347
+ to: added.column.name
348
+ });
349
+ }
350
+ }
351
+ }
352
+ if (renameGroups.size === 0) {
353
+ return operations;
354
+ }
355
+ if (!interactive) {
356
+ return operations;
357
+ }
358
+ const resolvedOps = [...operations];
359
+ const consumedDrops = new Set;
360
+ for (const [, renames] of renameGroups) {
361
+ const firstRename = renames[0];
362
+ const entityLabel = firstRename.type === "table" ? "table" : "column";
363
+ const dropType = firstRename.type === "table" ? "dropTable" : "dropColumn";
364
+ const availableRenames = renames.filter((r) => !consumedDrops.has(`${dropType}:${r.tableName}:${r.from}`));
365
+ if (availableRenames.length === 0) {
366
+ continue;
367
+ }
368
+ const promptOptions = [
369
+ {
370
+ value: "add",
371
+ label: firstRename.to,
372
+ hint: firstRename.type === "table" ? "create table" : "add column"
373
+ },
374
+ ...availableRenames.map((r) => ({
375
+ value: `rename:${r.from}`,
376
+ label: `${r.from} \u2192 ${r.to}`,
377
+ hint: `rename ${entityLabel}`
378
+ }))
379
+ ];
380
+ if (!prompt) {
381
+ continue;
382
+ }
383
+ const result = await prompt(`Is ${firstRename.to} ${entityLabel} added or renamed?`, promptOptions);
384
+ if (typeof result === "symbol") {
385
+ throw new CancellationError("Operation cancelled.");
386
+ }
387
+ if (result !== "add") {
388
+ const fromName = result.replace("rename:", "");
389
+ const rename = availableRenames.find((r) => r.from === fromName);
390
+ if (!rename) {
391
+ continue;
392
+ }
393
+ consumedDrops.add(`${dropType}:${rename.tableName}:${rename.from}`);
394
+ const renameOp = rename.type === "table" ? renameTable(rename.from, rename.to) : renameColumn(rename.tableName, rename.from, rename.to);
395
+ const dropIdx = resolvedOps.findIndex((op) => {
396
+ if (op.type !== dropType)
397
+ return false;
398
+ if (rename.type === "table") {
399
+ return op.tableName === rename.from;
400
+ }
401
+ return op.columnName === rename.from && op.tableName === rename.tableName;
402
+ });
403
+ let oldColNames;
404
+ if (dropIdx !== -1 && rename.type === "table") {
405
+ const dropOp = resolvedOps[dropIdx];
406
+ oldColNames = new Set((dropOp.columns ?? []).map((c) => c.name));
407
+ resolvedOps.splice(dropIdx, 1);
408
+ } else if (dropIdx !== -1) {
409
+ resolvedOps.splice(dropIdx, 1);
410
+ }
411
+ const addType = rename.type === "table" ? "addTable" : "addColumn";
412
+ const addIdx = resolvedOps.findIndex((op) => {
413
+ if (op.type !== addType)
414
+ return false;
415
+ if (rename.type === "table") {
416
+ return op.table?.name === rename.to;
417
+ }
418
+ return op.column?.name === rename.to && op.tableName === rename.tableName;
419
+ });
420
+ if (rename.type === "table" && addIdx !== -1 && oldColNames) {
421
+ const addOp = resolvedOps[addIdx];
422
+ for (const col of addOp.table.columns) {
423
+ if (!oldColNames.has(col.name)) {
424
+ resolvedOps.push(addColumn(rename.from, col));
425
+ }
426
+ }
427
+ }
428
+ if (addIdx !== -1) {
429
+ resolvedOps.splice(addIdx, 1);
430
+ }
431
+ if (rename.type === "table") {
432
+ for (const op of resolvedOps) {
433
+ if (op.type === "addColumn" && op.tableName === rename.to) {
434
+ op.tableName = rename.from;
435
+ }
436
+ }
437
+ }
438
+ resolvedOps.push(renameOp);
439
+ }
440
+ }
441
+ return resolvedOps;
442
+ }
443
+ var CancellationError;
444
+ var init_diff = __esm(() => {
445
+ CancellationError = class CancellationError extends Error {
446
+ constructor(message) {
447
+ super(message);
448
+ this.name = "CancellationError";
449
+ }
450
+ };
451
+ });
452
+
453
+ // src/migration/sql.ts
454
+ var exports_sql = {};
455
+ __export(exports_sql, {
456
+ generateSQLStatements: () => generateSQLStatements,
457
+ generateSQL: () => generateSQL
458
+ });
459
+ function sqlType(col) {
460
+ return col.sqlType.toUpperCase();
461
+ }
462
+ function columnToDDL(col) {
463
+ const parts = [col.name, sqlType(col)];
464
+ if (col.isPrimaryKey)
465
+ parts.push("PRIMARY KEY");
466
+ if (col.isNotNull && !col.isPrimaryKey)
467
+ parts.push("NOT NULL");
468
+ if (col.isUnique && !col.isPrimaryKey)
469
+ parts.push("UNIQUE");
470
+ if (col.hasDefault) {
471
+ const val = col.defaultValue;
472
+ if (typeof val === "string") {
473
+ parts.push(`DEFAULT '${val.replace(/'/g, "''")}'`);
474
+ } else if (val === null) {
475
+ parts.push("DEFAULT NULL");
476
+ } else {
477
+ parts.push(`DEFAULT ${val}`);
478
+ }
479
+ }
480
+ if (col.referencesTable && col.referencesColumn) {
481
+ let fkClause = `REFERENCES ${col.referencesTable}(${col.referencesColumn})`;
482
+ if (col.onDelete)
483
+ fkClause += ` ON DELETE ${col.onDelete.toUpperCase()}`;
484
+ if (col.onUpdate)
485
+ fkClause += ` ON UPDATE ${col.onUpdate.toUpperCase()}`;
486
+ parts.push(fkClause);
487
+ }
488
+ return parts.join(" ");
489
+ }
490
+ function indexToSQL(idx, tableName) {
491
+ const unique = idx.unique ? "UNIQUE " : "";
492
+ const cols = idx.columns.join(", ");
493
+ return `CREATE ${unique}INDEX ${idx.name} ON ${tableName} (${cols})`;
494
+ }
495
+ function formatDefault(value) {
496
+ if (value === null)
497
+ return "NULL";
498
+ if (typeof value === "string")
499
+ return `'${value.replace(/'/g, "''")}'`;
500
+ if (typeof value === "boolean")
501
+ return value ? "1" : "0";
502
+ return String(value);
503
+ }
504
+ function rebuildTableToSQL(op) {
505
+ const { tableName, oldTable, newTable } = op;
506
+ const tempName = `_flint_rebuild_${tableName}`;
507
+ const stmts = [];
508
+ stmts.push("PRAGMA defer_foreign_keys = 1");
509
+ const cols = newTable.columns.map(columnToDDL).join(`,
510
+ `);
511
+ stmts.push(`CREATE TABLE ${tempName} (
512
+ ${cols}
513
+ )`);
514
+ const oldColSet = new Set(oldTable.columns.map((c) => c.name));
515
+ const insertCols = [];
516
+ const selectExprs = [];
517
+ for (const newCol of newTable.columns) {
518
+ insertCols.push(newCol.name);
519
+ if (oldColSet.has(newCol.name)) {
520
+ selectExprs.push(newCol.name);
521
+ } else {
522
+ selectExprs.push(`DEFAULT`);
523
+ }
524
+ }
525
+ stmts.push(`INSERT INTO ${tempName} (${insertCols.join(", ")}) SELECT ${selectExprs.join(", ")} FROM ${tableName}`);
526
+ stmts.push(`DROP TABLE ${tableName}`);
527
+ stmts.push(`ALTER TABLE ${tempName} RENAME TO ${tableName}`);
528
+ for (const idx of newTable.indexes) {
529
+ stmts.push(indexToSQL(idx, tableName));
530
+ }
531
+ return stmts;
532
+ }
533
+ function operationToSQL(op) {
534
+ switch (op.type) {
535
+ case "addTable": {
536
+ const cols = op.table.columns.map(columnToDDL).join(`,
537
+ `);
538
+ const stmts = [`CREATE TABLE ${op.table.name} (
539
+ ${cols}
540
+ )`];
541
+ for (const idx of op.table.indexes) {
542
+ stmts.push(indexToSQL(idx, op.table.name));
543
+ }
544
+ return stmts;
545
+ }
546
+ case "dropTable":
547
+ return [`DROP TABLE ${op.tableName}`];
548
+ case "renameTable":
549
+ return [`ALTER TABLE ${op.from} RENAME TO ${op.to}`];
550
+ case "addColumn":
551
+ return [`ALTER TABLE ${op.tableName} ADD COLUMN ${columnToDDL(op.column)}`];
552
+ case "dropColumn":
553
+ return [`ALTER TABLE ${op.tableName} DROP COLUMN ${op.columnName}`];
554
+ case "renameColumn":
555
+ return [`ALTER TABLE ${op.tableName} RENAME COLUMN ${op.from} TO ${op.to}`];
556
+ case "createIndex":
557
+ return [indexToSQL(op.index, op.tableName)];
558
+ case "dropIndex":
559
+ return [`DROP INDEX ${op.indexName}`];
560
+ case "modifyColumn": {
561
+ const stmts = [];
562
+ if (op.changes.isNotNull !== undefined && op.changes.isNotNull) {
563
+ stmts.push(`ALTER TABLE ${op.tableName} ALTER COLUMN ${op.columnName} SET NOT NULL`);
564
+ }
565
+ if (op.changes.hasDefault !== undefined) {
566
+ if (op.changes.hasDefault && op.changes.defaultValue !== undefined) {
567
+ const val = formatDefault(op.changes.defaultValue);
568
+ stmts.push(`ALTER TABLE ${op.tableName} ALTER COLUMN ${op.columnName} SET DEFAULT ${val}`);
569
+ } else if (!op.changes.hasDefault) {
570
+ stmts.push(`ALTER TABLE ${op.tableName} ALTER COLUMN ${op.columnName} DROP DEFAULT`);
571
+ }
572
+ }
573
+ return stmts;
574
+ }
575
+ case "modifyIndex":
576
+ return [`DROP INDEX IF EXISTS ${op.indexName}`, indexToSQL(op.to, op.tableName)];
577
+ case "rebuildTable":
578
+ return rebuildTableToSQL(op);
579
+ }
580
+ }
581
+ function generateSQL(operations) {
582
+ return operations.flatMap(operationToSQL).join(`;
583
+ `) + ";";
584
+ }
585
+ function generateSQLStatements(operations) {
586
+ return operations.flatMap(operationToSQL);
587
+ }
588
+
589
+ // src/migration/generate.ts
590
+ var exports_generate = {};
591
+ __export(exports_generate, {
592
+ generate: () => generate
593
+ });
594
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from "fs";
595
+ import { join } from "path";
596
+ function randomWords() {
597
+ const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
598
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
599
+ return `${adj}_${noun}`;
600
+ }
601
+ function generateFolderName(migrationName) {
602
+ const timestamp = Math.floor(Date.now() / 1000);
603
+ if (migrationName) {
604
+ return `${timestamp}_${migrationName}`;
605
+ }
606
+ const words = randomWords();
607
+ return `${timestamp}_${words}`;
608
+ }
609
+ function findLatestState(migrationsDir) {
610
+ if (!existsSync(migrationsDir))
611
+ return null;
612
+ const entries = readdirSync(migrationsDir);
613
+ const migrationFolders = entries.filter((e) => /^\d{10}_/.test(e)).sort().reverse();
614
+ for (const folder of migrationFolders) {
615
+ const statePath = join(migrationsDir, folder, "state.json");
616
+ if (existsSync(statePath)) {
617
+ return JSON.parse(readFileSync(statePath, "utf-8"));
618
+ }
619
+ }
620
+ return null;
621
+ }
622
+ function serializeOpArg(op) {
623
+ switch (op.type) {
624
+ case "addTable":
625
+ return serializeTableArg(op.table);
626
+ case "dropTable":
627
+ return JSON.stringify(op.tableName);
628
+ case "renameTable":
629
+ return `${JSON.stringify(op.from)}, ${JSON.stringify(op.to)}`;
630
+ case "addColumn":
631
+ return `${JSON.stringify(op.tableName)}, ${serializeColumnArg(op.column)}`;
632
+ case "dropColumn":
633
+ return `${JSON.stringify(op.tableName)}, ${JSON.stringify(op.columnName)}`;
634
+ case "renameColumn":
635
+ return `${JSON.stringify(op.tableName)}, ${JSON.stringify(op.from)}, ${JSON.stringify(op.to)}`;
636
+ case "createIndex":
637
+ return `${JSON.stringify(op.tableName)}, ${serializeIndexArg(op.index)}`;
638
+ case "dropIndex":
639
+ return JSON.stringify(op.indexName);
640
+ case "modifyColumn":
641
+ return `${JSON.stringify(op.tableName)}, ${JSON.stringify(op.columnName)}, ${JSON.stringify(op.changes)}`;
642
+ case "modifyIndex":
643
+ return `${JSON.stringify(op.tableName)}, ${JSON.stringify(op.indexName)}, ${serializeIndexArg(op.from)}, ${serializeIndexArg(op.to)}`;
644
+ case "rebuildTable":
645
+ return `${JSON.stringify(op.tableName)}, ${serializeTableArg(op.oldTable)}, ${serializeTableArg(op.newTable)}`;
646
+ }
647
+ }
648
+ function serializeColumnArg(col) {
649
+ const obj = {
650
+ name: col.name,
651
+ sqlType: col.sqlType,
652
+ isPrimaryKey: col.isPrimaryKey,
653
+ isNotNull: col.isNotNull,
654
+ isUnique: col.isUnique,
655
+ hasDefault: col.hasDefault,
656
+ defaultValue: col.defaultValue
657
+ };
658
+ if (col.referencesTable && col.referencesColumn) {
659
+ obj.referencesTable = col.referencesTable;
660
+ obj.referencesColumn = col.referencesColumn;
661
+ if (col.onDelete)
662
+ obj.onDelete = col.onDelete;
663
+ if (col.onUpdate)
664
+ obj.onUpdate = col.onUpdate;
665
+ }
666
+ return JSON.stringify(obj);
667
+ }
668
+ function serializeIndexArg(idx) {
669
+ return `{ name: ${JSON.stringify(idx.name)}, columns: ${JSON.stringify(idx.columns)}, unique: ${idx.unique} }`;
670
+ }
671
+ function serializeTableArg(table) {
672
+ const cols = table.columns.map((c) => serializeColumnArg(c)).join(`,
673
+ `);
674
+ const idxs = table.indexes.map((i) => serializeIndexArg(i)).join(`,
675
+ `);
676
+ let arg = `{
677
+ name: ${JSON.stringify(table.name)},
678
+ columns: [
679
+ ${cols}
680
+ ]`;
681
+ if (table.indexes.length > 0) {
682
+ arg += `,
683
+ indexes: [
684
+ ${idxs}
685
+ ]`;
686
+ }
687
+ arg += `
688
+ }`;
689
+ return arg;
690
+ }
691
+ async function generate(tables, migrationsDir, nameOrOptions) {
692
+ const options = typeof nameOrOptions === "string" ? { name: nameOrOptions } : nameOrOptions ?? {};
693
+ const migrationName = options.name;
694
+ const previous = findLatestState(migrationsDir) ?? emptyState();
695
+ const current = serializeSchema(tables);
696
+ const rawOps = diffSchemas(previous, current);
697
+ if (rawOps.length === 0) {
698
+ throw new Error("No changes detected \u2014 schema is already up to date.");
699
+ }
700
+ const operations = await resolveRenames(rawOps, { interactive: options.interactive, prompt: options.prompt });
701
+ const sql = generateSQL(operations);
702
+ const folderName = generateFolderName(migrationName);
703
+ const migrationDir = join(migrationsDir, folderName);
704
+ mkdirSync(migrationDir, { recursive: true });
705
+ const uniqueOps = [...new Set(operations.map((op) => op.type))];
706
+ const imports = uniqueOps.map((op) => `import { ${op} } from "flint-orm/migration/operations";`).join(`
707
+ `);
708
+ const operationLines = operations.map((op) => {
709
+ const arg = serializeOpArg(op);
710
+ return ` ${op.type}(${arg}),`;
711
+ }).join(`
712
+ `);
713
+ const displayName = migrationName ?? folderName;
714
+ const migrationContent = `// Migration: ${displayName}
715
+ // Generated by flint generate
716
+
717
+ import { defineMigration } from "flint-orm/migration";
718
+ ${imports}
719
+
720
+ export default defineMigration({
721
+ name: "${displayName}",
722
+ operations: [
723
+ ${operationLines}
724
+ ],
725
+ });
726
+ `;
727
+ writeFileSync(join(migrationDir, "migration.ts"), migrationContent);
728
+ writeFileSync(join(migrationDir, "state.json"), JSON.stringify(current, null, 2));
729
+ return {
730
+ folderName,
731
+ operations,
732
+ sql,
733
+ state: current
734
+ };
735
+ }
736
+ var ADJECTIVES, NOUNS;
737
+ var init_generate = __esm(() => {
738
+ init_diff();
739
+ ADJECTIVES = [
740
+ "amber",
741
+ "azure",
742
+ "blank",
743
+ "brisk",
744
+ "calm",
745
+ "clear",
746
+ "cold",
747
+ "cool",
748
+ "crisp",
749
+ "dark",
750
+ "deep",
751
+ "dull",
752
+ "dusk",
753
+ "dawn",
754
+ "fair",
755
+ "faint",
756
+ "flat",
757
+ "foggy",
758
+ "frost",
759
+ "glad",
760
+ "golden",
761
+ "gray",
762
+ "green",
763
+ "gross",
764
+ "happy",
765
+ "harsh",
766
+ "hazy",
767
+ "keen",
768
+ "kind",
769
+ "light",
770
+ "lively",
771
+ "long",
772
+ "loud",
773
+ "lucky",
774
+ "mild",
775
+ "misty",
776
+ "mossy",
777
+ "neat",
778
+ "noble",
779
+ "odd",
780
+ "pale",
781
+ "plain",
782
+ "proud",
783
+ "pure",
784
+ "quick",
785
+ "quiet",
786
+ "rare",
787
+ "raw",
788
+ "rich",
789
+ "ripe",
790
+ "rough",
791
+ "royal",
792
+ "rusty",
793
+ "sharp",
794
+ "sheer",
795
+ "shiny",
796
+ "silent",
797
+ "silver",
798
+ "sleek",
799
+ "slim",
800
+ "slow",
801
+ "smooth",
802
+ "soft",
803
+ "solid",
804
+ "sour",
805
+ "stark",
806
+ "steep",
807
+ "stern",
808
+ "still",
809
+ "stout",
810
+ "strict",
811
+ "swift",
812
+ "tall",
813
+ "tame",
814
+ "thin",
815
+ "tidy",
816
+ "tough",
817
+ "vast",
818
+ "vivid",
819
+ "warm",
820
+ "wild",
821
+ "wise",
822
+ "young"
823
+ ];
824
+ NOUNS = [
825
+ "badger",
826
+ "birch",
827
+ "bison",
828
+ "bloom",
829
+ "brick",
830
+ "brook",
831
+ "cedar",
832
+ "cider",
833
+ "clay",
834
+ "cobra",
835
+ "coral",
836
+ "crane",
837
+ "creek",
838
+ "crow",
839
+ "deer",
840
+ "delta",
841
+ "dune",
842
+ "eagle",
843
+ "elm",
844
+ "ember",
845
+ "fern",
846
+ "finch",
847
+ "flint",
848
+ "fox",
849
+ "glacier",
850
+ "gorse",
851
+ "granite",
852
+ "hare",
853
+ "hawk",
854
+ "hazel",
855
+ "heron",
856
+ "hickory",
857
+ "hornet",
858
+ "ivy",
859
+ "jay",
860
+ "jasper",
861
+ "kestrel",
862
+ "kite",
863
+ "larch",
864
+ "lea",
865
+ "lichen",
866
+ "linen",
867
+ "lion",
868
+ "maple",
869
+ "marsh",
870
+ "mink",
871
+ "moss",
872
+ "moth",
873
+ "newt",
874
+ "oak",
875
+ "onyx",
876
+ "otter",
877
+ "owl",
878
+ "pearl",
879
+ "pine",
880
+ "plume",
881
+ "quail",
882
+ "quartz",
883
+ "rabbit",
884
+ "rain",
885
+ "raven",
886
+ "ridge",
887
+ "river",
888
+ "robin",
889
+ "rose",
890
+ "sage",
891
+ "salmon",
892
+ "scarab",
893
+ "shale",
894
+ "silk",
895
+ "skunk",
896
+ "slate",
897
+ "sparrow",
898
+ "spice",
899
+ "stone",
900
+ "storm",
901
+ "swift",
902
+ "thorn",
903
+ "tide",
904
+ "tile",
905
+ "toad",
906
+ "tulip",
907
+ "vale",
908
+ "viper",
909
+ "wasp",
910
+ "willow",
911
+ "wren",
912
+ "yarrow"
913
+ ];
914
+ });
915
+
916
+ // src/migration/migrate.ts
917
+ var exports_migrate = {};
918
+ __export(exports_migrate, {
919
+ migrate: () => migrate,
920
+ getMigrationStatus: () => getMigrationStatus
921
+ });
922
+ import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
923
+ import { join as join2 } from "path";
924
+ import { pathToFileURL } from "url";
925
+ async function ensureTrackingTable(executor) {
926
+ await executor.run(`CREATE TABLE IF NOT EXISTS ${TRACKING_TABLE} (
927
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
928
+ name TEXT NOT NULL UNIQUE,
929
+ applied_at INTEGER NOT NULL
930
+ )`, []);
931
+ }
932
+ async function getAppliedMigrations(executor) {
933
+ const rows = await executor.all(`SELECT name FROM ${TRACKING_TABLE} ORDER BY id`, []);
934
+ return new Set(rows.map((r) => r.name));
935
+ }
936
+ async function recordMigration(executor, name) {
937
+ await executor.run(`INSERT INTO ${TRACKING_TABLE} (name, applied_at) VALUES (?, ?)`, [name, Date.now()]);
938
+ }
939
+ async function checkIncomingForeignKeys(executor, tableName) {
940
+ const allTables = await executor.all(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__flint_%'`, []);
941
+ const referencing = [];
942
+ for (const { name } of allTables) {
943
+ if (name === tableName)
944
+ continue;
945
+ const fkRows = await executor.all(`PRAGMA foreign_key_list('${name}')`, []);
946
+ if (fkRows.some((fk) => fk.table === tableName)) {
947
+ referencing.push(name);
948
+ }
949
+ }
950
+ if (referencing.length > 0) {
951
+ throw new Error(`Cannot rebuild "${tableName}" \u2014 referenced by: ${referencing.join(", ")}. ` + `Rebuild or migrate those tables first.`);
952
+ }
953
+ }
954
+ function discoverMigrations(migrationsDir) {
955
+ if (!existsSync2(migrationsDir))
956
+ return [];
957
+ const entries = readdirSync2(migrationsDir);
958
+ const migrationFolders = entries.filter((e) => /^\d{10}_/.test(e)).sort();
959
+ return migrationFolders.map((folder) => {
960
+ const name = folder.replace(/^\d{10}_/, "");
961
+ return {
962
+ folderName: folder,
963
+ name,
964
+ path: join2(migrationsDir, folder)
965
+ };
966
+ });
967
+ }
968
+ async function loadMigration(entry) {
969
+ const migrationPath = join2(entry.path, "migration.ts");
970
+ if (!existsSync2(migrationPath)) {
971
+ throw new Error(`Migration file not found: ${migrationPath}`);
972
+ }
973
+ const url = pathToFileURL(migrationPath).href;
974
+ const mod = await import(url);
975
+ const migration = mod.default;
976
+ if (!migration || !migration.operations || !Array.isArray(migration.operations)) {
977
+ throw new Error(`Invalid migration file: ${migrationPath}`);
978
+ }
979
+ return migration;
980
+ }
981
+ async function migrate(executor, options) {
982
+ const { migrationsDir, dryRun = false } = options;
983
+ if (!dryRun) {
984
+ await ensureTrackingTable(executor);
985
+ }
986
+ const applied = dryRun ? new Set : await getAppliedMigrations(executor);
987
+ const allMigrations = discoverMigrations(migrationsDir);
988
+ const pending = allMigrations.filter((m) => !applied.has(m.folderName));
989
+ if (pending.length === 0) {
990
+ return { applied: [], skipped: allMigrations.map((m) => m.folderName) };
991
+ }
992
+ if (dryRun) {
993
+ return {
994
+ applied: pending.map((m) => m.folderName),
995
+ skipped: allMigrations.filter((m) => applied.has(m.folderName)).map((m) => m.folderName)
996
+ };
997
+ }
998
+ const newlyApplied = [];
999
+ for (const entry of pending) {
1000
+ const migration = await loadMigration(entry);
1001
+ for (const op of migration.operations) {
1002
+ if (op.type === "rebuildTable") {
1003
+ await checkIncomingForeignKeys(executor, op.tableName);
1004
+ }
1005
+ }
1006
+ const statements = generateSQLStatements(migration.operations);
1007
+ await executor.transaction(async () => {
1008
+ for (const stmt of statements) {
1009
+ await executor.run(stmt, []);
1010
+ }
1011
+ await recordMigration(executor, entry.folderName);
1012
+ });
1013
+ newlyApplied.push(entry.folderName);
1014
+ }
1015
+ return {
1016
+ applied: newlyApplied,
1017
+ skipped: allMigrations.filter((m) => applied.has(m.folderName)).map((m) => m.folderName)
1018
+ };
1019
+ }
1020
+ async function getMigrationStatus(executor, migrationsDir) {
1021
+ await ensureTrackingTable(executor);
1022
+ const appliedNames = await getAppliedMigrations(executor);
1023
+ const allMigrations = discoverMigrations(migrationsDir);
1024
+ return {
1025
+ applied: allMigrations.filter((m) => appliedNames.has(m.folderName)).map((m) => ({ name: m.name, folderName: m.folderName })),
1026
+ pending: allMigrations.filter((m) => !appliedNames.has(m.folderName)).map((m) => ({ name: m.name, folderName: m.folderName }))
1027
+ };
1028
+ }
1029
+ var TRACKING_TABLE = "__flint_migrations";
1030
+ var init_migrate = () => {};
1031
+
1032
+ // src/migration/migration.ts
1033
+ function defineMigration(config) {
1034
+ return {
1035
+ name: config.name,
1036
+ operations: config.operations
1037
+ };
1038
+ }
1039
+
1040
+ // src/migration/index.ts
1041
+ init_diff();
1042
+ init_generate();
1043
+ init_migrate();
1044
+ export {
1045
+ serializeSchema,
1046
+ resolveRenames,
1047
+ renameTable,
1048
+ renameColumn,
1049
+ rebuildTable,
1050
+ modifyIndex,
1051
+ modifyColumn,
1052
+ migrate,
1053
+ getMigrationStatus,
1054
+ generateSQL,
1055
+ generate,
1056
+ emptyState,
1057
+ dropTable,
1058
+ dropIndex,
1059
+ dropColumn,
1060
+ diffSchemas,
1061
+ defineMigration,
1062
+ createIndex,
1063
+ addTable,
1064
+ addColumn,
1065
+ CancellationError
1066
+ };