metal-orm 1.0.55 → 1.0.57

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 (72) hide show
  1. package/README.md +21 -20
  2. package/dist/index.cjs +831 -113
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +524 -71
  5. package/dist/index.d.ts +524 -71
  6. package/dist/index.js +794 -113
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/codegen/naming-strategy.ts +3 -1
  10. package/src/codegen/typescript.ts +20 -10
  11. package/src/core/ast/aggregate-functions.ts +14 -0
  12. package/src/core/ast/builders.ts +38 -20
  13. package/src/core/ast/expression-builders.ts +70 -2
  14. package/src/core/ast/expression-nodes.ts +305 -274
  15. package/src/core/ast/expression-visitor.ts +11 -1
  16. package/src/core/ast/expression.ts +4 -0
  17. package/src/core/ast/query.ts +3 -0
  18. package/src/core/ddl/introspect/catalogs/mysql.ts +5 -0
  19. package/src/core/ddl/introspect/catalogs/sqlite.ts +3 -0
  20. package/src/core/ddl/introspect/functions/mssql.ts +13 -0
  21. package/src/core/ddl/introspect/mssql.ts +4 -0
  22. package/src/core/ddl/introspect/mysql.ts +4 -0
  23. package/src/core/ddl/introspect/sqlite.ts +4 -0
  24. package/src/core/dialect/abstract.ts +552 -531
  25. package/src/core/dialect/base/function-table-formatter.ts +9 -30
  26. package/src/core/dialect/base/sql-dialect.ts +24 -0
  27. package/src/core/dialect/mssql/functions.ts +40 -2
  28. package/src/core/dialect/mysql/functions.ts +16 -2
  29. package/src/core/dialect/postgres/functions.ts +66 -2
  30. package/src/core/dialect/postgres/index.ts +17 -4
  31. package/src/core/dialect/postgres/table-functions.ts +27 -0
  32. package/src/core/dialect/sqlite/functions.ts +34 -0
  33. package/src/core/dialect/sqlite/index.ts +17 -1
  34. package/src/core/driver/database-driver.ts +9 -1
  35. package/src/core/driver/mssql-driver.ts +3 -0
  36. package/src/core/driver/mysql-driver.ts +3 -0
  37. package/src/core/driver/postgres-driver.ts +3 -0
  38. package/src/core/driver/sqlite-driver.ts +3 -0
  39. package/src/core/execution/executors/mssql-executor.ts +5 -0
  40. package/src/core/execution/executors/mysql-executor.ts +5 -0
  41. package/src/core/execution/executors/postgres-executor.ts +5 -0
  42. package/src/core/execution/executors/sqlite-executor.ts +5 -0
  43. package/src/core/functions/array.ts +26 -0
  44. package/src/core/functions/control-flow.ts +69 -0
  45. package/src/core/functions/datetime.ts +50 -0
  46. package/src/core/functions/definitions/aggregate.ts +16 -0
  47. package/src/core/functions/definitions/control-flow.ts +24 -0
  48. package/src/core/functions/definitions/datetime.ts +36 -0
  49. package/src/core/functions/definitions/helpers.ts +29 -0
  50. package/src/core/functions/definitions/json.ts +49 -0
  51. package/src/core/functions/definitions/numeric.ts +55 -0
  52. package/src/core/functions/definitions/string.ts +43 -0
  53. package/src/core/functions/function-registry.ts +48 -0
  54. package/src/core/functions/group-concat-helpers.ts +57 -0
  55. package/src/core/functions/json.ts +38 -0
  56. package/src/core/functions/numeric.ts +14 -0
  57. package/src/core/functions/standard-strategy.ts +86 -115
  58. package/src/core/functions/standard-table-strategy.ts +13 -0
  59. package/src/core/functions/table-types.ts +15 -0
  60. package/src/core/functions/text.ts +57 -0
  61. package/src/core/sql/sql.ts +59 -38
  62. package/src/decorators/bootstrap.ts +5 -4
  63. package/src/index.ts +18 -11
  64. package/src/orm/hydration-context.ts +10 -0
  65. package/src/orm/identity-map.ts +19 -0
  66. package/src/orm/interceptor-pipeline.ts +4 -0
  67. package/src/orm/relations/belongs-to.ts +17 -0
  68. package/src/orm/relations/has-one.ts +17 -0
  69. package/src/orm/relations/many-to-many.ts +41 -0
  70. package/src/query-builder/select.ts +68 -68
  71. package/src/schema/table-guards.ts +6 -0
  72. package/src/schema/types.ts +8 -1
@@ -1,131 +1,102 @@
1
+
1
2
  import { FunctionStrategy, FunctionRenderer, FunctionRenderContext } from './types.js';
2
- import { LiteralNode, OperandNode, isOperandNode } from '../ast/expression.js';
3
+ import type { LiteralNode, OperandNode } from '../ast/expression.js';
4
+ import { FunctionRegistry } from './function-registry.js';
5
+ import type { FunctionDefinition } from './function-registry.js';
6
+ import { aggregateFunctionDefinitions } from './definitions/aggregate.js';
7
+ import { stringFunctionDefinitions } from './definitions/string.js';
8
+ import { dateTimeFunctionDefinitions } from './definitions/datetime.js';
9
+ import { numericFunctionDefinitions } from './definitions/numeric.js';
10
+ import { controlFlowFunctionDefinitions } from './definitions/control-flow.js';
11
+ import { jsonFunctionDefinitions } from './definitions/json.js';
12
+ import {
13
+ renderStandardGroupConcat,
14
+ buildGroupConcatOrderBy as buildGroupConcatOrderByClause,
15
+ formatGroupConcatSeparator as formatGroupConcatSeparatorClause,
16
+ getGroupConcatSeparatorOperand as resolveGroupConcatSeparatorOperand,
17
+ DEFAULT_GROUP_CONCAT_SEPARATOR as DEFAULT_GROUP_CONCAT_SEPARATOR_LITERAL
18
+ } from './group-concat-helpers.js';
3
19
 
4
20
  /**
5
21
  * Standard implementation of FunctionStrategy for ANSI SQL functions.
6
22
  */
7
23
  export class StandardFunctionStrategy implements FunctionStrategy {
8
- protected renderers: Map<string, FunctionRenderer> = new Map();
24
+ protected readonly registry: FunctionRegistry;
25
+
26
+ /**
27
+ * Creates a new StandardFunctionStrategy and registers standard functions.
28
+ */
29
+ constructor(registry?: FunctionRegistry) {
30
+ this.registry = registry ?? new FunctionRegistry();
31
+ this.registerStandard();
32
+ }
9
33
 
10
- /**
11
- * Creates a new StandardFunctionStrategy and registers standard functions.
12
- */
13
- constructor() {
14
- this.registerStandard();
15
- }
34
+ protected registerStandard(): void {
35
+ this.registerDefinitions(aggregateFunctionDefinitions);
36
+ this.registerDefinitions(stringFunctionDefinitions);
37
+ this.registerDefinitions(dateTimeFunctionDefinitions);
38
+ this.registerDefinitions(numericFunctionDefinitions);
39
+ this.registerDefinitions(controlFlowFunctionDefinitions);
40
+ this.registerDefinitions(jsonFunctionDefinitions);
41
+ this.add('GROUP_CONCAT', ctx => this.renderGroupConcat(ctx));
42
+ }
16
43
 
17
- protected registerStandard() {
18
- // Register ANSI standard implementations
19
- this.add('COUNT', ({ compiledArgs }) => compiledArgs.length ? `COUNT(${compiledArgs.join(', ')})` : 'COUNT(*)');
20
- this.add('SUM', ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
21
- this.add('AVG', ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
22
- this.add('MIN', ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
23
- this.add('MAX', ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
24
- this.add('ABS', ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
25
- this.add('UPPER', ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
26
- this.add('LOWER', ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
27
- this.add('LENGTH', ({ compiledArgs }) => `LENGTH(${compiledArgs[0]})`);
28
- this.add('TRIM', ({ compiledArgs }) => `TRIM(${compiledArgs[0]})`);
29
- this.add('LTRIM', ({ compiledArgs }) => `LTRIM(${compiledArgs[0]})`);
30
- this.add('RTRIM', ({ compiledArgs }) => `RTRIM(${compiledArgs[0]})`);
31
- this.add('SUBSTRING', ({ compiledArgs }) => `SUBSTRING(${compiledArgs.join(', ')})`);
32
- this.add('CONCAT', ({ compiledArgs }) => `CONCAT(${compiledArgs.join(', ')})`);
33
- this.add('NOW', () => `NOW()`);
34
- this.add('CURRENT_DATE', () => `CURRENT_DATE`);
35
- this.add('CURRENT_TIME', () => `CURRENT_TIME`);
36
- this.add('EXTRACT', ({ compiledArgs }) => `EXTRACT(${compiledArgs[0]} FROM ${compiledArgs[1]})`);
37
- this.add('YEAR', ({ compiledArgs }) => `EXTRACT(YEAR FROM ${compiledArgs[0]})`);
38
- this.add('MONTH', ({ compiledArgs }) => `EXTRACT(MONTH FROM ${compiledArgs[0]})`);
39
- this.add('DAY', ({ compiledArgs }) => `EXTRACT(DAY FROM ${compiledArgs[0]})`);
40
- this.add('DATE_ADD', ({ compiledArgs }) => `(${compiledArgs[0]} + INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
41
- this.add('DATE_SUB', ({ compiledArgs }) => `(${compiledArgs[0]} - INTERVAL ${compiledArgs[1]} ${compiledArgs[2]})`);
42
- this.add('DATE_DIFF', ({ compiledArgs }) => `DATEDIFF(${compiledArgs[0]}, ${compiledArgs[1]})`);
43
- this.add('DATE_FORMAT', ({ compiledArgs }) => `DATE_FORMAT(${compiledArgs[0]}, ${compiledArgs[1]})`);
44
- this.add('UNIX_TIMESTAMP', () => `UNIX_TIMESTAMP()`);
45
- this.add('FROM_UNIXTIME', ({ compiledArgs }) => `FROM_UNIXTIME(${compiledArgs[0]})`);
46
- this.add('END_OF_MONTH', ({ compiledArgs }) => `LAST_DAY(${compiledArgs[0]})`);
47
- this.add('DAY_OF_WEEK', ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
48
- this.add('WEEK_OF_YEAR', ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
49
- this.add('DATE_TRUNC', ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
50
- this.add('GROUP_CONCAT', ctx => this.renderGroupConcat(ctx));
51
- }
44
+ protected registerDefinitions(definitions: FunctionDefinition[]): void {
45
+ this.registry.register(definitions);
46
+ }
52
47
 
53
- /**
54
- * Registers a renderer for a function name.
55
- * @param name - The function name.
56
- * @param renderer - The renderer function.
57
- */
58
- protected add(name: string, renderer: FunctionRenderer) {
59
- this.renderers.set(name, renderer);
60
- }
48
+ /**
49
+ * Registers a renderer for a function name.
50
+ * @param name - The function name.
51
+ * @param renderer - The renderer function.
52
+ */
53
+ protected add(name: string, renderer: FunctionRenderer): void {
54
+ this.registry.add(name, renderer);
55
+ }
61
56
 
62
- /**
63
- * @inheritDoc
64
- */
65
- getRenderer(name: string): FunctionRenderer | undefined {
66
- return this.renderers.get(name);
67
- }
57
+ /**
58
+ * @inheritDoc
59
+ */
60
+ getRenderer(name: string): FunctionRenderer | undefined {
61
+ return this.registry.get(name);
62
+ }
68
63
 
69
- /**
70
- * Renders the GROUP_CONCAT function with optional ORDER BY and SEPARATOR.
71
- * @param ctx - The function render context.
72
- * @returns The rendered SQL string.
73
- */
74
- private renderGroupConcat(ctx: FunctionRenderContext): string {
75
- const arg = ctx.compiledArgs[0];
76
- const orderClause = this.buildOrderByExpression(ctx);
77
- const orderSegment = orderClause ? ` ${orderClause}` : '';
78
- const separatorClause = this.formatGroupConcatSeparator(ctx);
79
- return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
80
- }
64
+ /**
65
+ * Renders the GROUP_CONCAT function with optional ORDER BY and SEPARATOR.
66
+ * @param ctx - The function render context.
67
+ * @returns The rendered SQL string.
68
+ */
69
+ private renderGroupConcat(ctx: FunctionRenderContext): string {
70
+ return renderStandardGroupConcat(ctx);
71
+ }
81
72
 
82
- /**
83
- * Builds the ORDER BY clause for functions like GROUP_CONCAT.
84
- * @param ctx - The function render context.
85
- * @returns The ORDER BY SQL clause or empty string.
86
- */
87
- protected buildOrderByExpression(ctx: FunctionRenderContext): string {
88
- const orderBy = ctx.node.orderBy;
89
- if (!orderBy || orderBy.length === 0) {
90
- return '';
91
- }
92
- const parts = orderBy.map(order => {
93
- const term = isOperandNode(order.term)
94
- ? ctx.compileOperand(order.term)
95
- : (() => {
96
- throw new Error('ORDER BY expressions inside functions must be operands');
97
- })();
98
- const collation = order.collation ? ` COLLATE ${order.collation}` : '';
99
- const nulls = order.nulls ? ` NULLS ${order.nulls}` : '';
100
- return `${term} ${order.direction}${collation}${nulls}`;
101
- });
102
- return `ORDER BY ${parts.join(', ')}`;
103
- }
73
+ /**
74
+ * Builds the ORDER BY clause for functions like GROUP_CONCAT.
75
+ * @param ctx - The function render context.
76
+ * @returns The ORDER BY SQL clause or empty string.
77
+ */
78
+ protected buildOrderByExpression(ctx: FunctionRenderContext): string {
79
+ return buildGroupConcatOrderByClause(ctx);
80
+ }
104
81
 
105
- /**
106
- * Formats the SEPARATOR clause for GROUP_CONCAT.
107
- * @param ctx - The function render context.
108
- * @returns The SEPARATOR SQL clause or empty string.
109
- */
110
- protected formatGroupConcatSeparator(ctx: FunctionRenderContext): string {
111
- if (!ctx.node.separator) {
112
- return '';
113
- }
114
- return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
115
- }
82
+ /**
83
+ * Formats the SEPARATOR clause for GROUP_CONCAT.
84
+ * @param ctx - The function render context.
85
+ * @returns The SEPARATOR SQL clause or empty string.
86
+ */
87
+ protected formatGroupConcatSeparator(ctx: FunctionRenderContext): string {
88
+ return formatGroupConcatSeparatorClause(ctx);
89
+ }
116
90
 
117
- /**
118
- * Gets the separator operand for GROUP_CONCAT, defaulting to comma.
119
- * @param ctx - The function render context.
120
- * @returns The separator operand.
121
- */
122
- protected getGroupConcatSeparatorOperand(ctx: FunctionRenderContext): OperandNode {
123
- return ctx.node.separator ?? StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
124
- }
91
+ /**
92
+ * Gets the separator operand for GROUP_CONCAT, defaulting to comma.
93
+ * @param ctx - The function render context.
94
+ * @returns The separator operand.
95
+ */
96
+ protected getGroupConcatSeparatorOperand(ctx: FunctionRenderContext): OperandNode {
97
+ return resolveGroupConcatSeparatorOperand(ctx);
98
+ }
125
99
 
126
- /** Default separator for GROUP_CONCAT, a comma. */
127
- protected static readonly DEFAULT_GROUP_CONCAT_SEPARATOR: LiteralNode = {
128
- type: 'Literal',
129
- value: ','
130
- };
100
+ /** Default separator for GROUP_CONCAT, a comma. */
101
+ protected static readonly DEFAULT_GROUP_CONCAT_SEPARATOR: LiteralNode = DEFAULT_GROUP_CONCAT_SEPARATOR_LITERAL;
131
102
  }
@@ -0,0 +1,13 @@
1
+ import type { TableFunctionRenderer, TableFunctionStrategy } from './table-types.js';
2
+
3
+ export class StandardTableFunctionStrategy implements TableFunctionStrategy {
4
+ protected renderers: Map<string, TableFunctionRenderer> = new Map();
5
+
6
+ protected add(key: string, renderer: TableFunctionRenderer) {
7
+ this.renderers.set(key, renderer);
8
+ }
9
+
10
+ getRenderer(key: string): TableFunctionRenderer | undefined {
11
+ return this.renderers.get(key);
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import type { OperandNode } from '../ast/expression.js';
2
+ import type { FunctionTableNode } from '../ast/query.js';
3
+
4
+ export interface TableFunctionRenderContext {
5
+ node: FunctionTableNode;
6
+ compiledArgs: string[];
7
+ compileOperand: (operand: OperandNode) => string;
8
+ quoteIdentifier: (id: string) => string;
9
+ }
10
+
11
+ export type TableFunctionRenderer = (ctx: TableFunctionRenderContext) => string;
12
+
13
+ export interface TableFunctionStrategy {
14
+ getRenderer(key: string): TableFunctionRenderer | undefined;
15
+ }
@@ -208,3 +208,60 @@ export const rpad = (value: OperandInput, len: OperandInput, pad: OperandInput):
208
208
  */
209
209
  export const space = (count: OperandInput): FunctionNode => fn('SPACE', [count]);
210
210
 
211
+ /**
212
+ * Reverses a string.
213
+ * @param value - The string value.
214
+ * @returns A FunctionNode representing the REVERSE SQL function.
215
+ */
216
+ export const reverse = (value: OperandInput): FunctionNode => fn('REVERSE', [value]);
217
+
218
+ /**
219
+ * Capitalizes the first letter of each word in a string.
220
+ * @param value - The string value.
221
+ * @returns A FunctionNode representing the INITCAP SQL function.
222
+ */
223
+ export const initcap = (value: OperandInput): FunctionNode => fn('INITCAP', [value]);
224
+
225
+ /**
226
+ * Returns the MD5 hash of a string.
227
+ * @param value - The string value.
228
+ * @returns A FunctionNode representing the MD5 SQL function.
229
+ */
230
+ export const md5 = (value: OperandInput): FunctionNode => fn('MD5', [value]);
231
+
232
+ /**
233
+ * Returns the SHA-1 hash of a string.
234
+ * @param value - The string value.
235
+ * @returns A FunctionNode representing the SHA1 SQL function.
236
+ */
237
+ export const sha1 = (value: OperandInput): FunctionNode => fn('SHA1', [value]);
238
+
239
+ /**
240
+ * Returns the SHA-2 hash of a string with a specified bit length.
241
+ * @param value - The string value.
242
+ * @param bits - The bit length (e.g., 224, 256, 384, 512).
243
+ * @returns A FunctionNode representing the SHA2 SQL function.
244
+ */
245
+ export const sha2 = (value: OperandInput, bits: OperandInput): FunctionNode => fn('SHA2', [value, bits]);
246
+
247
+ /**
248
+ * Returns the length of a string in bits.
249
+ * @param value - The string value.
250
+ * @returns A FunctionNode representing the BIT_LENGTH SQL function.
251
+ */
252
+ export const bitLength = (value: OperandInput): FunctionNode => fn('BIT_LENGTH', [value]);
253
+
254
+ /**
255
+ * Returns the length of a string in bytes.
256
+ * @param value - The string value.
257
+ * @returns A FunctionNode representing the OCTET_LENGTH SQL function.
258
+ */
259
+ export const octetLength = (value: OperandInput): FunctionNode => fn('OCTET_LENGTH', [value]);
260
+
261
+ /**
262
+ * Returns a string from an ASCII code.
263
+ * @param code - The ASCII code.
264
+ * @returns A FunctionNode representing the CHR/CHAR SQL function.
265
+ */
266
+ export const chr = (code: OperandInput): FunctionNode => fn('CHR', [code]);
267
+
@@ -33,44 +33,65 @@ export const SQL_KEYWORDS = {
33
33
  /**
34
34
  * SQL operators used in query conditions
35
35
  */
36
- export const SQL_OPERATORS = {
37
- /** Equality operator */
38
- EQUALS: '=',
39
- /** Not equals operator */
40
- NOT_EQUALS: '!=',
41
- /** Greater than operator */
42
- GREATER_THAN: '>',
43
- /** Greater than or equal operator */
44
- GREATER_OR_EQUAL: '>=',
45
- /** Less than operator */
46
- LESS_THAN: '<',
47
- /** Less than or equal operator */
48
- LESS_OR_EQUAL: '<=',
49
- /** LIKE pattern matching operator */
50
- LIKE: 'LIKE',
51
- /** NOT LIKE pattern matching operator */
52
- NOT_LIKE: 'NOT LIKE',
53
- /** IN membership operator */
54
- IN: 'IN',
55
- /** NOT IN membership operator */
56
- NOT_IN: 'NOT IN',
57
- /** BETWEEN range operator */
58
- BETWEEN: 'BETWEEN',
59
- /** NOT BETWEEN range operator */
60
- NOT_BETWEEN: 'NOT BETWEEN',
61
- /** IS NULL null check operator */
62
- IS_NULL: 'IS NULL',
63
- /** IS NOT NULL null check operator */
64
- IS_NOT_NULL: 'IS NOT NULL',
65
- /** Logical AND operator */
66
- AND: 'AND',
67
- /** Logical OR operator */
68
- OR: 'OR',
69
- /** EXISTS operator */
70
- EXISTS: 'EXISTS',
71
- /** NOT EXISTS operator */
72
- NOT_EXISTS: 'NOT EXISTS'
73
- } as const;
36
+ export const SQL_OPERATORS = {
37
+ /** Equality operator */
38
+ EQUALS: '=',
39
+ /** Not equals operator */
40
+ NOT_EQUALS: '!=',
41
+ /** Greater than operator */
42
+ GREATER_THAN: '>',
43
+ /** Greater than or equal operator */
44
+ GREATER_OR_EQUAL: '>=',
45
+ /** Less than operator */
46
+ LESS_THAN: '<',
47
+ /** Less than or equal operator */
48
+ LESS_OR_EQUAL: '<=',
49
+ /** LIKE pattern matching operator */
50
+ LIKE: 'LIKE',
51
+ /** NOT LIKE pattern matching operator */
52
+ NOT_LIKE: 'NOT LIKE',
53
+ /** IN membership operator */
54
+ IN: 'IN',
55
+ /** NOT IN membership operator */
56
+ NOT_IN: 'NOT IN',
57
+ /** BETWEEN range operator */
58
+ BETWEEN: 'BETWEEN',
59
+ /** NOT BETWEEN range operator */
60
+ NOT_BETWEEN: 'NOT BETWEEN',
61
+ /** IS NULL null check operator */
62
+ IS_NULL: 'IS NULL',
63
+ /** IS NOT NULL null check operator */
64
+ IS_NOT_NULL: 'IS NOT NULL',
65
+ /** Logical AND operator */
66
+ AND: 'AND',
67
+ /** Logical OR operator */
68
+ OR: 'OR',
69
+ /** EXISTS operator */
70
+ EXISTS: 'EXISTS',
71
+ /** NOT EXISTS operator */
72
+ NOT_EXISTS: 'NOT EXISTS'
73
+ } as const;
74
+
75
+ /**
76
+ * SQL bitwise operators
77
+ */
78
+ export const BITWISE_OPERATORS = {
79
+ /** Bitwise AND */
80
+ AND: '&',
81
+ /** Bitwise OR */
82
+ OR: '|',
83
+ /** Bitwise XOR */
84
+ XOR: '^',
85
+ /** Bitwise Shift Left */
86
+ SHIFT_LEFT: '<<',
87
+ /** Bitwise Shift Right */
88
+ SHIFT_RIGHT: '>>'
89
+ } as const;
90
+
91
+ /**
92
+ * Type representing supported bitwise operators
93
+ */
94
+ export type BitwiseOperator = (typeof BITWISE_OPERATORS)[keyof typeof BITWISE_OPERATORS];
74
95
 
75
96
  /**
76
97
  * Type representing any supported SQL operator
@@ -20,6 +20,7 @@ import {
20
20
  } from '../orm/entity-metadata.js';
21
21
 
22
22
  import { tableRef, type TableRef } from '../schema/table.js';
23
+ import { SelectableKeys, ColumnDef } from '../schema/types.js';
23
24
 
24
25
  const unwrapTarget = (target: EntityOrTableTargetResolver): EntityOrTableTarget => {
25
26
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
@@ -143,14 +144,14 @@ export const getTableDefFromEntity = <TTable extends TableDef = TableDef>(ctor:
143
144
  * @param ctor - The entity constructor.
144
145
  * @returns A select query builder for the entity.
145
146
  */
146
- export const selectFromEntity = <TTable extends TableDef = TableDef>(
147
- ctor: EntityConstructor
148
- ): SelectQueryBuilder<unknown, TTable> => {
147
+ export const selectFromEntity = <TEntity extends object>(
148
+ ctor: EntityConstructor<TEntity>
149
+ ): SelectQueryBuilder<unknown, TableDef<{ [K in SelectableKeys<TEntity>]: ColumnDef }>> => {
149
150
  const table = getTableDefFromEntity(ctor);
150
151
  if (!table) {
151
152
  throw new Error(`Entity '${ctor.name}' is not registered with decorators or has not been bootstrapped`);
152
153
  }
153
- return new SelectQueryBuilder(table as TTable);
154
+ return new SelectQueryBuilder(table as unknown as TableDef<{ [K in SelectableKeys<TEntity>]: ColumnDef }>);
154
155
  };
155
156
 
156
157
  /**
package/src/index.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * MetalORM core exports.
3
+ * Provides schema definition, query building, and ORM capabilities.
4
+ */
1
5
  export * from './schema/table.js';
2
6
  export * from './schema/column-types.js';
3
7
  export * from './schema/relation.js';
@@ -19,16 +23,19 @@ export * from './core/ddl/schema-types.js';
19
23
  export * from './core/ddl/schema-diff.js';
20
24
  export * from './core/ddl/schema-introspect.js';
21
25
  export * from './core/ddl/introspect/registry.js';
22
- export * from './core/functions/text.js';
23
- export * from './core/functions/numeric.js';
24
- export * from './core/functions/datetime.js';
26
+ export * from './core/functions/text.js';
27
+ export * from './core/functions/numeric.js';
28
+ export * from './core/functions/datetime.js';
29
+ export * from './core/functions/control-flow.js';
30
+ export * from './core/functions/json.js';
31
+ export * from './core/functions/array.js';
25
32
  export * from './orm/als.js';
26
33
  export * from './orm/hydration.js';
27
34
  export * from './codegen/typescript.js';
28
- export * from './orm/orm-session.js';
29
- export * from './orm/orm.js';
30
- export * from './orm/entity.js';
31
- export * from './orm/lazy-batch.js';
35
+ export * from './orm/orm-session.js';
36
+ export * from './orm/orm.js';
37
+ export * from './orm/entity.js';
38
+ export * from './orm/lazy-batch.js';
32
39
  export * from './orm/relations/has-many.js';
33
40
  export * from './orm/relations/belongs-to.js';
34
41
  export * from './orm/relations/many-to-many.js';
@@ -38,10 +45,10 @@ export * from './orm/execution-context.js';
38
45
  export * from './orm/hydration-context.js';
39
46
  export * from './orm/domain-event-bus.js';
40
47
  export * from './orm/runtime-types.js';
41
- export * from './orm/query-logger.js';
42
- export * from './orm/jsonify.js';
43
- export * from './orm/save-graph-types.js';
44
- export * from './decorators/index.js';
48
+ export * from './orm/query-logger.js';
49
+ export * from './orm/jsonify.js';
50
+ export * from './orm/save-graph-types.js';
51
+ export * from './decorators/index.js';
45
52
 
46
53
  // NEW: execution abstraction + helpers
47
54
  export * from './core/execution/db-executor.js';
@@ -6,11 +6,21 @@ import type { EntityContext } from './entity-context.js';
6
6
  import type { AnyDomainEvent, DomainEvent } from './runtime-types.js';
7
7
  import type { OrmSession } from './orm-session.js';
8
8
 
9
+ /**
10
+ * Context used during the hydration of entities from database results.
11
+ * It carries necessary services and processors to handle identity management,
12
+ * unit of work registration, and relation changes.
13
+ */
9
14
  export interface HydrationContext<E extends DomainEvent = AnyDomainEvent> {
15
+ /** The identity map used to track and reuse entity instances. */
10
16
  identityMap: IdentityMap;
17
+ /** The unit of work used to track changes in hydrated entities. */
11
18
  unitOfWork: UnitOfWork;
19
+ /** The bus used to dispatch domain events during or after hydration. */
12
20
  domainEvents: DomainEventBus<E, OrmSession<E>>;
21
+ /** Processor for handling changes in entity relations during hydration. */
13
22
  relationChanges: RelationChangeProcessor;
23
+ /** Context providing access to entity-specific metadata and services. */
14
24
  entityContext: EntityContext;
15
25
  // maybe mapping registry, converters, etc.
16
26
  }
@@ -1,6 +1,10 @@
1
1
  import type { TableDef } from '../schema/table.js';
2
2
  import type { TrackedEntity } from './runtime-types.js';
3
3
 
4
+ /**
5
+ * Simple identity map for tracking entities within a session.
6
+ * Ensures that the same database record is represented by a single entity instance.
7
+ */
4
8
  export class IdentityMap {
5
9
  private readonly buckets = new Map<string, Map<string, TrackedEntity>>();
6
10
 
@@ -8,11 +12,21 @@ export class IdentityMap {
8
12
  return this.buckets;
9
13
  }
10
14
 
15
+ /**
16
+ * Retrieves an entity from the identity map if it exists.
17
+ * @param table The table definition of the entity.
18
+ * @param pk The primary key value.
19
+ * @returns The entity instance if found, undefined otherwise.
20
+ */
11
21
  getEntity(table: TableDef, pk: string | number): unknown | undefined {
12
22
  const bucket = this.buckets.get(table.name);
13
23
  return bucket?.get(this.toIdentityKey(pk))?.entity;
14
24
  }
15
25
 
26
+ /**
27
+ * Registers a tracked entity in the identity map.
28
+ * @param tracked The tracked entity metadata and instance.
29
+ */
16
30
  register(tracked: TrackedEntity): void {
17
31
  if (tracked.pk == null) return;
18
32
  const bucket = this.buckets.get(tracked.table.name) ?? new Map<string, TrackedEntity>();
@@ -26,6 +40,11 @@ export class IdentityMap {
26
40
  bucket?.delete(this.toIdentityKey(tracked.pk));
27
41
  }
28
42
 
43
+ /**
44
+ * Returns all tracked entities for a specific table.
45
+ * @param table The table definition.
46
+ * @returns Array of tracked entities.
47
+ */
29
48
  getEntitiesForTable(table: TableDef): TrackedEntity[] {
30
49
  const bucket = this.buckets.get(table.name);
31
50
  return bucket ? Array.from(bucket.values()) : [];
@@ -8,6 +8,10 @@ export interface QueryContext {
8
8
 
9
9
  export type QueryInterceptor = (ctx: QueryContext, next: () => Promise<QueryResult[]>) => Promise<QueryResult[]>;
10
10
 
11
+ /**
12
+ * Pipeline for query interceptors.
13
+ * Interceptors can wrap query execution to add logging, tracing, caching, etc.
14
+ */
11
15
  export class InterceptorPipeline {
12
16
  private interceptors: QueryInterceptor[] = [];
13
17
 
@@ -20,10 +20,27 @@ const hideInternal = (obj: object, keys: string[]): void => {
20
20
  }
21
21
  };
22
22
 
23
+ /**
24
+ * Default implementation of a belongs-to reference.
25
+ * Manages a reference to a parent entity from a child entity through a foreign key.
26
+ *
27
+ * @template TParent The type of the parent entity.
28
+ */
23
29
  export class DefaultBelongsToReference<TParent> implements BelongsToReference<TParent> {
24
30
  private loaded = false;
25
31
  private current: TParent | null = null;
26
32
 
33
+ /**
34
+ * @param ctx The entity context for tracking changes.
35
+ * @param meta Metadata for the child entity.
36
+ * @param root The child entity instance (carrying the foreign key).
37
+ * @param relationName The name of the relation.
38
+ * @param relation Relation definition.
39
+ * @param rootTable Table definition of the child entity.
40
+ * @param loader Function to load the parent entity.
41
+ * @param createEntity Function to create entity instances from rows.
42
+ * @param targetKey The primary key of the target (parent) table.
43
+ */
27
44
  constructor(
28
45
  private readonly ctx: EntityContext,
29
46
  private readonly meta: EntityMeta<TableDef>,
@@ -20,10 +20,27 @@ const hideInternal = (obj: object, keys: string[]): void => {
20
20
  }
21
21
  };
22
22
 
23
+ /**
24
+ * Default implementation of a has-one reference.
25
+ * Manages a reference to a child entity where the child carries the foreign key.
26
+ *
27
+ * @template TChild The type of the child entity.
28
+ */
23
29
  export class DefaultHasOneReference<TChild> implements HasOneReference<TChild> {
24
30
  private loaded = false;
25
31
  private current: TChild | null = null;
26
32
 
33
+ /**
34
+ * @param ctx The entity context for tracking changes.
35
+ * @param meta Metadata for the parent entity.
36
+ * @param root The parent entity instance.
37
+ * @param relationName The name of the relation.
38
+ * @param relation Relation definition.
39
+ * @param rootTable Table definition of the parent entity.
40
+ * @param loader Function to load the child entity.
41
+ * @param createEntity Function to create entity instances from rows.
42
+ * @param localKey The local key on the parent entity used for the relation.
43
+ */
27
44
  constructor(
28
45
  private readonly ctx: EntityContext,
29
46
  private readonly meta: EntityMeta<TableDef>,