uql-orm 0.22.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 (104) hide show
  1. package/dist/browser/uql-browser.min.js.map +3 -3
  2. package/dist/dialect/abstractSqlDialect.d.ts +14 -1
  3. package/dist/dialect/abstractSqlDialect.js +21 -14
  4. package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -1
  5. package/dist/dialect/mysqlLikeSqlDialect.js +25 -0
  6. package/dist/dialect/pgLikeSqlDialect.d.ts +4 -7
  7. package/dist/dialect/pgLikeSqlDialect.js +7 -12
  8. package/dist/entity/decorator/bag.d.ts +35 -0
  9. package/dist/entity/decorator/bag.js +54 -0
  10. package/dist/entity/decorator/entity.d.ts +28 -2
  11. package/dist/entity/decorator/entity.js +40 -2
  12. package/dist/entity/decorator/members.d.ts +51 -0
  13. package/dist/entity/decorator/members.js +51 -0
  14. package/dist/entity/index.d.ts +3 -1
  15. package/dist/entity/index.js +3 -1
  16. package/dist/entity/metadata/definition.d.ts +23 -9
  17. package/dist/entity/metadata/definition.js +55 -100
  18. package/dist/http/contract.js +1 -2
  19. package/dist/http/handler.js +5 -26
  20. package/dist/http/query.js +1 -1
  21. package/dist/migrate/acquireQuerierForMigrations.d.ts +13 -1
  22. package/dist/migrate/acquireQuerierForMigrations.js +28 -0
  23. package/dist/migrate/cli-config.js +24 -8
  24. package/dist/migrate/cli.js +5 -1
  25. package/dist/migrate/codegen/entityCodeGenerator.js +3 -4
  26. package/dist/migrate/codegen/index.d.ts +0 -1
  27. package/dist/migrate/codegen/index.js +0 -2
  28. package/dist/migrate/drift/driftDetector.d.ts +10 -1
  29. package/dist/migrate/drift/driftDetector.js +22 -5
  30. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +5 -1
  31. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +17 -27
  32. package/dist/migrate/introspection/mongoIntrospector.js +7 -13
  33. package/dist/migrate/migrator.js +44 -81
  34. package/dist/migrate/storage/databaseStorage.d.ts +2 -0
  35. package/dist/migrate/storage/databaseStorage.js +8 -23
  36. package/dist/mongo/mongodbQuerier.js +171 -229
  37. package/dist/nestjs/uqlContextInterceptor.js +58 -22
  38. package/dist/nestjs/uqlModule.d.ts +2 -11
  39. package/dist/nestjs/uqlModule.js +93 -44
  40. package/dist/postgres/postgresDialect.js +2 -2
  41. package/dist/querier/abstractQuerier.d.ts +28 -0
  42. package/dist/querier/abstractQuerier.js +47 -22
  43. package/dist/querier/abstractQuerierPool.d.ts +3 -0
  44. package/dist/querier/abstractQuerierPool.js +5 -3
  45. package/dist/querier/abstractSqlQuerier.d.ts +1 -3
  46. package/dist/querier/abstractSqlQuerier.js +48 -96
  47. package/dist/querier/index.d.ts +3 -1
  48. package/dist/querier/index.js +3 -1
  49. package/dist/querier/querierContext.browser.d.ts +12 -0
  50. package/dist/querier/querierContext.browser.js +18 -0
  51. package/dist/querier/querierContext.d.ts +22 -0
  52. package/dist/querier/querierContext.js +42 -0
  53. package/dist/querier/queryError.d.ts +22 -0
  54. package/dist/querier/queryError.js +20 -0
  55. package/dist/querier/transactional.d.ts +26 -0
  56. package/dist/querier/transactional.js +43 -0
  57. package/dist/schema/index.d.ts +1 -1
  58. package/dist/schema/schemaASTBuilder.d.ts +1 -1
  59. package/dist/schema/schemaASTBuilder.js +2 -2
  60. package/dist/schema/types.d.ts +0 -21
  61. package/dist/sqlite/abstractSqliteQuerier.d.ts +9 -2
  62. package/dist/sqlite/hranaQuerier.js +20 -42
  63. package/dist/sqlite/index.d.ts +1 -0
  64. package/dist/sqlite/index.js +1 -0
  65. package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
  66. package/dist/sqlite/localSqliteQuerierPool.js +34 -0
  67. package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
  68. package/dist/sqlite/nodeSqliteAdapter.js +28 -0
  69. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
  70. package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
  71. package/dist/sqlite/sqliteDialect.d.ts +1 -2
  72. package/dist/sqlite/sqliteDialect.js +0 -13
  73. package/dist/sqlite/sqliteQuerierPool.d.ts +10 -23
  74. package/dist/sqlite/sqliteQuerierPool.js +9 -28
  75. package/dist/type/entity.d.ts +95 -28
  76. package/dist/type/querier.d.ts +6 -0
  77. package/dist/util/hook.util.js +1 -1
  78. package/package.json +8 -16
  79. package/dist/entity/decorator/field.d.ts +0 -2
  80. package/dist/entity/decorator/field.js +0 -7
  81. package/dist/entity/decorator/filter.d.ts +0 -7
  82. package/dist/entity/decorator/filter.js +0 -11
  83. package/dist/entity/decorator/hook.d.ts +0 -7
  84. package/dist/entity/decorator/hook.js +0 -14
  85. package/dist/entity/decorator/id.d.ts +0 -2
  86. package/dist/entity/decorator/id.js +0 -7
  87. package/dist/entity/decorator/index-decorator.d.ts +0 -22
  88. package/dist/entity/decorator/index-decorator.js +0 -26
  89. package/dist/entity/decorator/index.d.ts +0 -8
  90. package/dist/entity/decorator/index.js +0 -8
  91. package/dist/entity/decorator/relation.d.ts +0 -8
  92. package/dist/entity/decorator/relation.js +0 -19
  93. package/dist/migrate/codegen/smartRelationDetector.d.ts +0 -47
  94. package/dist/migrate/codegen/smartRelationDetector.js +0 -134
  95. package/dist/querier/decorator/index.d.ts +0 -4
  96. package/dist/querier/decorator/index.js +0 -4
  97. package/dist/querier/decorator/injectQuerier.d.ts +0 -3
  98. package/dist/querier/decorator/injectQuerier.js +0 -33
  99. package/dist/querier/decorator/log.d.ts +0 -32
  100. package/dist/querier/decorator/log.js +0 -52
  101. package/dist/querier/decorator/serialized.d.ts +0 -6
  102. package/dist/querier/decorator/serialized.js +0 -13
  103. package/dist/querier/decorator/transactional.d.ts +0 -6
  104. package/dist/querier/decorator/transactional.js +0 -48
@@ -58,14 +58,15 @@ export class MongoSchemaIntrospector {
58
58
  return ast;
59
59
  }
60
60
  async getTableSchema(tableName) {
61
- const querier = await this.pool.getQuerier();
62
- try {
61
+ return this.pool.withQuerier(async (querier) => {
63
62
  const { db } = querier;
64
63
  const collections = await db.listCollections({ name: tableName }).toArray();
65
64
  if (collections.length === 0) {
66
65
  return undefined;
67
66
  }
68
- // MongoDB doesn't have a fixed schema, but we can look at the indexes
67
+ // MongoDB doesn't have a fixed schema, but we can look at the indexes. Annotated rather than
68
+ // inferred: the driver's `indexes()` is overloaded and resolves to `any` on some versions, which
69
+ // silently made every field below unchecked.
69
70
  const indexes = await db.collection(tableName).indexes();
70
71
  return {
71
72
  name: tableName,
@@ -76,21 +77,14 @@ export class MongoSchemaIntrospector {
76
77
  unique: !!idx.unique,
77
78
  })),
78
79
  };
79
- }
80
- finally {
81
- await querier.release();
82
- }
80
+ });
83
81
  }
84
82
  async getTableNames() {
85
- const querier = await this.pool.getQuerier();
86
- try {
83
+ return this.pool.withQuerier(async (querier) => {
87
84
  const { db } = querier;
88
85
  const collections = await db.listCollections().toArray();
89
86
  return collections.map((c) => c.name);
90
- }
91
- finally {
92
- await querier.release();
93
- }
87
+ });
94
88
  }
95
89
  async tableExists(tableName) {
96
90
  const names = await this.getTableNames();
@@ -5,7 +5,7 @@ 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
10
  import { runMongoCommand } from './generator/mongoCommand.js';
11
11
  import { MongoSchemaIntrospector, MysqlSchemaIntrospector, PostgresSchemaIntrospector, SqliteSchemaIntrospector, } from './introspection/index.js';
@@ -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
@@ -334,13 +327,7 @@ export class Migrator {
334
327
  */
335
328
  async syncForce() {
336
329
  await this.ensureSchemaGenerator();
337
- const querier = await acquireQuerierForMigrations(this.pool);
338
- if (!isSqlQuerier(querier)) {
339
- await querier.release();
340
- throw new Error('Migrator requires a SQL-based querier');
341
- }
342
- try {
343
- await querier.beginTransaction();
330
+ await withSqlQuerierForMigrations(this.pool, 'Migrator', (querier) => querier.transaction(async () => {
344
331
  // Drop all tables first (in reverse order for foreign keys)
345
332
  for (const entity of [...this.entities].reverse()) {
346
333
  const tableName = this.generator.resolveTableName(entity, getMeta(entity));
@@ -356,16 +343,8 @@ export class Migrator {
356
343
  await querier.run(createSql);
357
344
  }
358
345
  }
359
- await querier.commitTransaction();
360
- this.logger.logSchema('Schema sync (force) completed');
361
- }
362
- catch (error) {
363
- await querier.rollbackTransaction();
364
- throw error;
365
- }
366
- finally {
367
- await querier.release();
368
- }
346
+ }));
347
+ this.logger.logSchema('Schema sync (force) completed');
369
348
  }
370
349
  /**
371
350
  * Safely synchronizes the schema by only adding missing tables and columns.
@@ -442,26 +421,12 @@ export class Migrator {
442
421
  return filteredDiff;
443
422
  }
444
423
  async executeSyncStatements(statements, options) {
445
- const querier = await acquireQuerierForMigrations(this.pool);
446
- try {
447
- if (this.dialectName === 'mongodb') {
448
- await this.executeMongoSyncStatements(statements, options, querier);
449
- }
450
- else {
451
- await this.executeSqlSyncStatements(statements, options, querier);
452
- }
453
- if (options.logging)
454
- this.logger.logSchema('Schema synchronization completed');
455
- }
456
- catch (error) {
457
- if (this.dialectName !== 'mongodb' && isSqlQuerier(querier)) {
458
- await querier.rollbackTransaction();
459
- }
460
- throw error;
461
- }
462
- finally {
463
- await querier.release();
464
- }
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');
465
430
  }
466
431
  async executeMongoSyncStatements(statements, options, querier) {
467
432
  for (const statement of statements) {
@@ -474,13 +439,11 @@ export class Migrator {
474
439
  if (!isSqlQuerier(querier)) {
475
440
  throw new Error('Migrator requires a SQL-based querier for this dialect');
476
441
  }
477
- await querier.beginTransaction();
478
442
  for (const sql of statements) {
479
443
  if (options.logging)
480
444
  this.logger.logSchema(`Executing: ${sql}`);
481
445
  await querier.run(sql);
482
446
  }
483
- await querier.commitTransaction();
484
447
  }
485
448
  /**
486
449
  * Get migration status
@@ -3,6 +3,8 @@ import type { MigrationStorage, QuerierPool, SqlQuerier } from '../../type/index
3
3
  * Stores migration state in a database table.
4
4
  * Uses the querier's dialect for escaping and placeholders.
5
5
  */
6
+ /** Where executed migrations are recorded when the config does not name a table. */
7
+ export declare const DEFAULT_MIGRATIONS_TABLE = "uql_migrations";
6
8
  export declare class DatabaseMigrationStorage implements MigrationStorage {
7
9
  private readonly pool;
8
10
  private readonly tableName;
@@ -1,33 +1,26 @@
1
- import { isSqlQuerier } from '../../type/index.js';
2
- import { acquireQuerierForMigrations } from '../acquireQuerierForMigrations.js';
1
+ import { withSqlQuerierForMigrations } from '../acquireQuerierForMigrations.js';
3
2
  /**
4
3
  * Stores migration state in a database table.
5
4
  * Uses the querier's dialect for escaping and placeholders.
6
5
  */
6
+ /** Where executed migrations are recorded when the config does not name a table. */
7
+ export const DEFAULT_MIGRATIONS_TABLE = 'uql_migrations';
7
8
  export class DatabaseMigrationStorage {
8
9
  pool;
9
10
  tableName;
10
11
  storageInitialized = false;
11
12
  constructor(pool, options = {}) {
12
13
  this.pool = pool;
13
- this.tableName = options.tableName ?? 'uql_migrations';
14
+ this.tableName = options.tableName ?? DEFAULT_MIGRATIONS_TABLE;
14
15
  }
15
16
  async ensureStorage() {
16
17
  if (this.storageInitialized) {
17
18
  return;
18
19
  }
19
- const querier = await acquireQuerierForMigrations(this.pool);
20
- if (!isSqlQuerier(querier)) {
21
- await querier.release();
22
- throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
23
- }
24
- try {
20
+ await withSqlQuerierForMigrations(this.pool, 'DatabaseMigrationStorage', async (querier) => {
25
21
  await this.createTableIfNotExists(querier);
26
22
  this.storageInitialized = true;
27
- }
28
- finally {
29
- await querier.release();
30
- }
23
+ });
31
24
  }
32
25
  async createTableIfNotExists(querier) {
33
26
  const { dialect } = querier;
@@ -41,20 +34,12 @@ export class DatabaseMigrationStorage {
41
34
  }
42
35
  async executed() {
43
36
  await this.ensureStorage();
44
- const querier = await acquireQuerierForMigrations(this.pool);
45
- if (!isSqlQuerier(querier)) {
46
- await querier.release();
47
- throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
48
- }
49
- try {
37
+ return withSqlQuerierForMigrations(this.pool, 'DatabaseMigrationStorage', async (querier) => {
50
38
  const { dialect } = querier;
51
39
  const sql = /*sql*/ `SELECT ${dialect.escapeId('name')} FROM ${dialect.escapeId(this.tableName)} ORDER BY ${dialect.escapeId('name')} ASC`;
52
40
  const results = await querier.all(sql);
53
41
  return results.map((r) => r.name);
54
- }
55
- finally {
56
- await querier.release();
57
- }
42
+ });
58
43
  }
59
44
  /**
60
45
  * Log a migration as executed - uses provided querier (within transaction)