uql-orm 0.79.0 → 0.81.0

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 (110) hide show
  1. package/dist/browser/uql-browser.min.js.map +2 -2
  2. package/dist/cockroachdb/cockroachDialect.js +5 -1
  3. package/dist/dialect/abstractDialect.d.ts +1 -31
  4. package/dist/dialect/abstractDialect.js +3 -27
  5. package/dist/dialect/abstractSqlDialect.d.ts +25 -56
  6. package/dist/dialect/abstractSqlDialect.js +78 -145
  7. package/dist/dialect/aliases.d.ts +5 -0
  8. package/dist/dialect/aliases.js +5 -0
  9. package/dist/dialect/mysqlLikeSqlDialect.d.ts +4 -2
  10. package/dist/dialect/mysqlLikeSqlDialect.js +14 -1
  11. package/dist/dialect/operators.d.ts +66 -0
  12. package/dist/dialect/operators.js +129 -0
  13. package/dist/dialect/pgLikeSqlDialect.d.ts +4 -1
  14. package/dist/dialect/pgLikeSqlDialect.js +16 -3
  15. package/dist/dialect/vectorSqlDialect.d.ts +2 -0
  16. package/dist/dialect/vectorSqlDialect.js +4 -0
  17. package/dist/entity/decorator/entity.d.ts +6 -1
  18. package/dist/entity/decorator/entity.js +12 -1
  19. package/dist/entity/index.d.ts +1 -1
  20. package/dist/entity/index.js +1 -1
  21. package/dist/entity/metadata/definition.d.ts +6 -1
  22. package/dist/entity/metadata/definition.js +19 -0
  23. package/dist/migrate/builder/expressions.d.ts +2 -0
  24. package/dist/migrate/builder/expressions.js +24 -0
  25. package/dist/migrate/cli.js +1 -1
  26. package/dist/migrate/codegen/entityCodeGenerator.js +2 -2
  27. package/dist/migrate/codegen/entityTypes.js +1 -2
  28. package/dist/migrate/codegen/indexDecoratorSource.d.ts +3 -2
  29. package/dist/migrate/codegen/indexDecoratorSource.js +5 -23
  30. package/dist/migrate/ddl/mssqlIndexDdl.d.ts +5 -0
  31. package/dist/migrate/ddl/mssqlIndexDdl.js +10 -0
  32. package/dist/migrate/ddl/mssqlTableDdl.d.ts +6 -4
  33. package/dist/migrate/ddl/mssqlTableDdl.js +25 -14
  34. package/dist/migrate/ddl/mysqlIndexDdl.d.ts +2 -2
  35. package/dist/migrate/ddl/mysqlIndexDdl.js +7 -6
  36. package/dist/migrate/ddl/pgIndexDdl.d.ts +2 -1
  37. package/dist/migrate/ddl/pgIndexDdl.js +8 -6
  38. package/dist/migrate/ddl/tableDdl.d.ts +5 -2
  39. package/dist/migrate/ddl/tableDdl.js +13 -7
  40. package/dist/migrate/drift/driftDetector.d.ts +4 -5
  41. package/dist/migrate/drift/driftDetector.js +21 -21
  42. package/dist/migrate/generator/definitionToNode.d.ts +1 -1
  43. package/dist/migrate/generator/definitionToNode.js +9 -20
  44. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +5 -1
  45. package/dist/migrate/generator/mongoSchemaGenerator.js +20 -18
  46. package/dist/migrate/index.d.ts +2 -1
  47. package/dist/migrate/index.js +1 -0
  48. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +16 -6
  49. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +18 -4
  50. package/dist/migrate/introspection/baseSqlIntrospector.js +7 -18
  51. package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
  52. package/dist/migrate/introspection/mongoIntrospector.js +7 -3
  53. package/dist/migrate/introspection/mssqlIntrospector.d.ts +1 -0
  54. package/dist/migrate/introspection/mssqlIntrospector.js +9 -0
  55. package/dist/migrate/introspection/mysqlIntrospector.d.ts +16 -5
  56. package/dist/migrate/introspection/mysqlIntrospector.js +39 -2
  57. package/dist/migrate/introspection/postgresIntrospector.d.ts +30 -21
  58. package/dist/migrate/introspection/postgresIntrospector.js +70 -43
  59. package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -0
  60. package/dist/migrate/introspection/sqliteIntrospector.js +13 -8
  61. package/dist/migrate/migrator.d.ts +33 -1
  62. package/dist/migrate/migrator.js +111 -43
  63. package/dist/migrate/schemaChange.d.ts +18 -0
  64. package/dist/migrate/schemaChange.js +37 -0
  65. package/dist/migrate/schemaGenerator.d.ts +25 -15
  66. package/dist/migrate/schemaGenerator.js +130 -182
  67. package/dist/migrate/storage/databaseStorage.d.ts +4 -0
  68. package/dist/migrate/storage/databaseStorage.js +14 -8
  69. package/dist/migrate/triggerSql.d.ts +24 -0
  70. package/dist/migrate/triggerSql.js +229 -0
  71. package/dist/mongo/mongoDialect.d.ts +0 -21
  72. package/dist/mongo/mongoDialect.js +105 -100
  73. package/dist/mongo/mongodbQuerier.js +17 -1
  74. package/dist/mssql/mssqlDialect.d.ts +18 -7
  75. package/dist/mssql/mssqlDialect.js +77 -33
  76. package/dist/mssql/mssqlQuerier.js +2 -2
  77. package/dist/schema/canonicalType.d.ts +6 -1
  78. package/dist/schema/canonicalType.js +14 -0
  79. package/dist/schema/indexDifferences.d.ts +22 -6
  80. package/dist/schema/indexDifferences.js +23 -8
  81. package/dist/schema/matchByKey.d.ts +10 -0
  82. package/dist/schema/matchByKey.js +18 -0
  83. package/dist/schema/schemaAST.d.ts +6 -2
  84. package/dist/schema/schemaAST.js +7 -3
  85. package/dist/schema/schemaASTBuilder.d.ts +4 -8
  86. package/dist/schema/schemaASTBuilder.js +20 -29
  87. package/dist/schema/schemaASTDiffer.d.ts +2 -3
  88. package/dist/schema/schemaASTDiffer.js +15 -36
  89. package/dist/schema/types.d.ts +14 -15
  90. package/dist/sqlite/sqliteDialect.d.ts +1 -1
  91. package/dist/sqlite/sqliteDialect.js +12 -3
  92. package/dist/type/dialect.d.ts +69 -9
  93. package/dist/type/entity.d.ts +96 -3
  94. package/dist/type/migration.d.ts +43 -44
  95. package/dist/type/query.d.ts +13 -4
  96. package/dist/type/queryWhere.d.ts +4 -2
  97. package/dist/util/ddlExpression.util.d.ts +5 -1
  98. package/dist/util/ddlExpression.util.js +6 -2
  99. package/dist/util/field.util.d.ts +9 -1
  100. package/dist/util/field.util.js +14 -2
  101. package/dist/util/fieldOption.util.d.ts +2 -2
  102. package/dist/util/fieldOption.util.js +2 -2
  103. package/dist/util/raw.d.ts +9 -1
  104. package/dist/util/raw.js +36 -11
  105. package/dist/util/sql.util.d.ts +12 -0
  106. package/dist/util/sql.util.js +24 -3
  107. package/dist/util/uqlError.d.ts +2 -0
  108. package/dist/util/uqlError.js +4 -0
  109. package/package.json +4 -4
  110. package/skills/uql-orm/SKILL.md +11 -6
@@ -3,10 +3,12 @@ import { basename, extname, join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { getEntities, getMeta } from '../entity/index.js';
5
5
  import { SchemaAST } from '../schema/index.js';
6
+ import { hasTriggers } from '../util/field.util.js';
6
7
  import { LoggerWrapper } from '../util/index.js';
7
8
  import { buildMigrationModule } from './codegen/migrationFile.js';
8
9
  import { introspectorFor } from './introspection/registry.js';
9
10
  import { migrationBuilderFor, migrationTargetFor } from './migrationTarget.js';
11
+ import { dropped, nonEmpty, reverseDiff, sides } from './schemaChange.js';
10
12
  /**
11
13
  * Main class for managing database migrations
12
14
  */
@@ -181,17 +183,17 @@ export class Migrator {
181
183
  async generateFromEntities(name) {
182
184
  const generator = await this.getSchemaGenerator();
183
185
  const { created, altered } = await this.pendingChanges();
184
- const up = [
185
- ...this.createSchema(generator, created),
186
- ...altered.flatMap((diff) => generator.generateAlterTable(diff)),
187
- ];
186
+ const plan = this.alterPlan(generator, altered, await this.installedTriggers(created));
187
+ const up = [...this.createSchema(generator, created), ...plan.up];
188
188
  if (up.length === 0) {
189
189
  this.logger.logInfo('No schema changes detected.');
190
190
  return '';
191
191
  }
192
192
  // Diff by diff in reverse, each rolled back in the order its generator wrote it.
193
193
  const down = [
194
- ...altered.toReversed().flatMap((diff) => generator.generateAlterTableDown(diff)),
194
+ ...plan.down(),
195
+ // A table's drop takes its triggers along, but not the function the Postgres family keeps each body in.
196
+ ...this.createdEntities(created).flatMap((entity) => generator.generateTriggersDown(entity)),
195
197
  ...created.toReversed().map((tableName) => generator.generateDropTable(tableName, { ifExists: true })),
196
198
  ];
197
199
  const { emit } = this.target.source;
@@ -203,6 +205,74 @@ export class Migrator {
203
205
  this.logger.logInfo(`Created migration from entities: ${filePath}`);
204
206
  return filePath;
205
207
  }
208
+ /**
209
+ * Each entity on a table this plan does not create - a new one carries its triggers in its `CREATE` -
210
+ * beside the triggers uql has installed there, read once per schema. Kept only where either side has
211
+ * any: one declaring none on a table holding none has nothing to reconcile.
212
+ */
213
+ async installedTriggers(created, entities = this.entities) {
214
+ const { dialect } = this.pool;
215
+ const fresh = new Set(created);
216
+ // Tables this plan creates are left out: their `CREATE` carries their triggers, and asking the
217
+ // catalogue about a table that is not there yet fails outright on some engines.
218
+ const wanted = entities.filter((entity) => !fresh.has(this.tableOf(entity)));
219
+ const state = [];
220
+ for (const entity of wanted) {
221
+ const meta = getMeta(entity);
222
+ const installed = await this.schemaIntrospectorFor(dialect.resolveSchema(meta)).ownedTriggers(dialect.resolveTableAlias(meta));
223
+ // An installed trigger alone keeps it: an entity that stopped declaring one has it to drop.
224
+ if (installed.size || hasTriggers(meta)) {
225
+ state.push({ entity, installed });
226
+ }
227
+ }
228
+ return state;
229
+ }
230
+ /**
231
+ * The alters, with the triggers reconciled around them. Postgres refuses to retype or drop a column a
232
+ * trigger names, so every trigger on a table whose columns change comes off before the alters and what
233
+ * its entity declares goes back on after. `down` is lazy: SQLite cannot express every alter's inverse.
234
+ */
235
+ alterPlan(generator, altered, state) {
236
+ const changing = new Set(altered.filter((diff) => sides(diff.columns, 'from').length).map((diff) => diff.tableName));
237
+ const cleared = state.filter(({ entity }) => changing.has(this.tableOf(entity)));
238
+ const after = state.map((it) => (cleared.includes(it) ? { entity: it.entity, installed: new Map() } : it));
239
+ return {
240
+ up: [
241
+ ...cleared.flatMap(({ entity, installed }) => generator.generateTriggerDrops(entity, [...installed.keys()])),
242
+ ...altered.flatMap((diff) => generator.generateAlterTable(diff)),
243
+ ...this.reconcileTriggers(generator, after),
244
+ ],
245
+ down: () => [
246
+ ...this.revertedTriggers(generator, after),
247
+ ...altered.toReversed().flatMap((diff) => generator.generateAlterTable(reverseDiff(diff))),
248
+ ...cleared.flatMap(({ installed }) => [...installed.values()].flat().map((sql) => `${sql};`)),
249
+ ],
250
+ };
251
+ }
252
+ /**
253
+ * Each entity's triggers taken from what the catalogue holds to what it declares. Against the catalogue
254
+ * rather than a diff, because a trigger hangs off a table whose columns may be unchanged: a body edited
255
+ * on a settled table appears in no diff at all.
256
+ */
257
+ reconcileTriggers(generator, state) {
258
+ return state.flatMap(({ entity, installed }) => generator.generateTriggers(entity, installed));
259
+ }
260
+ /**
261
+ * The inverse: what the reconcile created dropped, and what it dropped restored as the engine reprints
262
+ * it. Read off the catalogue rather than recorded by uql, and exactly right for restoring one.
263
+ */
264
+ revertedTriggers(generator, state) {
265
+ return state.flatMap(({ entity, installed }) => generator.generateTriggersDown(entity, installed));
266
+ }
267
+ /** The entities whose tables are among `created`. */
268
+ createdEntities(created) {
269
+ const fresh = new Set(created);
270
+ return this.entities.filter((entity) => fresh.has(this.tableOf(entity)));
271
+ }
272
+ /** The table `entity` maps to, as a diff names it. */
273
+ tableOf(entity) {
274
+ return this.pool.dialect.resolveTableName(getMeta(entity));
275
+ }
206
276
  /**
207
277
  * Get all schema differences between entities and database
208
278
  */
@@ -269,14 +339,16 @@ export class Migrator {
269
339
  }
270
340
  // With the tables it references, which its foreign keys resolve against.
271
341
  const ast = await this.introspectEntities([entity, ...referencedEntities(meta)]);
272
- return this.alterFromEntity(generator, entity, ast.getTable(tableName), options);
342
+ // The table is already there, so its triggers are reconciled rather than carried by a `CREATE`.
343
+ const altered = this.alterFromEntity(generator, entity, ast.getTable(tableName), options);
344
+ return this.alterPlan(generator, altered, await this.installedTriggers([], [entity])).up;
273
345
  }
274
- /** The same for one entity against the table it already has, and nothing where the two agree. */
346
+ /** The diff for one entity against the table it already has, and none where the two agree. */
275
347
  alterFromEntity(generator, entity, table, options) {
276
348
  // Spanning the set for the reason `planEntity` spells out: a foreign key needs the table it
277
349
  // points at, which a sync of one entity outside the configured list would not otherwise have.
278
350
  const diff = generator.diffSchema(entity, table, generator.buildAST?.(this.entitiesWith(entity)));
279
- return diff?.type === 'alter' ? generator.generateAlterTable(this.filterDiff(diff, options)) : [];
351
+ return diff?.type === 'alter' ? [this.filterDiff(diff, options)] : [];
280
352
  }
281
353
  /** The configured entities, with `entity` among them however the migrator was built. */
282
354
  entitiesWith(entity) {
@@ -300,9 +372,10 @@ export class Migrator {
300
372
  return this.planEntity(generator, options.entity, options);
301
373
  }
302
374
  const { created, altered } = await this.pendingChanges();
375
+ const filtered = altered.map((diff) => this.filterDiff(diff, options));
303
376
  return [
304
377
  ...this.createSchema(generator, created),
305
- ...altered.flatMap((diff) => generator.generateAlterTable(this.filterDiff(diff, options))),
378
+ ...this.alterPlan(generator, filtered, await this.installedTriggers(created)).up,
306
379
  ];
307
380
  }
308
381
  /** The new tables, created together so a foreign key between them, cyclic included, resolves. Empty in, empty out. */
@@ -321,45 +394,40 @@ export class Migrator {
321
394
  altered: diffs.filter((diff) => diff.type === 'alter'),
322
395
  };
323
396
  }
397
+ /**
398
+ * Safe mode only adds: a change with a `from` drops or rebuilds what the table holds, so it is held,
399
+ * and so is a key whole, which rebuilds an index over every row and fails where a column holds a null.
400
+ * Without `drop`, a column's drop is held too.
401
+ */
324
402
  filterDiff(diff, options) {
325
- const filteredDiff = { ...diff };
326
- if (options.safe !== false) {
327
- // In safe mode, we only allow additions (creating tables/columns)
328
- // We block drops and alterations to prevent accidental data loss
329
- if (filteredDiff.columnsToDrop?.length) {
330
- this.logger.logSkippedMigration(`[AutoSync] Skipped dropping ${filteredDiff.columnsToDrop.length} columns in table '${diff.tableName}': ${filteredDiff.columnsToDrop.join(', ')} (safe mode active)`);
331
- delete filteredDiff.columnsToDrop;
403
+ const safe = options.safe !== false;
404
+ const skip = (what, names, fix) => {
405
+ if (names.length) {
406
+ this.logger.logSkippedMigration(`[AutoSync] Skipped ${names.length} ${what} in table '${diff.tableName}': ${names.join(', ')} (${fix}).`);
332
407
  }
333
- if (filteredDiff.columnsToAlter?.length) {
334
- this.logger.logSkippedMigration(`[AutoSync] Skipped altering ${filteredDiff.columnsToAlter.length} columns in table '${diff.tableName}': ${filteredDiff.columnsToAlter.map((c) => c.to.name).join(', ')} (safe mode active). Use a migration or { safe: false } to apply.`);
335
- delete filteredDiff.columnsToAlter;
336
- }
337
- if (filteredDiff.primaryKey) {
338
- // Rewriting a key drops a constraint and rebuilds an index over the whole table, and fails
339
- // outright where the new columns are null on rows that already exist. Firmly not additive.
340
- this.logger.logSkippedMigration(`[AutoSync] Skipped changing the primary key of '${diff.tableName}' from (${filteredDiff.primaryKey.from.join(', ')}) to (${filteredDiff.primaryKey.to.join(', ')}) (safe mode active). Use a migration or { safe: false } to apply.`);
341
- delete filteredDiff.primaryKey;
342
- }
343
- if (filteredDiff.foreignKeysToAlter?.length) {
344
- // Altering one is dropping it and adding it back, so letting the add through while the drop
345
- // is held would emit `ADD CONSTRAINT` for a constraint the table still has.
346
- this.logger.logSkippedMigration(`[AutoSync] Skipped altering ${filteredDiff.foreignKeysToAlter.length} foreign keys in table '${diff.tableName}': ${filteredDiff.foreignKeysToAlter.map((fk) => fk.to.name).join(', ')} (safe mode active). Use a migration or { safe: false } to apply.`);
347
- delete filteredDiff.foreignKeysToAlter;
348
- }
349
- if (filteredDiff.indexesToDrop?.length) {
350
- // An index recreated under its old name is a drop and an add, held back together.
351
- const dropped = new Set(filteredDiff.indexesToDrop.map((index) => index.name));
352
- this.logger.logSkippedMigration(`[AutoSync] Skipped dropping ${dropped.size} indexes in table '${diff.tableName}': ${[...dropped].join(', ')} (safe mode active). Use a migration or { safe: false } to apply.`);
353
- filteredDiff.indexesToAdd = filteredDiff.indexesToAdd?.filter((index) => !dropped.has(index.name));
354
- delete filteredDiff.indexesToDrop;
408
+ };
409
+ const safeFix = 'safe mode active. Use a migration or { safe: false } to apply';
410
+ const additive = (what, changes, nameOf) => {
411
+ if (!safe) {
412
+ return changes;
355
413
  }
356
- delete filteredDiff.foreignKeysToDrop;
414
+ skip(`${what} changes`, sides(changes, 'from').map(nameOf), safeFix);
415
+ return nonEmpty((changes ?? []).filter((change) => change.from === undefined));
416
+ };
417
+ const columns = additive('column', diff.columns, (column) => column.name);
418
+ if (safe && diff.primaryKey) {
419
+ skip('primary key changes', [diff.tableName], safeFix);
357
420
  }
358
- if (!options.drop && filteredDiff.columnsToDrop?.length) {
359
- this.logger.logSkippedMigration(`[AutoSync] Skipped dropping ${filteredDiff.columnsToDrop.length} columns in table '${diff.tableName}' (drop: false). Use { drop: true } to apply.`);
360
- delete filteredDiff.columnsToDrop;
421
+ if (!options.drop) {
422
+ skip('column drops', dropped(columns).map((column) => column.name), 'drop: false. Use { drop: true } to apply');
361
423
  }
362
- return filteredDiff;
424
+ return {
425
+ ...diff,
426
+ primaryKey: safe ? undefined : diff.primaryKey,
427
+ columns: options.drop ? columns : nonEmpty((columns ?? []).filter((change) => change.to !== undefined)),
428
+ indexes: additive('index', diff.indexes, (index) => index.name),
429
+ foreignKeys: additive('foreign key', diff.foreignKeys, (foreignKey) => foreignKey.name ?? foreignKey.columns.join(', ')),
430
+ };
363
431
  }
364
432
  /** Runs the statements a generator wrote, in one transaction where the engine takes DDL in one. */
365
433
  async executeSyncStatements(statements, options) {
@@ -0,0 +1,18 @@
1
+ import type { Change, SchemaDiff } from '../type/index.js';
2
+ /** Each change's end on `side`, where it has one: what a drop half removes (`from`), or an add half creates (`to`). */
3
+ export declare function sides<T>(changes: readonly Change<T>[] | undefined, side: 'from' | 'to'): T[];
4
+ /** What the changes add: each `to` with no `from`. */
5
+ export declare function added<T>(changes?: readonly Change<T>[]): T[];
6
+ /** What the changes drop: each `from` with no `to`. */
7
+ export declare function dropped<T>(changes?: readonly Change<T>[]): T[];
8
+ /** The changes that alter an object in place, which only a column can. */
9
+ export declare function alterations<T>(changes?: readonly Change<T>[]): {
10
+ readonly from: T;
11
+ readonly to: T;
12
+ }[];
13
+ /** `items`, or nothing where it has none, so an empty change list is left off a diff. */
14
+ export declare function nonEmpty<T>(items: readonly T[]): readonly T[] | undefined;
15
+ /** `change` undone: an add becomes a drop, a drop an add, and an alter runs the other way. */
16
+ export declare function swap<T>({ from, to }: Change<T>): Change<T>;
17
+ /** `diff` undone: every change swapped, which is what a migration's `down` runs. */
18
+ export declare function reverseDiff(diff: SchemaDiff): SchemaDiff;
@@ -0,0 +1,37 @@
1
+ /** Each change's end on `side`, where it has one: what a drop half removes (`from`), or an add half creates (`to`). */
2
+ export function sides(changes, side) {
3
+ return (changes ?? []).flatMap((change) => {
4
+ const end = change[side];
5
+ return end === undefined ? [] : [end];
6
+ });
7
+ }
8
+ /** What the changes add: each `to` with no `from`. */
9
+ export function added(changes = []) {
10
+ return changes.flatMap(({ from, to }) => (from === undefined && to !== undefined ? [to] : []));
11
+ }
12
+ /** What the changes drop: each `from` with no `to`. */
13
+ export function dropped(changes = []) {
14
+ return changes.flatMap(({ from, to }) => (to === undefined && from !== undefined ? [from] : []));
15
+ }
16
+ /** The changes that alter an object in place, which only a column can. */
17
+ export function alterations(changes = []) {
18
+ return changes.flatMap(({ from, to }) => (from === undefined || to === undefined ? [] : [{ from, to }]));
19
+ }
20
+ /** `items`, or nothing where it has none, so an empty change list is left off a diff. */
21
+ export function nonEmpty(items) {
22
+ return items.length ? items : undefined;
23
+ }
24
+ /** `change` undone: an add becomes a drop, a drop an add, and an alter runs the other way. */
25
+ export function swap({ from, to }) {
26
+ return { from: to, to: from };
27
+ }
28
+ /** `diff` undone: every change swapped, which is what a migration's `down` runs. */
29
+ export function reverseDiff(diff) {
30
+ return {
31
+ ...diff,
32
+ primaryKey: diff.primaryKey && swap(diff.primaryKey),
33
+ columns: diff.columns?.map(swap),
34
+ indexes: diff.indexes?.map(swap),
35
+ foreignKeys: diff.foreignKeys?.map(swap),
36
+ };
37
+ }
@@ -3,7 +3,7 @@ import type { SchemaAST } from '../schema/schemaAST.js';
3
3
  import { type BuildSchemaASTOptions } from '../schema/schemaASTBuilder.js';
4
4
  import { type DiffOptions } from '../schema/schemaASTDiffer.js';
5
5
  import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
6
- import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, EntityWhereMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, Type } from '../type/index.js';
6
+ import type { ColumnSchema, CreateSchemaOptions, DialectFeatures, DropSchemaOptions, EntityMeta, InstalledTriggers, EntityWhereMeta, FieldMeta, FieldOptions, ForeignKeySchema, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, Type } from '../type/index.js';
7
7
  import type { AnyMigrationOperation, FullColumnDefinition, IndexDefinition, TableDefinition } from './builder/types.js';
8
8
  import { type IndexDdl, type TableDdl } from './ddl/index.js';
9
9
  /**
@@ -43,6 +43,17 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
43
43
  * cyclic. SQLite keeps them inline: it cannot add one later, and resolves a forward reference lazily.
44
44
  */
45
45
  generateCreateSchema(entities: readonly Type<object>[], options?: CreateSchemaOptions): string[];
46
+ /**
47
+ * The installed triggers on `entity`'s table it does not declare, and the declared ones not installed,
48
+ * compared by name alone: a name carries a hash of the trigger's SQL, so an edited one is a new name.
49
+ * Every trigger counts - the ones it authored, and one per event each stamp names.
50
+ */
51
+ private triggerChanges;
52
+ generateTriggers(entity: Type<object>, installed?: InstalledTriggers): string[];
53
+ generateTriggersDown(entity: Type<object>, installed?: InstalledTriggers): string[];
54
+ /** `dropped` taken off `entity`'s table and `created` put on, which is a reconcile read either way. */
55
+ private swapTriggers;
56
+ generateTriggerDrops(entity: Type<object>, names: readonly string[]): string[];
46
57
  /**
47
58
  * One statement per distinct schema the tables being created live in, in first-seen order. Only
48
59
  * the tables actually being created, so a narrowed `only` does not declare namespaces it is not
@@ -57,18 +68,19 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
57
68
  */
58
69
  private orderedTables;
59
70
  generateDropTable(tableName: string, options?: DropSchemaOptions): string;
71
+ /**
72
+ * The statements taking a table through `diff`, in the one order both directions need: whatever holds
73
+ * something down goes before it and comes back after it. A foreign key holds its columns and the key it
74
+ * points at, so it goes first and comes back last; the key holds its columns; and some engines drop an
75
+ * index along with its column, which would leave nothing to name. An alter is its drop, then its add.
76
+ */
60
77
  generateAlterTable(diff: SchemaDiff): string[];
61
78
  /** `ADD CONSTRAINT` for each of `foreignKeys`. */
62
79
  private addForeignKeyStatements;
63
- /** `DROP CONSTRAINT` for each of `constraintNames`, the mirror of {@link addForeignKeyStatements}. */
64
- private dropForeignKeyStatements;
65
- /** The `ALTER COLUMN` restating each of `columns`. */
66
- private alterColumnStatements;
67
80
  /** An index added to a table that may already have rows: its `CREATE`, then what the engine needs after. */
68
81
  private addIndexStatements;
69
- /** `DROP INDEX` for each of `indexes`, the mirror of {@link addIndexStatements}. */
70
- private dropIndexStatements;
71
- generateAlterTableDown(diff: SchemaDiff): string[];
82
+ /** A column added to a table that exists, and its comment where the engine keeps one apart. */
83
+ private addColumnStatements;
72
84
  generateCreateIndex(tableName: string, index: IndexSchema, options?: {
73
85
  ifNotExists?: boolean;
74
86
  }): string;
@@ -85,8 +97,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
85
97
  /**
86
98
  * The one place a column definition is spelled, so the `ColumnSchema` and `ColumnNode` paths cannot
87
99
  * drift. A key column states `NOT NULL` rather than leave it to the key: SQLite lets a key column hold
88
- * NULL otherwise, and SQL Server adds no key over a nullable column. `UNIQUE` is left to the key. An
89
- * enum's `CHECK` comes last, the only place MariaDB takes it.
100
+ * NULL otherwise, and SQL Server adds no key over a nullable column. Never `UNIQUE`: a unique column is
101
+ * a unique index, which the table creates beside it. An enum's `CHECK` comes last, the only place MariaDB takes it.
90
102
  */
91
103
  private renderColumn;
92
104
  /**
@@ -113,10 +125,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
113
125
  protected diffOptions(): DiffOptions;
114
126
  /** Spread, not copied field by field, so a field the node gains cannot go missing here. */
115
127
  private columnNodeToSchema;
116
- /**
117
- * Compare two default values for equality
118
- */
119
- protected isDefaultValueEqual(current: unknown, desired: unknown): boolean;
128
+ /** Whether a column's stored default is the one the entity declares, as this engine reprints it. */
129
+ readonly defaultsEqual: (desired: unknown, current: unknown) => boolean;
120
130
  generateCreateTableFromNode(table: TableNode, options?: {
121
131
  ifNotExists?: boolean;
122
132
  }): string[];
@@ -175,4 +185,4 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
175
185
  * The entities as an AST, named by `generator`'s resolvers rather than a naming strategy, which would
176
186
  * also rename an explicit `@Entity({ name })` and so compare each table under another name.
177
187
  */
178
- export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolveTableAlias' | 'resolveSchema' | 'resolveColumnName' | 'compileDdl' | 'compileIndexPredicate'>, entities: readonly Type<object>[], options?: Pick<BuildSchemaASTOptions, 'defaultForeignKeyAction' | 'textScoreIndexes'>): SchemaAST;
188
+ export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolveTableAlias' | 'resolveSchema' | 'resolveColumnName' | 'compileDdl' | 'compileIndexPredicate'>, entities: readonly Type<object>[], options?: Pick<BuildSchemaASTOptions, 'defaultForeignKeyAction' | 'textScoreIndexes' | 'vectorIndexRequiresNotNull'>): SchemaAST;