uql-orm 0.21.0 → 0.23.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 (214) hide show
  1. package/README.md +5 -4
  2. package/dist/browser/uql-browser.min.js.map +3 -3
  3. package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
  4. package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
  5. package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
  6. package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
  7. package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
  8. package/dist/cockroachdb/cockroachDialect.js +33 -18
  9. package/dist/d1/d1Querier.d.ts +4 -3
  10. package/dist/d1/d1Querier.js +0 -3
  11. package/dist/d1/d1SqliteDialect.d.ts +7 -0
  12. package/dist/d1/d1SqliteDialect.js +9 -0
  13. package/dist/dialect/abstractDialect.d.ts +8 -3
  14. package/dist/dialect/abstractDialect.js +9 -4
  15. package/dist/dialect/abstractSqlDialect.d.ts +49 -8
  16. package/dist/dialect/abstractSqlDialect.js +95 -47
  17. package/dist/dialect/index.d.ts +1 -0
  18. package/dist/dialect/index.js +1 -0
  19. package/dist/dialect/indexSqlDialect.d.ts +57 -0
  20. package/dist/dialect/indexSqlDialect.js +101 -0
  21. package/dist/dialect/mysqlLikeSqlDialect.d.ts +26 -1
  22. package/dist/dialect/mysqlLikeSqlDialect.js +57 -1
  23. package/dist/dialect/pgLikeSqlDialect.d.ts +37 -22
  24. package/dist/dialect/pgLikeSqlDialect.js +97 -68
  25. package/dist/dialect/vectorCast.d.ts +21 -0
  26. package/dist/dialect/vectorCast.js +28 -0
  27. package/dist/dialect/vectorSqlDialect.d.ts +10 -3
  28. package/dist/dialect/vectorSqlDialect.js +19 -8
  29. package/dist/entity/decorator/bag.d.ts +35 -0
  30. package/dist/entity/decorator/bag.js +54 -0
  31. package/dist/entity/decorator/entity.d.ts +28 -2
  32. package/dist/entity/decorator/entity.js +40 -2
  33. package/dist/entity/decorator/members.d.ts +51 -0
  34. package/dist/entity/decorator/members.js +51 -0
  35. package/dist/entity/index.d.ts +3 -1
  36. package/dist/entity/index.js +3 -1
  37. package/dist/entity/metadata/definition.d.ts +23 -8
  38. package/dist/entity/metadata/definition.js +56 -100
  39. package/dist/http/contract.js +1 -2
  40. package/dist/http/handler.js +5 -26
  41. package/dist/http/query.js +1 -1
  42. package/dist/libsql/libsqlDialect.d.ts +12 -2
  43. package/dist/libsql/libsqlDialect.js +14 -2
  44. package/dist/libsql/libsqlQuerier.d.ts +9 -22
  45. package/dist/libsql/libsqlQuerier.js +9 -85
  46. package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
  47. package/dist/libsql/libsqlQuerierPool.js +17 -15
  48. package/dist/maria/mariaDialect.d.ts +26 -4
  49. package/dist/maria/mariaDialect.js +54 -15
  50. package/dist/migrate/acquireQuerierForMigrations.d.ts +13 -1
  51. package/dist/migrate/acquireQuerierForMigrations.js +28 -0
  52. package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
  53. package/dist/migrate/builder/migrationBuilder.js +58 -76
  54. package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
  55. package/dist/migrate/builder/splitSqlStatements.js +0 -2
  56. package/dist/migrate/builder/tableBuilder.d.ts +12 -2
  57. package/dist/migrate/builder/tableBuilder.js +71 -119
  58. package/dist/migrate/builder/types.d.ts +30 -41
  59. package/dist/migrate/cli-config.js +24 -8
  60. package/dist/migrate/cli.d.ts +3 -2
  61. package/dist/migrate/cli.js +26 -49
  62. package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
  63. package/dist/migrate/codegen/entityCodeGenerator.js +8 -67
  64. package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
  65. package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
  66. package/dist/migrate/codegen/index.d.ts +0 -3
  67. package/dist/migrate/codegen/index.js +0 -6
  68. package/dist/migrate/drift/driftDetector.d.ts +10 -1
  69. package/dist/migrate/drift/driftDetector.js +22 -5
  70. package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
  71. package/dist/migrate/generator/indexNodeToSchema.js +14 -0
  72. package/dist/migrate/generator/mongoCommand.d.ts +57 -0
  73. package/dist/migrate/generator/mongoCommand.js +26 -0
  74. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
  75. package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
  76. package/dist/migrate/index.d.ts +0 -1
  77. package/dist/migrate/index.js +0 -1
  78. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +30 -11
  79. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +61 -57
  80. package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
  81. package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
  82. package/dist/migrate/introspection/mongoIntrospector.js +9 -15
  83. package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
  84. package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
  85. package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
  86. package/dist/migrate/introspection/postgresIntrospector.js +4 -10
  87. package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
  88. package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
  89. package/dist/migrate/migrator.d.ts +23 -3
  90. package/dist/migrate/migrator.js +101 -150
  91. package/dist/migrate/schemaGenerator.d.ts +26 -37
  92. package/dist/migrate/schemaGenerator.js +69 -174
  93. package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
  94. package/dist/migrate/schemaGeneratorAsync.js +3 -3
  95. package/dist/migrate/storage/databaseStorage.d.ts +2 -0
  96. package/dist/migrate/storage/databaseStorage.js +12 -27
  97. package/dist/mongo/mongoDialect.d.ts +2 -0
  98. package/dist/mongo/mongoDialect.js +14 -3
  99. package/dist/mongo/mongodbQuerier.js +171 -229
  100. package/dist/mysql/mysqlDialect.d.ts +8 -0
  101. package/dist/mysql/mysqlDialect.js +13 -0
  102. package/dist/nestjs/uqlContextInterceptor.js +58 -22
  103. package/dist/nestjs/uqlModule.d.ts +2 -11
  104. package/dist/nestjs/uqlModule.js +93 -44
  105. package/dist/postgres/postgresDialect.js +2 -2
  106. package/dist/querier/abstractQuerier.d.ts +28 -0
  107. package/dist/querier/abstractQuerier.js +47 -22
  108. package/dist/querier/abstractQuerierPool.d.ts +3 -0
  109. package/dist/querier/abstractQuerierPool.js +5 -3
  110. package/dist/querier/abstractSqlQuerier.d.ts +1 -3
  111. package/dist/querier/abstractSqlQuerier.js +48 -96
  112. package/dist/querier/index.d.ts +3 -1
  113. package/dist/querier/index.js +3 -1
  114. package/dist/querier/querierContext.browser.d.ts +12 -0
  115. package/dist/querier/querierContext.browser.js +18 -0
  116. package/dist/querier/querierContext.d.ts +22 -0
  117. package/dist/querier/querierContext.js +42 -0
  118. package/dist/querier/queryError.d.ts +22 -0
  119. package/dist/querier/queryError.js +20 -0
  120. package/dist/querier/transactional.d.ts +26 -0
  121. package/dist/querier/transactional.js +43 -0
  122. package/dist/schema/canonicalType.d.ts +14 -2
  123. package/dist/schema/canonicalType.js +41 -31
  124. package/dist/schema/index.d.ts +1 -1
  125. package/dist/schema/schemaASTBuilder.d.ts +9 -2
  126. package/dist/schema/schemaASTBuilder.js +58 -49
  127. package/dist/schema/types.d.ts +10 -58
  128. package/dist/sqlite/abstractSqliteQuerier.d.ts +46 -0
  129. package/dist/sqlite/abstractSqliteQuerier.js +44 -0
  130. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
  131. package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
  132. package/dist/sqlite/hranaQuerier.d.ts +54 -0
  133. package/dist/sqlite/hranaQuerier.js +68 -0
  134. package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
  135. package/dist/sqlite/hranaQuerierPool.js +25 -0
  136. package/dist/sqlite/index.d.ts +3 -1
  137. package/dist/sqlite/index.js +3 -1
  138. package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
  139. package/dist/sqlite/localSqliteQuerierPool.js +34 -0
  140. package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
  141. package/dist/sqlite/nodeSqliteAdapter.js +28 -0
  142. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
  143. package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
  144. package/dist/sqlite/sqliteDialect.d.ts +18 -5
  145. package/dist/sqlite/sqliteDialect.js +23 -36
  146. package/dist/sqlite/sqliteQuerier.d.ts +16 -9
  147. package/dist/sqlite/sqliteQuerier.js +4 -27
  148. package/dist/sqlite/sqliteQuerierPool.d.ts +11 -14
  149. package/dist/sqlite/sqliteQuerierPool.js +16 -24
  150. package/dist/turso/index.d.ts +3 -0
  151. package/dist/turso/index.js +3 -0
  152. package/dist/turso/local.d.ts +3 -0
  153. package/dist/turso/local.js +3 -0
  154. package/dist/turso/tursoDialect.d.ts +15 -0
  155. package/dist/turso/tursoDialect.js +18 -0
  156. package/dist/turso/tursoLocalQuerier.d.ts +25 -0
  157. package/dist/turso/tursoLocalQuerier.js +20 -0
  158. package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
  159. package/dist/turso/tursoLocalQuerierPool.js +39 -0
  160. package/dist/turso/tursoQuerier.d.ts +10 -0
  161. package/dist/turso/tursoQuerier.js +10 -0
  162. package/dist/turso/tursoQuerierPool.d.ts +39 -0
  163. package/dist/turso/tursoQuerierPool.js +38 -0
  164. package/dist/type/config.d.ts +0 -6
  165. package/dist/type/dialect.d.ts +12 -4
  166. package/dist/type/dialect.js +7 -1
  167. package/dist/type/entity.d.ts +154 -26
  168. package/dist/type/migration.d.ts +32 -23
  169. package/dist/type/querier.d.ts +6 -0
  170. package/dist/type/vector.d.ts +5 -2
  171. package/dist/util/hook.util.js +1 -1
  172. package/dist/util/index.d.ts +1 -0
  173. package/dist/util/index.js +1 -0
  174. package/dist/util/indexColumn.util.d.ts +6 -0
  175. package/dist/util/indexColumn.util.js +26 -0
  176. package/package.json +21 -16
  177. package/dist/entity/decorator/field.d.ts +0 -2
  178. package/dist/entity/decorator/field.js +0 -7
  179. package/dist/entity/decorator/filter.d.ts +0 -7
  180. package/dist/entity/decorator/filter.js +0 -11
  181. package/dist/entity/decorator/hook.d.ts +0 -7
  182. package/dist/entity/decorator/hook.js +0 -14
  183. package/dist/entity/decorator/id.d.ts +0 -2
  184. package/dist/entity/decorator/id.js +0 -7
  185. package/dist/entity/decorator/index-decorator.d.ts +0 -29
  186. package/dist/entity/decorator/index-decorator.js +0 -26
  187. package/dist/entity/decorator/index.d.ts +0 -8
  188. package/dist/entity/decorator/index.js +0 -8
  189. package/dist/entity/decorator/relation.d.ts +0 -8
  190. package/dist/entity/decorator/relation.js +0 -19
  191. package/dist/migrate/codegen/entityMerger.d.ts +0 -114
  192. package/dist/migrate/codegen/entityMerger.js +0 -293
  193. package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
  194. package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
  195. package/dist/migrate/codegen/smartRelationDetector.d.ts +0 -47
  196. package/dist/migrate/codegen/smartRelationDetector.js +0 -134
  197. package/dist/migrate/generator/index.d.ts +0 -2
  198. package/dist/migrate/generator/index.js +0 -2
  199. package/dist/migrate/sync/index.d.ts +0 -6
  200. package/dist/migrate/sync/index.js +0 -6
  201. package/dist/migrate/sync/schemaSync.d.ts +0 -131
  202. package/dist/migrate/sync/schemaSync.js +0 -259
  203. package/dist/querier/decorator/index.d.ts +0 -4
  204. package/dist/querier/decorator/index.js +0 -4
  205. package/dist/querier/decorator/injectQuerier.d.ts +0 -3
  206. package/dist/querier/decorator/injectQuerier.js +0 -33
  207. package/dist/querier/decorator/log.d.ts +0 -32
  208. package/dist/querier/decorator/log.js +0 -52
  209. package/dist/querier/decorator/serialized.d.ts +0 -6
  210. package/dist/querier/decorator/serialized.js +0 -13
  211. package/dist/querier/decorator/transactional.d.ts +0 -6
  212. package/dist/querier/decorator/transactional.js +0 -48
  213. package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
  214. package/dist/sqlite/betterSqlite3Dialect.js +0 -9
@@ -5,8 +5,9 @@ import { getEntities, getMeta } from '../entity/index.js';
5
5
  import { introspectSchema } from '../schema/index.js';
6
6
  import { isKnownMigratorDialect, isSqlQuerier } from '../type/index.js';
7
7
  import { LoggerWrapper } from '../util/index.js';
8
- import { acquireQuerierForMigrations } from './acquireQuerierForMigrations.js';
8
+ import { withQuerierForMigrations, withSqlQuerierForMigrations } from './acquireQuerierForMigrations.js';
9
9
  import { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCalls, } from './codegen/migrationFile.js';
10
+ import { runMongoCommand } from './generator/mongoCommand.js';
10
11
  import { MongoSchemaIntrospector, MysqlSchemaIntrospector, PostgresSchemaIntrospector, SqliteSchemaIntrospector, } from './introspection/index.js';
11
12
  import { createSchemaGenerator } from './schemaGenerator.js';
12
13
  import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
@@ -32,12 +33,12 @@ export class Migrator {
32
33
  dialectName;
33
34
  schemaGenerator;
34
35
  schemaIntrospector;
35
- _namingStrategy;
36
+ _defaultForeignKeyAction;
36
37
  _mongoSchemaLoadPromise;
37
38
  constructor(pool, options = {}) {
38
39
  this.pool = pool;
39
40
  this.dialectName = pool.dialect.dialectName ?? 'postgres';
40
- this._namingStrategy = options.namingStrategy;
41
+ this._defaultForeignKeyAction = options.defaultForeignKeyAction;
41
42
  this.storage =
42
43
  options.storage ??
43
44
  new DatabaseMigrationStorage(pool, {
@@ -48,8 +49,7 @@ export class Migrator {
48
49
  this._entities = options.entities;
49
50
  this.schemaIntrospector = this.createIntrospector();
50
51
  this.schemaGenerator =
51
- options.schemaGenerator ??
52
- (this.dialectName === 'mongodb' ? undefined : this.createGenerator(options.namingStrategy));
52
+ options.schemaGenerator ?? (this.dialectName === 'mongodb' ? undefined : this.createGenerator());
53
53
  }
54
54
  /** Loads MongoDB schema generator on first use; SQL generators are set in the constructor (or via {@link setSchemaGenerator}). */
55
55
  async ensureSchemaGenerator() {
@@ -57,7 +57,7 @@ export class Migrator {
57
57
  return;
58
58
  }
59
59
  if (!this._mongoSchemaLoadPromise) {
60
- this._mongoSchemaLoadPromise = createSchemaGeneratorAsync(this.pool.dialect, this._namingStrategy).then((gen) => {
60
+ this._mongoSchemaLoadPromise = createSchemaGeneratorAsync(this.pool.dialect, this._defaultForeignKeyAction).then((gen) => {
61
61
  if (gen) {
62
62
  this.schemaGenerator = gen;
63
63
  }
@@ -91,11 +91,11 @@ export class Migrator {
91
91
  return undefined;
92
92
  }
93
93
  }
94
- createGenerator(namingStrategy) {
94
+ createGenerator() {
95
95
  if (!isKnownMigratorDialect(this.dialectName)) {
96
96
  return undefined;
97
97
  }
98
- return createSchemaGenerator(this.pool.dialect, namingStrategy);
98
+ return createSchemaGenerator(this.pool.dialect, this._defaultForeignKeyAction);
99
99
  }
100
100
  /**
101
101
  * Get all discovered migrations from the migrations directory
@@ -185,49 +185,42 @@ export class Migrator {
185
185
  */
186
186
  async runMigration(migration, direction) {
187
187
  const startTime = Date.now();
188
- const querier = await acquireQuerierForMigrations(this.pool);
189
- if (!isSqlQuerier(querier)) {
190
- await querier.release();
191
- throw new Error('Migrator requires a SQL-based querier');
192
- }
193
- try {
194
- this.logger.logMigration(`${direction === 'up' ? 'Running' : 'Reverting'} migration: ${migration.name}`);
195
- await querier.beginTransaction();
196
- if (direction === 'up') {
197
- await migration.up(querier);
198
- // Log within the same transaction
199
- await this.storage.logWithQuerier(querier, migration.name);
188
+ return withSqlQuerierForMigrations(this.pool, 'Migrator', async (querier) => {
189
+ try {
190
+ this.logger.logMigration(`${direction === 'up' ? 'Running' : 'Reverting'} migration: ${migration.name}`);
191
+ await querier.transaction(async () => {
192
+ if (direction === 'up') {
193
+ await migration.up(querier);
194
+ // Log within the same transaction
195
+ await this.storage.logWithQuerier(querier, migration.name);
196
+ }
197
+ else {
198
+ await migration.down(querier);
199
+ // Unlog within the same transaction
200
+ await this.storage.unlogWithQuerier(querier, migration.name);
201
+ }
202
+ });
203
+ const duration = Date.now() - startTime;
204
+ this.logger.logMigration(`Migration ${migration.name} ${direction === 'up' ? 'applied' : 'reverted'} in ${duration}ms`);
205
+ return {
206
+ name: migration.name,
207
+ direction,
208
+ duration,
209
+ success: true,
210
+ };
200
211
  }
201
- else {
202
- await migration.down(querier);
203
- // Unlog within the same transaction
204
- await this.storage.unlogWithQuerier(querier, migration.name);
212
+ catch (error) {
213
+ const duration = Date.now() - startTime;
214
+ this.logger.logError(`Migration ${migration.name} failed: ${error.message}`, error);
215
+ return {
216
+ name: migration.name,
217
+ direction,
218
+ duration,
219
+ success: false,
220
+ error: error,
221
+ };
205
222
  }
206
- await querier.commitTransaction();
207
- const duration = Date.now() - startTime;
208
- this.logger.logMigration(`Migration ${migration.name} ${direction === 'up' ? 'applied' : 'reverted'} in ${duration}ms`);
209
- return {
210
- name: migration.name,
211
- direction,
212
- duration,
213
- success: true,
214
- };
215
- }
216
- catch (error) {
217
- await querier.rollbackTransaction();
218
- const duration = Date.now() - startTime;
219
- this.logger.logError(`Migration ${migration.name} failed: ${error.message}`, error);
220
- return {
221
- name: migration.name,
222
- direction,
223
- duration,
224
- success: false,
225
- error: error,
226
- };
227
- }
228
- finally {
229
- await querier.release();
230
- }
223
+ });
231
224
  }
232
225
  /**
233
226
  * Generate a new migration file
@@ -251,26 +244,18 @@ export class Migrator {
251
244
  * Generate a migration based on entity schema differences
252
245
  */
253
246
  async generateFromEntities(name) {
254
- await this.ensureSchemaGenerator();
255
- if (!this.schemaGenerator) {
256
- throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
257
- }
258
- const diffs = await this.getDiffs();
259
247
  const upStatements = [];
260
248
  const downStatements = [];
261
- for (const diff of diffs) {
249
+ for (const { diff, entity } of await this.pendingDiffs()) {
262
250
  if (diff.type === 'create') {
263
- const entity = await this.findEntityForTable(diff.tableName);
264
251
  if (entity) {
265
- upStatements.push(...this.schemaGenerator.generateCreateTable(entity));
266
- downStatements.push(this.schemaGenerator.generateDropTable(entity));
252
+ upStatements.push(...this.generator.generateCreateTable(entity));
253
+ downStatements.push(this.generator.generateDropTable(diff.tableName, { ifExists: true }));
267
254
  }
268
255
  }
269
256
  else if (diff.type === 'alter') {
270
- const alterStatements = this.schemaGenerator.generateAlterTable(diff);
271
- upStatements.push(...alterStatements);
272
- const alterDownStatements = this.schemaGenerator.generateAlterTableDown(diff);
273
- downStatements.push(...alterDownStatements);
257
+ upStatements.push(...this.generator.generateAlterTable(diff));
258
+ downStatements.push(...this.generator.generateAlterTableDown(diff));
274
259
  }
275
260
  }
276
261
  if (upStatements.length === 0) {
@@ -342,70 +327,76 @@ export class Migrator {
342
327
  */
343
328
  async syncForce() {
344
329
  await this.ensureSchemaGenerator();
345
- if (!this.schemaGenerator) {
346
- throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
347
- }
348
- const querier = await acquireQuerierForMigrations(this.pool);
349
- if (!isSqlQuerier(querier)) {
350
- await querier.release();
351
- throw new Error('Migrator requires a SQL-based querier');
352
- }
353
- try {
354
- await querier.beginTransaction();
330
+ await withSqlQuerierForMigrations(this.pool, 'Migrator', (querier) => querier.transaction(async () => {
355
331
  // Drop all tables first (in reverse order for foreign keys)
356
332
  for (const entity of [...this.entities].reverse()) {
357
- const dropSql = this.schemaGenerator.generateDropTable(entity);
333
+ const tableName = this.generator.resolveTableName(entity, getMeta(entity));
334
+ const dropSql = this.generator.generateDropTable(tableName, { ifExists: true });
358
335
  this.logger.logSchema(`Executing: ${dropSql}`);
359
336
  await querier.run(dropSql);
360
337
  }
361
338
  // Create all tables
362
339
  for (const entity of this.entities) {
363
- const createStmts = this.schemaGenerator.generateCreateTable(entity);
340
+ const createStmts = this.generator.generateCreateTable(entity);
364
341
  for (const createSql of createStmts) {
365
342
  this.logger.logSchema(`Executing: ${createSql}`);
366
343
  await querier.run(createSql);
367
344
  }
368
345
  }
369
- await querier.commitTransaction();
370
- this.logger.logSchema('Schema sync (force) completed');
371
- }
372
- catch (error) {
373
- await querier.rollbackTransaction();
374
- throw error;
375
- }
376
- finally {
377
- await querier.release();
378
- }
346
+ }));
347
+ this.logger.logSchema('Schema sync (force) completed');
379
348
  }
380
349
  /**
381
350
  * Safely synchronizes the schema by only adding missing tables and columns.
382
351
  */
383
352
  async autoSync(options = {}) {
384
- await this.ensureSchemaGenerator();
385
- if (!this.schemaGenerator || !this.schemaIntrospector) {
386
- throw new Error('Schema generator and introspector must be set');
353
+ const statements = await this.planSync(options);
354
+ if (statements.length === 0) {
355
+ if (options.logging)
356
+ this.logger.logSchema('Schema is already in sync.');
357
+ return;
387
358
  }
388
- const diffs = await this.getDiffs();
359
+ await this.executeSyncStatements(statements, options);
360
+ }
361
+ /**
362
+ * The DDL {@link autoSync} would run, without running it. Separate so `--dry-run` shows the real
363
+ * statements rather than a summary of a second, differently-computed diff.
364
+ */
365
+ async planSync(options = {}) {
389
366
  const statements = [];
390
- for (const diff of diffs) {
367
+ for (const { diff, entity } of await this.pendingDiffs()) {
391
368
  if (diff.type === 'create') {
392
- const entity = await this.findEntityForTable(diff.tableName);
393
- if (entity) {
394
- statements.push(...this.schemaGenerator.generateCreateTable(entity));
395
- }
369
+ if (entity)
370
+ statements.push(...this.generator.generateCreateTable(entity));
396
371
  }
397
372
  else if (diff.type === 'alter') {
398
- const filteredDiff = this.filterDiff(diff, options);
399
- const alterStatements = this.schemaGenerator.generateAlterTable(filteredDiff);
400
- statements.push(...alterStatements);
373
+ statements.push(...this.generator.generateAlterTable(this.filterDiff(diff, options)));
401
374
  }
402
375
  }
403
- if (statements.length === 0) {
404
- if (options.logging)
405
- this.logger.logSchema('Schema is already in sync.');
406
- return;
376
+ return statements;
377
+ }
378
+ /**
379
+ * Each pending diff with the entity it came from, since resolving that is async and every caller
380
+ * needs it. What to emit stays with the caller: a sync narrows the forward direction to what the
381
+ * caller allows and never asks for the rollback, which on SQLite cannot even be expressed (no
382
+ * `ALTER COLUMN`), so computing it eagerly for everyone would throw there.
383
+ */
384
+ async pendingDiffs() {
385
+ const diffs = await this.getDiffs();
386
+ return Promise.all(diffs.map(async (diff) => ({
387
+ diff,
388
+ entity: diff.type === 'create' ? await this.findEntityForTable(diff.tableName) : undefined,
389
+ })));
390
+ }
391
+ /**
392
+ * The schema generator. A getter because MongoDB's loads lazily (see {@link ensureSchemaGenerator}),
393
+ * so every caller had to repeat the same assertion after awaiting it.
394
+ */
395
+ get generator() {
396
+ if (!this.schemaGenerator) {
397
+ throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
407
398
  }
408
- await this.executeSyncStatements(statements, options);
399
+ return this.schemaGenerator;
409
400
  }
410
401
  filterDiff(diff, options) {
411
402
  const filteredDiff = { ...diff };
@@ -430,69 +421,29 @@ export class Migrator {
430
421
  return filteredDiff;
431
422
  }
432
423
  async executeSyncStatements(statements, options) {
433
- const querier = await acquireQuerierForMigrations(this.pool);
434
- try {
435
- if (this.dialectName === 'mongodb') {
436
- await this.executeMongoSyncStatements(statements, options, querier);
437
- }
438
- else {
439
- await this.executeSqlSyncStatements(statements, options, querier);
440
- }
441
- if (options.logging)
442
- this.logger.logSchema('Schema synchronization completed');
443
- }
444
- catch (error) {
445
- if (this.dialectName !== 'mongodb' && isSqlQuerier(querier)) {
446
- await querier.rollbackTransaction();
447
- }
448
- throw error;
449
- }
450
- finally {
451
- await querier.release();
452
- }
424
+ // Mongo creates collections and indexes outside any transaction, so only the SQL path opens one.
425
+ await withQuerierForMigrations(this.pool, (querier) => this.dialectName === 'mongodb'
426
+ ? this.executeMongoSyncStatements(statements, options, querier)
427
+ : querier.transaction(() => this.executeSqlSyncStatements(statements, options, querier)));
428
+ if (options.logging)
429
+ this.logger.logSchema('Schema synchronization completed');
453
430
  }
454
431
  async executeMongoSyncStatements(statements, options, querier) {
455
- const db = querier.db;
456
- for (const stmt of statements) {
457
- const cmd = JSON.parse(stmt);
432
+ for (const statement of statements) {
458
433
  if (options.logging)
459
- this.logger.logSchema(`Executing MongoDB: ${stmt}`);
460
- const collectionName = cmd.name || cmd.collection;
461
- if (!collectionName) {
462
- throw new Error(`MongoDB command missing collection name: ${stmt}`);
463
- }
464
- const collection = db.collection(collectionName);
465
- if (cmd.action === 'createCollection') {
466
- await db.createCollection(cmd.name);
467
- if (cmd.indexes?.length) {
468
- for (const idx of cmd.indexes) {
469
- const key = Object.fromEntries(idx.columns.map((c) => [c, 1]));
470
- await collection.createIndex(key, { unique: idx.unique, name: idx.name });
471
- }
472
- }
473
- }
474
- else if (cmd.action === 'dropCollection') {
475
- await collection.drop();
476
- }
477
- else if (cmd.action === 'createIndex') {
478
- await collection.createIndex(cmd.key, cmd.options);
479
- }
480
- else if (cmd.action === 'dropIndex') {
481
- await collection.dropIndex(cmd.name);
482
- }
434
+ this.logger.logSchema(`Executing MongoDB: ${statement}`);
435
+ await runMongoCommand(querier.db, statement);
483
436
  }
484
437
  }
485
438
  async executeSqlSyncStatements(statements, options, querier) {
486
439
  if (!isSqlQuerier(querier)) {
487
440
  throw new Error('Migrator requires a SQL-based querier for this dialect');
488
441
  }
489
- await querier.beginTransaction();
490
442
  for (const sql of statements) {
491
443
  if (options.logging)
492
444
  this.logger.logSchema(`Executing: ${sql}`);
493
445
  await querier.run(sql);
494
446
  }
495
- await querier.commitTransaction();
496
447
  }
497
448
  /**
498
449
  * Get migration status
@@ -1,12 +1,12 @@
1
1
  import { type AbstractDialect, AbstractSqlDialect } from '../dialect/index.js';
2
2
  import type { CanonicalType, ColumnNode, ForeignKeyAction, IndexNode, TableNode } from '../schema/types.js';
3
- import type { ColumnSchema, DialectFeatures, EntityMeta, FieldOptions, IndexSchema, NamingStrategy, SchemaDiff, SchemaGenerator, Type } from '../type/index.js';
3
+ import type { ColumnSchema, DialectFeatures, EntityMeta, FieldOptions, IndexSchema, NamingStrategy, SchemaDiff, SqlDdlGenerator, Type } from '../type/index.js';
4
4
  import type { FullColumnDefinition, TableDefinition, TableForeignKeyDefinition } from './builder/types.js';
5
5
  /**
6
6
  * Unified SQL schema generator.
7
7
  * Parameterized by dialect to handle Postgres, MySQL, MariaDB, and SQLite.
8
8
  */
9
- export declare class SqlSchemaGenerator implements SchemaGenerator {
9
+ export declare class SqlSchemaGenerator implements SqlDdlGenerator {
10
10
  protected readonly dialect: AbstractSqlDialect;
11
11
  protected readonly defaultForeignKeyAction: ForeignKeyAction;
12
12
  constructor(dialect: AbstractSqlDialect, defaultForeignKeyAction?: ForeignKeyAction);
@@ -26,15 +26,14 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
26
26
  * Convert FieldOptions to CanonicalType using the unified type system.
27
27
  */
28
28
  protected getCanonicalType(field: FieldOptions, fieldType?: unknown): CanonicalType;
29
- /**
30
- * Convert CanonicalType to SQL type string for this dialect.
31
- * Also handles legacy string types for backward compatibility.
32
- */
33
- protected canonicalTypeToSql(type: CanonicalType | string): string;
29
+ protected canonicalTypeToSql(type: CanonicalType): string;
34
30
  generateCreateTable<E>(entity: Type<E>, options?: {
35
31
  ifNotExists?: boolean;
36
32
  }): string[];
37
- generateDropTable<E>(entity: Type<E>): string;
33
+ generateDropTable(tableName: string, options?: {
34
+ ifExists?: boolean;
35
+ cascade?: boolean;
36
+ }): string;
38
37
  generateAlterTable(diff: SchemaDiff): string[];
39
38
  generateAlterTableDown(diff: SchemaDiff): string[];
40
39
  generateCreateIndex(tableName: string, index: IndexSchema, options?: {
@@ -42,25 +41,24 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
42
41
  }): string;
43
42
  generateDropIndex(tableName: string, indexName: string): string;
44
43
  /**
45
- * Generate column definition from a ColumnSchema object
44
+ * Generate a column definition from a {@link ColumnSchema}, whose type is the engine's own spelling
45
+ * and may already carry its precision (or even `PRIMARY KEY`, for a serial).
46
46
  */
47
47
  generateColumnDefinitionFromSchema(column: ColumnSchema, options?: {
48
48
  includePrimaryKey?: boolean;
49
49
  includeUnique?: boolean;
50
50
  }): string;
51
- getSqlType(field: FieldOptions, fieldType?: unknown): string;
52
51
  /**
53
- * Get the boolean type for this database
52
+ * The one place a column definition is spelled. Both callers reach it - the `ColumnSchema` path above
53
+ * and the `ColumnNode` path below - because the clause order and the "no NOT NULL on a primary key"
54
+ * rules are the same everywhere, and having them written twice is how the two paths drifted.
54
55
  */
55
- getBooleanType(): string;
56
+ private renderColumn;
57
+ getSqlType(field: FieldOptions, fieldType?: unknown): string;
56
58
  /**
57
59
  * Generate ALTER COLUMN statements (database-specific)
58
60
  */
59
61
  generateAlterColumnStatements(tableName: string, column: ColumnSchema, newDefinition: string): string[];
60
- /**
61
- * Get table options (e.g., ENGINE for MySQL)
62
- */
63
- getTableOptions<E>(_meta: EntityMeta<E>): string;
64
62
  /**
65
63
  * Generate column comment clause (if supported)
66
64
  */
@@ -75,7 +73,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
75
73
  diffSchema<E>(entity: Type<E>, currentTable: TableNode | undefined): SchemaDiff | undefined;
76
74
  private columnNodeToSchema;
77
75
  /**
78
- * Convert field options to ColumnSchema
76
+ * Convert field options to ColumnSchema. Both sides of a diff are the engine's SQL spelling: what it
77
+ * would create for this field, against what it reported for the existing column.
79
78
  */
80
79
  protected fieldToColumnSchema<E>(fieldKey: string, field: FieldOptions, meta: EntityMeta<E>): ColumnSchema;
81
80
  /**
@@ -83,7 +82,13 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
83
82
  */
84
83
  protected columnsNeedAlteration(current: ColumnSchema, desired: ColumnSchema): boolean;
85
84
  /**
86
- * Compare two column types for equality using the canonical type system
85
+ * Whether two column types are the same *as this engine stores them*.
86
+ *
87
+ * Both sides are SQL spellings, parsed back to canonical so that `INT` and `INTEGER`, or `DATETIME`
88
+ * and `TIMESTAMP`, do not read as a change. Do not "simplify" this into comparing the entity's
89
+ * canonical type against the column's: several canonical types share one storage type per engine
90
+ * (`boolean` is `TINYINT(1)` on MySQL and `INTEGER` on SQLite), so that comparison reports an
91
+ * alteration for those columns on every single sync.
87
92
  */
88
93
  protected isTypeEqual(current: ColumnSchema, desired: ColumnSchema): boolean;
89
94
  /**
@@ -94,14 +99,10 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
94
99
  ifNotExists?: boolean;
95
100
  }): string[];
96
101
  /**
97
- * Generate a column definition from a ColumnNode.
102
+ * Generate a column definition from a ColumnNode. A composite key is declared as a table constraint,
103
+ * so only a lone primary key column carries `PRIMARY KEY` inline.
98
104
  */
99
105
  protected generateColumnFromNode(col: ColumnNode): string;
100
- /**
101
- * Generate an inline VECTOR INDEX clause for use inside CREATE TABLE.
102
- * Syntax: `VECTOR INDEX (col) M=n DISTANCE=metric`
103
- */
104
- private generateInlineVectorIndex;
105
106
  /**
106
107
  * Generate CREATE INDEX SQL from an IndexNode.
107
108
  * Delegates to `generateCreateIndex` for unified SQL assembly.
@@ -109,26 +110,14 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
109
110
  generateCreateIndexFromNode(index: IndexNode, options?: {
110
111
  ifNotExists: boolean;
111
112
  }): string;
112
- /**
113
- * Generate DROP TABLE SQL from a TableNode.
114
- */
115
- generateDropTableFromNode(table: TableNode, options?: {
116
- ifExists?: boolean;
117
- }): string;
118
113
  generateCreateTableFromDefinition(table: TableDefinition, options?: {
119
114
  ifNotExists?: boolean;
120
115
  }): string[];
121
- generateDropTableSql(tableName: string, options?: {
122
- ifExists?: boolean;
123
- cascade?: boolean;
124
- }): string;
125
116
  generateRenameTableSql(oldName: string, newName: string): string;
126
117
  generateAddColumnSql(tableName: string, column: FullColumnDefinition): string;
127
118
  generateAlterColumnSql(tableName: string, columnName: string, column: FullColumnDefinition): string;
128
119
  generateDropColumnSql(tableName: string, columnName: string): string;
129
120
  generateRenameColumnSql(tableName: string, oldName: string, newName: string): string;
130
- generateCreateIndexSql(tableName: string, index: IndexSchema): string;
131
- generateDropIndexSql(tableName: string, indexName: string): string;
132
121
  generateAddForeignKeySql(tableName: string, foreignKey: TableForeignKeyDefinition): string;
133
122
  generateDropForeignKeySql(tableName: string, constraintName: string): string;
134
123
  private tableDefinitionToNode;
@@ -138,4 +127,4 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
138
127
  * Synchronous factory for SQL schema generators only.
139
128
  * For MongoDB, use `createSchemaGeneratorAsync` from `./schemaGeneratorAsync.js` so the optional `mongodb` peer is not loaded at import time.
140
129
  */
141
- export declare function createSchemaGenerator(dialect: AbstractDialect, namingStrategy?: NamingStrategy, defaultForeignKeyAction?: ForeignKeyAction): SchemaGenerator | undefined;
130
+ export declare function createSchemaGenerator(dialect: AbstractDialect, defaultForeignKeyAction?: ForeignKeyAction): SqlSchemaGenerator | undefined;