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
@@ -1,134 +0,0 @@
1
- /**
2
- * Smart Relation Detector
3
- *
4
- * Uses heuristics and schema analysis to detect relationships between tables:
5
- * - Explicit foreign keys (highest confidence)
6
- * - Junction tables for ManyToMany
7
- * - Unique FK columns for OneToOne
8
- */
9
- import { singularize } from '../../util/string.util.js';
10
- /**
11
- * Detects relationships in a SchemaAST using multiple heuristics.
12
- */
13
- export class SmartRelationDetector {
14
- ast;
15
- options;
16
- constructor(ast, options = {}) {
17
- this.ast = ast;
18
- this.options = {
19
- minConfidence: options.minConfidence ?? 0.5,
20
- singularize: options.singularize ?? this.defaultSingularize.bind(this),
21
- };
22
- }
23
- /**
24
- * Detect all relationships in the schema.
25
- */
26
- detectAll() {
27
- const relations = [];
28
- // 1. Add explicit FK relationships (confidence: 1.0)
29
- for (const rel of this.ast.relationships) {
30
- relations.push({
31
- type: rel.type,
32
- from: {
33
- table: rel.from.table,
34
- columns: rel.from.columns,
35
- },
36
- to: {
37
- table: rel.to.table,
38
- columns: rel.to.columns,
39
- },
40
- through: rel.through,
41
- confidence: 1.0,
42
- source: 'explicit_fk',
43
- });
44
- }
45
- // 2. Detect junction tables (ManyToMany)
46
- const junctionRelations = this.detectJunctionTables();
47
- relations.push(...junctionRelations);
48
- // 3. Detect unique FK -> OneToOne upgrades
49
- const oneToOneUpgrades = this.detectOneToOneRelations(relations);
50
- relations.push(...oneToOneUpgrades);
51
- // Filter by confidence
52
- return relations.filter((r) => r.confidence >= this.options.minConfidence);
53
- }
54
- /**
55
- * Detect junction tables that represent ManyToMany relationships.
56
- */
57
- detectJunctionTables() {
58
- const relations = [];
59
- for (const table of this.ast.tables.values()) {
60
- if (!this.ast.isJunctionTable(table))
61
- continue;
62
- const outgoingRels = table.outgoingRelations;
63
- if (outgoingRels.length !== 2)
64
- continue;
65
- const [rel1, rel2] = outgoingRels;
66
- // Create ManyToMany relation
67
- relations.push({
68
- type: 'ManyToMany',
69
- from: {
70
- table: rel1.to.table,
71
- columns: rel1.to.columns,
72
- },
73
- to: {
74
- table: rel2.to.table,
75
- columns: rel2.to.columns,
76
- },
77
- through: table,
78
- confidence: 0.95,
79
- source: 'junction_table',
80
- });
81
- // Also create inverse relation
82
- relations.push({
83
- type: 'ManyToMany',
84
- from: {
85
- table: rel2.to.table,
86
- columns: rel2.to.columns,
87
- },
88
- to: {
89
- table: rel1.to.table,
90
- columns: rel1.to.columns,
91
- },
92
- through: table,
93
- confidence: 0.95,
94
- source: 'junction_table',
95
- });
96
- }
97
- return relations;
98
- }
99
- /**
100
- * Detect relations where unique FK should upgrade to OneToOne.
101
- */
102
- detectOneToOneRelations(existingRelations) {
103
- const upgrades = [];
104
- for (const rel of existingRelations) {
105
- if (rel.source !== 'explicit_fk')
106
- continue;
107
- const fromCol = rel.from.columns[0];
108
- if (fromCol?.isUnique && rel.type === 'ManyToOne') {
109
- // Upgrade to OneToOne
110
- upgrades.push({
111
- type: 'OneToOne',
112
- from: rel.from,
113
- to: rel.to,
114
- through: rel.through,
115
- confidence: 0.9,
116
- source: 'unique_fk',
117
- });
118
- }
119
- }
120
- return upgrades;
121
- }
122
- /**
123
- * Default singularize function (delegates to shared utility).
124
- */
125
- defaultSingularize(name) {
126
- return singularize(name);
127
- }
128
- }
129
- /**
130
- * Create a SmartRelationDetector for the given AST.
131
- */
132
- export function createRelationDetector(ast, options) {
133
- return new SmartRelationDetector(ast, options);
134
- }
@@ -1,4 +0,0 @@
1
- export * from './injectQuerier.js';
2
- export * from './log.js';
3
- export * from './serialized.js';
4
- export * from './transactional.js';
@@ -1,4 +0,0 @@
1
- export * from './injectQuerier.js';
2
- export * from './log.js';
3
- export * from './serialized.js';
4
- export * from './transactional.js';
@@ -1,3 +0,0 @@
1
- import type { Key, Type } from '../../type/index.js';
2
- export declare function InjectQuerier(): (proto: Record<PropertyKey, any>, key: string, index: number) => void;
3
- export declare function getInjectedQuerierIndex<S>(service: Type<S>, key: Key<S>): any;
@@ -1,33 +0,0 @@
1
- const metadataKey = Symbol('InjectQuerier');
2
- export function InjectQuerier() {
3
- // biome-ignore lint/suspicious/noExplicitAny: `any` is required - class prototypes don't satisfy Record<K, unknown>
4
- return (proto, key, index) => {
5
- if (!proto[metadataKey]) {
6
- proto[metadataKey] = new WeakMap();
7
- }
8
- if (!proto[metadataKey].has(proto.constructor)) {
9
- proto[metadataKey].set(proto.constructor, {});
10
- }
11
- const meta = proto[metadataKey].get(proto.constructor);
12
- const isAlreadyInjected = key in meta;
13
- if (isAlreadyInjected) {
14
- throw new TypeError(`@InjectQuerier() can only appears once in '${proto.constructor.name}.${key}'}`);
15
- }
16
- meta[key] = index;
17
- };
18
- }
19
- export function getInjectedQuerierIndex(service, key) {
20
- let proto = service.prototype;
21
- while (proto.constructor !== Object) {
22
- const meta = proto[metadataKey]?.get(proto.constructor);
23
- if (meta && key in meta) {
24
- return meta[key];
25
- }
26
- const keys = Object.getOwnPropertyNames(proto);
27
- const isOwnKey = keys.includes(key);
28
- if (isOwnKey) {
29
- return;
30
- }
31
- proto = Object.getPrototypeOf(proto);
32
- }
33
- }
@@ -1,32 +0,0 @@
1
- import type { LoggerWrapper } from '../../util/logger.js';
2
- /**
3
- * A driver error enriched with context by {@link enrichError}. `query` is always attached; `values`
4
- * only when the querier's logger is configured to surface them (see {@link enrichError}) - they can
5
- * carry sensitive data (PII, tokens, etc.) and would otherwise leak into whatever error-tracking
6
- * pipeline (Sentry, console.error, ...) serializes the error, without the developer opting in.
7
- */
8
- export interface QueryError extends Error {
9
- query?: string;
10
- values?: unknown[];
11
- }
12
- /**
13
- * Tags `err` with the query it failed on (as `QueryError`) and re-throws. `values` is only attached
14
- * when `logger?.willLogValues()` is true - i.e. the app already has query values surfacing somewhere
15
- * (query-level or slow-query logging), so attaching them here doesn't introduce a new leak surface.
16
- * Shared by every query call site - `@Log()`, streams, transaction statements - so this logic lives
17
- * in one place.
18
- *
19
- * Not typed `never`: an async `catch` that calls a `never`-returning function ahead of a `finally`
20
- * containing an `if` trips a TS control-flow bug (`TS7027 Unreachable code`) unrelated to this logic.
21
- */
22
- export declare function enrichError(err: unknown, logger: LoggerWrapper | undefined, query: string, values?: unknown[]): void;
23
- /**
24
- * Decorator that logs the execution of a query method.
25
- * It tracks execution time and logs the query, parameters, and duration.
26
- * The decorated class must have a `logger` property of type LoggerWrapper.
27
- *
28
- * On failure, also attaches the query (and values, when the logger surfaces them) to the thrown
29
- * error via {@link enrichError} - so that context survives even when nothing gets logged, or is
30
- * printed in full when the app already opted into it.
31
- */
32
- export declare function Log(): (_target: object, _key: string, propDescriptor: PropertyDescriptor) => void;
@@ -1,52 +0,0 @@
1
- /**
2
- * Tags `err` with the query it failed on (as `QueryError`) and re-throws. `values` is only attached
3
- * when `logger?.willLogValues()` is true - i.e. the app already has query values surfacing somewhere
4
- * (query-level or slow-query logging), so attaching them here doesn't introduce a new leak surface.
5
- * Shared by every query call site - `@Log()`, streams, transaction statements - so this logic lives
6
- * in one place.
7
- *
8
- * Not typed `never`: an async `catch` that calls a `never`-returning function ahead of a `finally`
9
- * containing an `if` trips a TS control-flow bug (`TS7027 Unreachable code`) unrelated to this logic.
10
- */
11
- export function enrichError(err, logger, query, values) {
12
- if (err instanceof Error) {
13
- const queryError = err;
14
- queryError.query ??= query;
15
- if (values !== undefined && logger?.willLogValues()) {
16
- queryError.values ??= values;
17
- }
18
- }
19
- throw err;
20
- }
21
- /**
22
- * Decorator that logs the execution of a query method.
23
- * It tracks execution time and logs the query, parameters, and duration.
24
- * The decorated class must have a `logger` property of type LoggerWrapper.
25
- *
26
- * On failure, also attaches the query (and values, when the logger surfaces them) to the thrown
27
- * error via {@link enrichError} - so that context survives even when nothing gets logged, or is
28
- * printed in full when the app already opted into it.
29
- */
30
- export function Log() {
31
- return (_target, _key, propDescriptor) => {
32
- const originalMethod = propDescriptor.value;
33
- propDescriptor.value = async function (...args) {
34
- const startTime = performance.now();
35
- const isSql = typeof args[0] === 'string';
36
- const query = isSql ? args[0] : _key;
37
- const values = isSql ? args[1] : args;
38
- try {
39
- return await originalMethod.apply(this, args);
40
- }
41
- catch (err) {
42
- enrichError(err, this.logger, query, values);
43
- }
44
- finally {
45
- if (this.logger) {
46
- const duration = performance.now() - startTime;
47
- this.logger.logQuery(query, values, Math.round(duration));
48
- }
49
- }
50
- };
51
- };
52
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Decorator that ensures the decorated method is executed serially within the Querier instance.
3
- * It uses a private promise queue to prevent race conditions on the database connection.
4
- * Note: The decorated class must extend AbstractQuerier or implement a compatible serialize method.
5
- */
6
- export declare function Serialized(): (_target: object, _key: string, propDescriptor: PropertyDescriptor) => void;
@@ -1,13 +0,0 @@
1
- /**
2
- * Decorator that ensures the decorated method is executed serially within the Querier instance.
3
- * It uses a private promise queue to prevent race conditions on the database connection.
4
- * Note: The decorated class must extend AbstractQuerier or implement a compatible serialize method.
5
- */
6
- export function Serialized() {
7
- return (_target, _key, propDescriptor) => {
8
- const originalMethod = propDescriptor.value;
9
- propDescriptor.value = function (...args) {
10
- return this.serialize(() => originalMethod.apply(this, args));
11
- };
12
- };
13
- }
@@ -1,6 +0,0 @@
1
- import type { IsolationLevel, QuerierPool } from '../../type/index.js';
2
- export declare function Transactional({ propagation, pool, isolationLevel, }?: {
3
- readonly propagation?: 'supported' | 'required';
4
- readonly pool?: QuerierPool;
5
- readonly isolationLevel?: IsolationLevel;
6
- }): (target: object, key: string, propDescriptor: PropertyDescriptor) => void;
@@ -1,48 +0,0 @@
1
- import { getQuerierPool } from '../../options.js';
2
- import { getInjectedQuerierIndex } from './injectQuerier.js';
3
- export function Transactional({ propagation = 'required', pool, isolationLevel, } = {}) {
4
- return (target, key, propDescriptor) => {
5
- // biome-ignore lint/suspicious/noExplicitAny: decorator pattern - runtime constructor type is erased
6
- const theClass = target.constructor;
7
- const originalMethod = propDescriptor.value;
8
- const injectedQuerierIndex = getInjectedQuerierIndex(theClass, key);
9
- if (injectedQuerierIndex === undefined) {
10
- throw TypeError(`missing decorator @InjectQuerier() in '${target.constructor.name}.${key}'`);
11
- }
12
- propDescriptor.value = async function func(...args) {
13
- const params = [...args];
14
- let isOwnTransaction = false;
15
- let querier;
16
- if (params[injectedQuerierIndex]) {
17
- querier = params[injectedQuerierIndex];
18
- }
19
- else {
20
- isOwnTransaction = true;
21
- pool ??= getQuerierPool();
22
- querier = await pool.getQuerier();
23
- params[injectedQuerierIndex] = querier;
24
- }
25
- try {
26
- if (propagation === 'required' && !querier.hasOpenTransaction) {
27
- await querier.beginTransaction(isolationLevel ? { isolationLevel } : undefined);
28
- }
29
- const resp = await originalMethod.apply(this, params);
30
- if (isOwnTransaction && querier.hasOpenTransaction) {
31
- await querier.commitTransaction();
32
- }
33
- return resp;
34
- }
35
- catch (err) {
36
- if (isOwnTransaction && querier.hasOpenTransaction) {
37
- await querier.rollbackTransaction();
38
- }
39
- throw err;
40
- }
41
- finally {
42
- if (isOwnTransaction) {
43
- await querier.release();
44
- }
45
- }
46
- };
47
- };
48
- }