metal-orm 1.0.56 → 1.0.58
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.
- package/README.md +41 -33
- package/dist/index.cjs +1461 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +541 -114
- package/dist/index.d.ts +541 -114
- package/dist/index.js +1424 -195
- package/dist/index.js.map +1 -1
- package/package.json +69 -69
- package/src/codegen/naming-strategy.ts +3 -1
- package/src/codegen/typescript.ts +20 -10
- package/src/core/ast/aggregate-functions.ts +14 -0
- package/src/core/ast/builders.ts +38 -20
- package/src/core/ast/expression-builders.ts +70 -2
- package/src/core/ast/expression-nodes.ts +305 -274
- package/src/core/ast/expression-visitor.ts +11 -1
- package/src/core/ast/expression.ts +4 -0
- package/src/core/ast/query.ts +3 -0
- package/src/core/ddl/introspect/catalogs/mysql.ts +5 -0
- package/src/core/ddl/introspect/catalogs/sqlite.ts +3 -0
- package/src/core/ddl/introspect/functions/mssql.ts +13 -0
- package/src/core/ddl/introspect/mssql.ts +4 -0
- package/src/core/ddl/introspect/mysql.ts +4 -0
- package/src/core/ddl/introspect/sqlite.ts +4 -0
- package/src/core/dialect/abstract.ts +552 -531
- package/src/core/dialect/base/function-table-formatter.ts +9 -30
- package/src/core/dialect/base/sql-dialect.ts +24 -0
- package/src/core/dialect/mssql/functions.ts +40 -2
- package/src/core/dialect/mysql/functions.ts +16 -2
- package/src/core/dialect/postgres/functions.ts +66 -2
- package/src/core/dialect/postgres/index.ts +17 -4
- package/src/core/dialect/postgres/table-functions.ts +27 -0
- package/src/core/dialect/sqlite/functions.ts +34 -0
- package/src/core/dialect/sqlite/index.ts +17 -1
- package/src/core/driver/database-driver.ts +9 -1
- package/src/core/driver/mssql-driver.ts +3 -0
- package/src/core/driver/mysql-driver.ts +3 -0
- package/src/core/driver/postgres-driver.ts +3 -0
- package/src/core/driver/sqlite-driver.ts +3 -0
- package/src/core/execution/executors/mssql-executor.ts +5 -0
- package/src/core/execution/executors/mysql-executor.ts +5 -0
- package/src/core/execution/executors/postgres-executor.ts +5 -0
- package/src/core/execution/executors/sqlite-executor.ts +5 -0
- package/src/core/functions/array.ts +26 -0
- package/src/core/functions/control-flow.ts +69 -0
- package/src/core/functions/datetime.ts +50 -0
- package/src/core/functions/definitions/aggregate.ts +16 -0
- package/src/core/functions/definitions/control-flow.ts +24 -0
- package/src/core/functions/definitions/datetime.ts +36 -0
- package/src/core/functions/definitions/helpers.ts +29 -0
- package/src/core/functions/definitions/json.ts +49 -0
- package/src/core/functions/definitions/numeric.ts +55 -0
- package/src/core/functions/definitions/string.ts +43 -0
- package/src/core/functions/function-registry.ts +48 -0
- package/src/core/functions/group-concat-helpers.ts +57 -0
- package/src/core/functions/json.ts +38 -0
- package/src/core/functions/numeric.ts +14 -0
- package/src/core/functions/standard-strategy.ts +86 -115
- package/src/core/functions/standard-table-strategy.ts +13 -0
- package/src/core/functions/table-types.ts +15 -0
- package/src/core/functions/text.ts +57 -0
- package/src/core/sql/sql.ts +59 -38
- package/src/decorators/bootstrap.ts +41 -4
- package/src/index.ts +18 -11
- package/src/orm/entity-meta.ts +6 -3
- package/src/orm/entity.ts +81 -14
- package/src/orm/execute.ts +87 -20
- package/src/orm/hydration-context.ts +10 -0
- package/src/orm/identity-map.ts +19 -0
- package/src/orm/interceptor-pipeline.ts +4 -0
- package/src/orm/lazy-batch.ts +237 -54
- package/src/orm/relations/belongs-to.ts +19 -2
- package/src/orm/relations/has-many.ts +23 -9
- package/src/orm/relations/has-one.ts +19 -2
- package/src/orm/relations/many-to-many.ts +59 -4
- package/src/orm/save-graph-types.ts +2 -2
- package/src/orm/save-graph.ts +18 -18
- package/src/query-builder/relation-conditions.ts +80 -59
- package/src/query-builder/relation-service.ts +399 -95
- package/src/query-builder/relation-types.ts +2 -2
- package/src/query-builder/select.ts +124 -106
- package/src/schema/table-guards.ts +6 -0
- package/src/schema/types.ts +109 -85
|
@@ -1,131 +1,102 @@
|
|
|
1
|
+
|
|
1
2
|
import { FunctionStrategy, FunctionRenderer, FunctionRenderContext } from './types.js';
|
|
2
|
-
import { LiteralNode, OperandNode
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
/**
|
|
58
|
+
* @inheritDoc
|
|
59
|
+
*/
|
|
60
|
+
getRenderer(name: string): FunctionRenderer | undefined {
|
|
61
|
+
return this.registry.get(name);
|
|
62
|
+
}
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
+
|
package/src/core/sql/sql.ts
CHANGED
|
@@ -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
|
|
@@ -5,6 +5,10 @@ import {
|
|
|
5
5
|
belongsTo,
|
|
6
6
|
belongsToMany,
|
|
7
7
|
RelationKinds,
|
|
8
|
+
type HasManyRelation,
|
|
9
|
+
type HasOneRelation,
|
|
10
|
+
type BelongsToRelation,
|
|
11
|
+
type BelongsToManyRelation,
|
|
8
12
|
type RelationDef
|
|
9
13
|
} from '../schema/relation.js';
|
|
10
14
|
import { TableDef } from '../schema/table.js';
|
|
@@ -20,6 +24,14 @@ import {
|
|
|
20
24
|
} from '../orm/entity-metadata.js';
|
|
21
25
|
|
|
22
26
|
import { tableRef, type TableRef } from '../schema/table.js';
|
|
27
|
+
import {
|
|
28
|
+
SelectableKeys,
|
|
29
|
+
ColumnDef,
|
|
30
|
+
HasManyCollection,
|
|
31
|
+
HasOneReference,
|
|
32
|
+
BelongsToReference,
|
|
33
|
+
ManyToManyCollection
|
|
34
|
+
} from '../schema/types.js';
|
|
23
35
|
|
|
24
36
|
const unwrapTarget = (target: EntityOrTableTargetResolver): EntityOrTableTarget => {
|
|
25
37
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
@@ -143,14 +155,39 @@ export const getTableDefFromEntity = <TTable extends TableDef = TableDef>(ctor:
|
|
|
143
155
|
* @param ctor - The entity constructor.
|
|
144
156
|
* @returns A select query builder for the entity.
|
|
145
157
|
*/
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
158
|
+
type NonFunctionKeys<T> = {
|
|
159
|
+
[K in keyof T]-?: T[K] extends (...args: unknown[]) => unknown ? never : K
|
|
160
|
+
}[keyof T];
|
|
161
|
+
|
|
162
|
+
type RelationKeys<TEntity extends object> =
|
|
163
|
+
Exclude<NonFunctionKeys<TEntity>, SelectableKeys<TEntity>> & string;
|
|
164
|
+
|
|
165
|
+
type EntityTable<TEntity extends object> =
|
|
166
|
+
Omit<TableDef<{ [K in SelectableKeys<TEntity>]: ColumnDef }>, 'relations'> & {
|
|
167
|
+
relations: {
|
|
168
|
+
[K in RelationKeys<TEntity>]:
|
|
169
|
+
NonNullable<TEntity[K]> extends HasManyCollection<infer TChild>
|
|
170
|
+
? HasManyRelation<EntityTable<NonNullable<TChild> & object>>
|
|
171
|
+
: NonNullable<TEntity[K]> extends ManyToManyCollection<infer TTarget>
|
|
172
|
+
? BelongsToManyRelation<EntityTable<NonNullable<TTarget> & object>>
|
|
173
|
+
: NonNullable<TEntity[K]> extends HasOneReference<infer TChild>
|
|
174
|
+
? HasOneRelation<EntityTable<NonNullable<TChild> & object>>
|
|
175
|
+
: NonNullable<TEntity[K]> extends BelongsToReference<infer TParent>
|
|
176
|
+
? BelongsToRelation<EntityTable<NonNullable<TParent> & object>>
|
|
177
|
+
: NonNullable<TEntity[K]> extends object
|
|
178
|
+
? BelongsToRelation<EntityTable<NonNullable<TEntity[K]> & object>>
|
|
179
|
+
: never;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const selectFromEntity = <TEntity extends object>(
|
|
184
|
+
ctor: EntityConstructor<TEntity>
|
|
185
|
+
): SelectQueryBuilder<unknown, EntityTable<TEntity>> => {
|
|
149
186
|
const table = getTableDefFromEntity(ctor);
|
|
150
187
|
if (!table) {
|
|
151
188
|
throw new Error(`Entity '${ctor.name}' is not registered with decorators or has not been bootstrapped`);
|
|
152
189
|
}
|
|
153
|
-
return new SelectQueryBuilder(table as
|
|
190
|
+
return new SelectQueryBuilder(table as unknown as EntityTable<TEntity>);
|
|
154
191
|
};
|
|
155
192
|
|
|
156
193
|
/**
|
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';
|
package/src/orm/entity-meta.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table.js';
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { RelationIncludeOptions } from '../query-builder/relation-types.js';
|
|
2
3
|
import { EntityContext } from './entity-context.js';
|
|
3
4
|
import { RelationMap } from '../schema/types.js';
|
|
4
5
|
|
|
@@ -18,8 +19,10 @@ export interface EntityMeta<TTable extends TableDef> {
|
|
|
18
19
|
ctx: EntityContext;
|
|
19
20
|
/** Table definition */
|
|
20
21
|
table: TTable;
|
|
21
|
-
/** Relations that should be loaded lazily */
|
|
22
|
-
lazyRelations: (keyof RelationMap<TTable>)[];
|
|
22
|
+
/** Relations that should be loaded lazily */
|
|
23
|
+
lazyRelations: (keyof RelationMap<TTable>)[];
|
|
24
|
+
/** Include options for lazy relations */
|
|
25
|
+
lazyRelationOptions: Map<string, RelationIncludeOptions>;
|
|
23
26
|
/** Cache for relation promises */
|
|
24
27
|
relationCache: Map<string, Promise<unknown>>;
|
|
25
28
|
/** Hydration data for relations */
|