metal-orm 1.0.14 → 1.0.16
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 +69 -67
- package/dist/decorators/index.cjs +1983 -224
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +6 -6
- package/dist/decorators/index.d.ts +6 -6
- package/dist/decorators/index.js +1982 -224
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +5284 -3751
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +524 -169
- package/dist/index.d.ts +524 -169
- package/dist/index.js +5197 -3736
- package/dist/index.js.map +1 -1
- package/dist/{select-CCp1oz9p.d.cts → select-BKZrMRCQ.d.cts} +555 -94
- package/dist/{select-CCp1oz9p.d.ts → select-BKZrMRCQ.d.ts} +555 -94
- package/package.json +1 -1
- package/src/codegen/naming-strategy.ts +64 -0
- package/src/codegen/typescript.ts +19 -21
- package/src/core/ast/adapters.ts +21 -0
- package/src/core/ast/aggregate-functions.ts +13 -13
- package/src/core/ast/builders.ts +56 -43
- package/src/core/ast/expression-builders.ts +34 -34
- package/src/core/ast/expression-nodes.ts +18 -16
- package/src/core/ast/expression-visitor.ts +122 -69
- package/src/core/ast/expression.ts +6 -4
- package/src/core/ast/join-metadata.ts +15 -0
- package/src/core/ast/join-node.ts +22 -20
- package/src/core/ast/join.ts +5 -5
- package/src/core/ast/query.ts +52 -88
- package/src/core/ast/types.ts +20 -0
- package/src/core/ast/window-functions.ts +55 -55
- package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
- package/src/core/ddl/introspect/catalogs/index.ts +1 -0
- package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
- package/src/core/ddl/introspect/context.ts +9 -0
- package/src/core/ddl/introspect/functions/postgres.ts +26 -0
- package/src/core/ddl/introspect/mssql.ts +149 -149
- package/src/core/ddl/introspect/mysql.ts +99 -99
- package/src/core/ddl/introspect/postgres.ts +245 -154
- package/src/core/ddl/introspect/registry.ts +26 -0
- package/src/core/ddl/introspect/run-select.ts +25 -0
- package/src/core/ddl/introspect/sqlite.ts +7 -7
- package/src/core/ddl/introspect/types.ts +23 -19
- package/src/core/ddl/introspect/utils.ts +1 -1
- package/src/core/ddl/naming-strategy.ts +10 -0
- package/src/core/ddl/schema-dialect.ts +41 -0
- package/src/core/ddl/schema-diff.ts +211 -179
- package/src/core/ddl/schema-generator.ts +17 -90
- package/src/core/ddl/schema-introspect.ts +25 -32
- package/src/core/ddl/schema-plan-executor.ts +17 -0
- package/src/core/ddl/schema-types.ts +46 -39
- package/src/core/ddl/sql-writing.ts +170 -0
- package/src/core/dialect/abstract.ts +172 -126
- package/src/core/dialect/base/cte-compiler.ts +33 -0
- package/src/core/dialect/base/function-table-formatter.ts +132 -0
- package/src/core/dialect/base/groupby-compiler.ts +21 -0
- package/src/core/dialect/base/join-compiler.ts +26 -0
- package/src/core/dialect/base/orderby-compiler.ts +21 -0
- package/src/core/dialect/base/pagination-strategy.ts +32 -0
- package/src/core/dialect/base/returning-strategy.ts +56 -0
- package/src/core/dialect/base/sql-dialect.ts +181 -204
- package/src/core/dialect/dialect-factory.ts +91 -0
- package/src/core/dialect/mssql/functions.ts +101 -0
- package/src/core/dialect/mssql/index.ts +128 -126
- package/src/core/dialect/mysql/functions.ts +101 -0
- package/src/core/dialect/mysql/index.ts +20 -18
- package/src/core/dialect/postgres/functions.ts +95 -0
- package/src/core/dialect/postgres/index.ts +30 -28
- package/src/core/dialect/sqlite/functions.ts +115 -0
- package/src/core/dialect/sqlite/index.ts +30 -28
- package/src/core/driver/database-driver.ts +11 -0
- package/src/core/driver/mssql-driver.ts +20 -0
- package/src/core/driver/mysql-driver.ts +20 -0
- package/src/core/driver/postgres-driver.ts +20 -0
- package/src/core/driver/sqlite-driver.ts +20 -0
- package/src/core/execution/db-executor.ts +63 -0
- package/src/core/execution/executors/mssql-executor.ts +39 -0
- package/src/core/execution/executors/mysql-executor.ts +47 -0
- package/src/core/execution/executors/postgres-executor.ts +32 -0
- package/src/core/execution/executors/sqlite-executor.ts +31 -0
- package/src/core/functions/datetime.ts +132 -0
- package/src/core/functions/numeric.ts +179 -0
- package/src/core/functions/standard-strategy.ts +47 -0
- package/src/core/functions/text.ts +147 -0
- package/src/core/functions/types.ts +18 -0
- package/src/core/hydration/types.ts +57 -0
- package/src/decorators/bootstrap.ts +10 -0
- package/src/decorators/column.ts +13 -4
- package/src/decorators/relations.ts +15 -0
- package/src/index.ts +37 -19
- package/src/orm/entity-context.ts +30 -0
- package/src/orm/entity-meta.ts +2 -2
- package/src/orm/entity-metadata.ts +8 -6
- package/src/orm/entity.ts +72 -41
- package/src/orm/execute.ts +42 -25
- package/src/orm/execution-context.ts +12 -0
- package/src/orm/hydration-context.ts +14 -0
- package/src/orm/hydration.ts +25 -17
- package/src/orm/identity-map.ts +4 -0
- package/src/orm/interceptor-pipeline.ts +29 -0
- package/src/orm/lazy-batch.ts +50 -6
- package/src/orm/orm-session.ts +234 -0
- package/src/orm/orm.ts +58 -0
- package/src/orm/query-logger.ts +1 -1
- package/src/orm/relation-change-processor.ts +48 -3
- package/src/orm/relations/belongs-to.ts +45 -44
- package/src/orm/relations/has-many.ts +44 -43
- package/src/orm/relations/has-one.ts +140 -0
- package/src/orm/relations/many-to-many.ts +46 -45
- package/src/orm/transaction-runner.ts +1 -1
- package/src/orm/unit-of-work.ts +66 -61
- package/src/query-builder/delete.ts +22 -5
- package/src/query-builder/hydration-manager.ts +2 -1
- package/src/query-builder/hydration-planner.ts +8 -7
- package/src/query-builder/insert.ts +22 -5
- package/src/query-builder/relation-conditions.ts +9 -8
- package/src/query-builder/relation-service.ts +3 -2
- package/src/query-builder/select.ts +575 -64
- package/src/query-builder/update.ts +22 -5
- package/src/schema/column.ts +246 -246
- package/src/schema/relation.ts +35 -1
- package/src/schema/table.ts +28 -28
- package/src/schema/types.ts +41 -31
- package/src/orm/db-executor.ts +0 -11
- package/src/orm/orm-context.ts +0 -159
package/package.json
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { TableNode, FunctionTableNode } from '../core/ast/query.js';
|
|
2
|
+
import type { ColumnNode } from '../core/ast/expression.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Strategy interface for converting database names to TypeScript identifiers
|
|
6
|
+
*/
|
|
7
|
+
export interface NamingStrategy {
|
|
8
|
+
/**
|
|
9
|
+
* Converts a table name to a TypeScript symbol name
|
|
10
|
+
* @param table - Table node, function table node, or name
|
|
11
|
+
* @returns Valid TypeScript identifier
|
|
12
|
+
*/
|
|
13
|
+
tableToSymbol(table: TableNode | FunctionTableNode | string): string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Converts a column reference to a property name
|
|
17
|
+
* @param column - Column node
|
|
18
|
+
* @returns Valid TypeScript property name
|
|
19
|
+
*/
|
|
20
|
+
columnToProperty(column: ColumnNode): string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default naming strategy that maintains backward compatibility
|
|
25
|
+
* with the original capitalize() behavior
|
|
26
|
+
*/
|
|
27
|
+
export class DefaultNamingStrategy implements NamingStrategy {
|
|
28
|
+
/**
|
|
29
|
+
* Converts table names to TypeScript symbols
|
|
30
|
+
* @param table - Table node, function table node, or string name
|
|
31
|
+
* @returns Capitalized table name (handles schema-qualified names)
|
|
32
|
+
*/
|
|
33
|
+
tableToSymbol(table: TableNode | FunctionTableNode | string): string {
|
|
34
|
+
const tableName = typeof table === 'string' ? table : table.name;
|
|
35
|
+
|
|
36
|
+
// Handle schema-qualified names (e.g., "auth.user" → "AuthUser")
|
|
37
|
+
if (tableName.includes('.')) {
|
|
38
|
+
return tableName.split('.')
|
|
39
|
+
.map(part => this.capitalize(part))
|
|
40
|
+
.join('');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return this.capitalize(tableName);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Converts column references to property names
|
|
48
|
+
* @param column - Column node
|
|
49
|
+
* @returns Column name as-is (for backward compatibility)
|
|
50
|
+
*/
|
|
51
|
+
columnToProperty(column: ColumnNode): string {
|
|
52
|
+
return column.name;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Capitalizes the first letter of a string
|
|
57
|
+
* @param s - String to capitalize
|
|
58
|
+
* @returns Capitalized string
|
|
59
|
+
*/
|
|
60
|
+
private capitalize(s: string): string {
|
|
61
|
+
if (!s) return s;
|
|
62
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -23,13 +23,9 @@ import {
|
|
|
23
23
|
import { SQL_OPERATOR_REGISTRY } from '../core/sql/sql-operator-config.js';
|
|
24
24
|
import { SqlOperator } from '../core/sql/sql.js';
|
|
25
25
|
import { isRelationAlias } from '../query-builder/relation-alias.js';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @param s - String to capitalize
|
|
30
|
-
* @returns Capitalized string
|
|
31
|
-
*/
|
|
32
|
-
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
26
|
+
import { HydrationMetadata } from '../core/hydration/types.js';
|
|
27
|
+
import { getJoinRelationName } from '../core/ast/join-metadata.js';
|
|
28
|
+
import { NamingStrategy, DefaultNamingStrategy } from './naming-strategy.js';
|
|
33
29
|
|
|
34
30
|
const assertNever = (value: never): never => {
|
|
35
31
|
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
@@ -39,6 +35,7 @@ const assertNever = (value: never): never => {
|
|
|
39
35
|
* Generates TypeScript code from query AST nodes
|
|
40
36
|
*/
|
|
41
37
|
export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVisitor<string> {
|
|
38
|
+
constructor(private namingStrategy: NamingStrategy = new DefaultNamingStrategy()) {}
|
|
42
39
|
|
|
43
40
|
/**
|
|
44
41
|
* Generates TypeScript code from a query AST
|
|
@@ -59,7 +56,7 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
59
56
|
*/
|
|
60
57
|
private buildSelectLines(ast: SelectQueryNode): string[] {
|
|
61
58
|
const lines: string[] = [];
|
|
62
|
-
const hydration = ast.meta?.hydration;
|
|
59
|
+
const hydration = (ast.meta as HydrationMetadata | undefined)?.hydration;
|
|
63
60
|
const hydratedRelations = new Set(hydration?.relations?.map(r => r.name) ?? []);
|
|
64
61
|
|
|
65
62
|
const selections = ast.columns
|
|
@@ -75,26 +72,27 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
75
72
|
lines.push(` ${sel}${index < selections.length - 1 ? ',' : ''}`);
|
|
76
73
|
});
|
|
77
74
|
lines.push(`})`);
|
|
78
|
-
lines.push(`.from(${
|
|
75
|
+
lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
|
|
79
76
|
|
|
80
77
|
if (ast.distinct && ast.distinct.length) {
|
|
81
|
-
const cols = ast.distinct.map(c => `${
|
|
78
|
+
const cols = ast.distinct.map(c => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(', ');
|
|
82
79
|
lines.push(`.distinct(${cols})`);
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
ast.joins.forEach(join => {
|
|
86
|
-
|
|
83
|
+
const relationName = getJoinRelationName(join);
|
|
84
|
+
if (relationName && hydratedRelations.has(relationName)) {
|
|
87
85
|
return;
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
if (
|
|
88
|
+
if (relationName) {
|
|
91
89
|
if (join.kind === 'INNER') {
|
|
92
|
-
lines.push(`.joinRelation('${
|
|
90
|
+
lines.push(`.joinRelation('${relationName}')`);
|
|
93
91
|
} else {
|
|
94
|
-
lines.push(`.joinRelation('${
|
|
92
|
+
lines.push(`.joinRelation('${relationName}', '${join.kind}')`);
|
|
95
93
|
}
|
|
96
94
|
} else {
|
|
97
|
-
const table =
|
|
95
|
+
const table = this.namingStrategy.tableToSymbol(join.table);
|
|
98
96
|
const cond = this.printExpression(join.condition);
|
|
99
97
|
let method = 'innerJoin';
|
|
100
98
|
if (join.kind === 'LEFT') method = 'leftJoin';
|
|
@@ -118,7 +116,7 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
118
116
|
}
|
|
119
117
|
|
|
120
118
|
if (ast.groupBy && ast.groupBy.length) {
|
|
121
|
-
const cols = ast.groupBy.map(c => `${
|
|
119
|
+
const cols = ast.groupBy.map(c => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(', ');
|
|
122
120
|
lines.push(`.groupBy(${cols})`);
|
|
123
121
|
}
|
|
124
122
|
|
|
@@ -128,7 +126,7 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
128
126
|
|
|
129
127
|
if (ast.orderBy && ast.orderBy.length) {
|
|
130
128
|
ast.orderBy.forEach(o => {
|
|
131
|
-
lines.push(`.orderBy(${
|
|
129
|
+
lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
|
|
132
130
|
});
|
|
133
131
|
}
|
|
134
132
|
|
|
@@ -289,7 +287,7 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
289
287
|
* @returns TypeScript code representation
|
|
290
288
|
*/
|
|
291
289
|
private printColumnOperand(column: ColumnNode): string {
|
|
292
|
-
return `${
|
|
290
|
+
return `${this.namingStrategy.tableToSymbol(column.table)}.${column.name}`;
|
|
293
291
|
}
|
|
294
292
|
|
|
295
293
|
/**
|
|
@@ -318,7 +316,7 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
318
316
|
* @returns TypeScript code representation
|
|
319
317
|
*/
|
|
320
318
|
private printJsonPathOperand(json: JsonPathNode): string {
|
|
321
|
-
return `jsonPath(${
|
|
319
|
+
return `jsonPath(${this.namingStrategy.tableToSymbol(json.column.table)}.${json.column.name}, '${json.path}')`;
|
|
322
320
|
}
|
|
323
321
|
|
|
324
322
|
/**
|
|
@@ -361,14 +359,14 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
361
359
|
|
|
362
360
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
363
361
|
const partitionClause =
|
|
364
|
-
'PARTITION BY ' + node.partitionBy.map(col => `${
|
|
362
|
+
'PARTITION BY ' + node.partitionBy.map(col => `${this.namingStrategy.tableToSymbol(col.table)}.${col.name}`).join(', ');
|
|
365
363
|
parts.push(partitionClause);
|
|
366
364
|
}
|
|
367
365
|
|
|
368
366
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
369
367
|
const orderClause =
|
|
370
368
|
'ORDER BY ' +
|
|
371
|
-
node.orderBy.map(o => `${
|
|
369
|
+
node.orderBy.map(o => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(', ');
|
|
372
370
|
parts.push(orderClause);
|
|
373
371
|
}
|
|
374
372
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ColumnDef } from '../../schema/column.js';
|
|
2
|
+
import { TableDef } from '../../schema/table.js';
|
|
3
|
+
import { ColumnRef, TableRef } from './types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Adapts a schema ColumnDef to an AST-friendly ColumnRef.
|
|
7
|
+
*/
|
|
8
|
+
export const toColumnRef = (col: ColumnRef | ColumnDef): ColumnRef => ({
|
|
9
|
+
name: col.name,
|
|
10
|
+
table: col.table,
|
|
11
|
+
alias: (col as ColumnRef).alias
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Adapts a schema TableDef to an AST-friendly TableRef.
|
|
16
|
+
*/
|
|
17
|
+
export const toTableRef = (table: TableRef | TableDef): TableRef => ({
|
|
18
|
+
name: table.name,
|
|
19
|
+
schema: table.schema,
|
|
20
|
+
alias: (table as TableRef).alias
|
|
21
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const buildAggregate = (name: string) => (col:
|
|
6
|
-
type: 'Function',
|
|
7
|
-
name,
|
|
8
|
-
args: [columnOperand(col)]
|
|
9
|
-
});
|
|
1
|
+
import { ColumnNode, FunctionNode } from './expression-nodes.js';
|
|
2
|
+
import { columnOperand } from './expression-builders.js';
|
|
3
|
+
import { ColumnRef } from './types.js';
|
|
4
|
+
|
|
5
|
+
const buildAggregate = (name: string) => (col: ColumnRef | ColumnNode): FunctionNode => ({
|
|
6
|
+
type: 'Function',
|
|
7
|
+
name,
|
|
8
|
+
args: [columnOperand(col)]
|
|
9
|
+
});
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates a COUNT function expression
|
|
@@ -17,10 +17,10 @@ export const count = buildAggregate('COUNT');
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Creates a SUM function expression
|
|
20
|
-
* @param col - Column to sum
|
|
21
|
-
* @returns Function node with SUM
|
|
22
|
-
*/
|
|
23
|
-
export const sum = buildAggregate('SUM');
|
|
20
|
+
* @param col - Column to sum
|
|
21
|
+
* @returns Function node with SUM
|
|
22
|
+
*/
|
|
23
|
+
export const sum = buildAggregate('SUM');
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates an AVG function expression
|
package/src/core/ast/builders.ts
CHANGED
|
@@ -1,43 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* @param
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
import { ColumnNode } from './expression-nodes.js';
|
|
2
|
+
import { TableNode, FunctionTableNode } from './query.js';
|
|
3
|
+
import { ColumnRef, TableRef } from './types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Builds or normalizes a column AST node from a column definition or existing node
|
|
7
|
+
* @param table - Table definition providing a default table name
|
|
8
|
+
* @param column - Column definition or existing column node
|
|
9
|
+
*/
|
|
10
|
+
export const buildColumnNode = (table: TableRef, column: ColumnRef | ColumnNode): ColumnNode => {
|
|
11
|
+
if ((column as ColumnNode).type === 'Column') {
|
|
12
|
+
return column as ColumnNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const def = column as ColumnRef;
|
|
16
|
+
return {
|
|
17
|
+
type: 'Column',
|
|
18
|
+
table: def.table || table.name,
|
|
19
|
+
name: def.name
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds column AST nodes for a list of column names
|
|
25
|
+
* @param table - Table definition providing the table name
|
|
26
|
+
* @param names - Column names
|
|
27
|
+
*/
|
|
28
|
+
export const buildColumnNodes = (table: TableRef, names: string[]): ColumnNode[] =>
|
|
29
|
+
names.map(name => ({
|
|
30
|
+
type: 'Column',
|
|
31
|
+
table: table.name,
|
|
32
|
+
name
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Builds a table AST node for the provided table definition
|
|
37
|
+
* @param table - Table definition
|
|
38
|
+
*/
|
|
39
|
+
export const createTableNode = (table: TableRef): TableNode => ({
|
|
40
|
+
type: 'Table',
|
|
41
|
+
name: table.name
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a FunctionTable node for expressions like `function_name(args...)` used in FROM
|
|
46
|
+
*/
|
|
47
|
+
export const fnTable = (name: string, args: any[] = [], alias?: string, opts?: { lateral?: boolean; withOrdinality?: boolean; columnAliases?: string[]; schema?: string }): FunctionTableNode => ({
|
|
48
|
+
type: 'FunctionTable',
|
|
49
|
+
name,
|
|
50
|
+
args,
|
|
51
|
+
alias,
|
|
52
|
+
lateral: opts?.lateral,
|
|
53
|
+
withOrdinality: opts?.withOrdinality,
|
|
54
|
+
columnAliases: opts?.columnAliases,
|
|
55
|
+
schema: opts?.schema
|
|
56
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ColumnDef } from '../../schema/column.js';
|
|
2
1
|
import { SelectQueryNode } from './query.js';
|
|
3
2
|
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
+
import { ColumnRef } from './types.js';
|
|
4
4
|
import {
|
|
5
5
|
ColumnNode,
|
|
6
6
|
FunctionNode,
|
|
@@ -37,9 +37,9 @@ export const valueToOperand = (value: unknown): OperandNode => {
|
|
|
37
37
|
return value as OperandNode;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
const toNode = (col:
|
|
40
|
+
const toNode = (col: ColumnRef | OperandNode): OperandNode => {
|
|
41
41
|
if (isOperandNode(col)) return col as OperandNode;
|
|
42
|
-
const def = col as
|
|
42
|
+
const def = col as ColumnRef;
|
|
43
43
|
return { type: 'Column', table: def.table || 'unknown', name: def.name };
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -48,20 +48,20 @@ const toLiteralNode = (value: string | number | boolean | null): LiteralNode =>
|
|
|
48
48
|
value
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
const toOperand = (val: OperandNode |
|
|
51
|
+
const toOperand = (val: OperandNode | ColumnRef | string | number | boolean | null): OperandNode => {
|
|
52
52
|
if (val === null) return { type: 'Literal', value: null };
|
|
53
53
|
if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {
|
|
54
54
|
return { type: 'Literal', value: val };
|
|
55
55
|
}
|
|
56
|
-
return toNode(val as OperandNode |
|
|
56
|
+
return toNode(val as OperandNode | ColumnRef);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
export const columnOperand = (col:
|
|
59
|
+
export const columnOperand = (col: ColumnRef | ColumnNode): ColumnNode => toNode(col) as ColumnNode;
|
|
60
60
|
|
|
61
61
|
const createBinaryExpression = (
|
|
62
62
|
operator: SqlOperator,
|
|
63
|
-
left: OperandNode |
|
|
64
|
-
right: OperandNode |
|
|
63
|
+
left: OperandNode | ColumnRef,
|
|
64
|
+
right: OperandNode | ColumnRef | string | number | boolean | null,
|
|
65
65
|
escape?: string
|
|
66
66
|
): BinaryExpressionNode => {
|
|
67
67
|
const node: BinaryExpressionNode = {
|
|
@@ -84,15 +84,15 @@ const createBinaryExpression = (
|
|
|
84
84
|
* @param right - Right operand
|
|
85
85
|
* @returns Binary expression node with equality operator
|
|
86
86
|
*/
|
|
87
|
-
export const eq = (left: OperandNode |
|
|
87
|
+
export const eq = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number | boolean): BinaryExpressionNode =>
|
|
88
88
|
createBinaryExpression('=', left, right);
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
91
|
* Creates a not equal expression (left != right)
|
|
92
92
|
*/
|
|
93
93
|
export const neq = (
|
|
94
|
-
left: OperandNode |
|
|
95
|
-
right: OperandNode |
|
|
94
|
+
left: OperandNode | ColumnRef,
|
|
95
|
+
right: OperandNode | ColumnRef | string | number | boolean
|
|
96
96
|
): BinaryExpressionNode => createBinaryExpression('!=', left, right);
|
|
97
97
|
|
|
98
98
|
/**
|
|
@@ -101,13 +101,13 @@ export const neq = (
|
|
|
101
101
|
* @param right - Right operand
|
|
102
102
|
* @returns Binary expression node with greater-than operator
|
|
103
103
|
*/
|
|
104
|
-
export const gt = (left: OperandNode |
|
|
104
|
+
export const gt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
105
105
|
createBinaryExpression('>', left, right);
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* Creates a greater than or equal expression (left >= right)
|
|
109
109
|
*/
|
|
110
|
-
export const gte = (left: OperandNode |
|
|
110
|
+
export const gte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
111
111
|
createBinaryExpression('>=', left, right);
|
|
112
112
|
|
|
113
113
|
/**
|
|
@@ -116,13 +116,13 @@ export const gte = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDe
|
|
|
116
116
|
* @param right - Right operand
|
|
117
117
|
* @returns Binary expression node with less-than operator
|
|
118
118
|
*/
|
|
119
|
-
export const lt = (left: OperandNode |
|
|
119
|
+
export const lt = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
120
120
|
createBinaryExpression('<', left, right);
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* Creates a less than or equal expression (left <= right)
|
|
124
124
|
*/
|
|
125
|
-
export const lte = (left: OperandNode |
|
|
125
|
+
export const lte = (left: OperandNode | ColumnRef, right: OperandNode | ColumnRef | string | number): BinaryExpressionNode =>
|
|
126
126
|
createBinaryExpression('<=', left, right);
|
|
127
127
|
|
|
128
128
|
/**
|
|
@@ -132,7 +132,7 @@ export const lte = (left: OperandNode | ColumnDef, right: OperandNode | ColumnDe
|
|
|
132
132
|
* @param escape - Optional escape character
|
|
133
133
|
* @returns Binary expression node with LIKE operator
|
|
134
134
|
*/
|
|
135
|
-
export const like = (left: OperandNode |
|
|
135
|
+
export const like = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
136
136
|
createBinaryExpression('LIKE', left, pattern, escape);
|
|
137
137
|
|
|
138
138
|
/**
|
|
@@ -142,7 +142,7 @@ export const like = (left: OperandNode | ColumnDef, pattern: string, escape?: st
|
|
|
142
142
|
* @param escape - Optional escape character
|
|
143
143
|
* @returns Binary expression node with NOT LIKE operator
|
|
144
144
|
*/
|
|
145
|
-
export const notLike = (left: OperandNode |
|
|
145
|
+
export const notLike = (left: OperandNode | ColumnRef, pattern: string, escape?: string): BinaryExpressionNode =>
|
|
146
146
|
createBinaryExpression('NOT LIKE', left, pattern, escape);
|
|
147
147
|
|
|
148
148
|
/**
|
|
@@ -172,7 +172,7 @@ export const or = (...operands: ExpressionNode[]): LogicalExpressionNode => ({
|
|
|
172
172
|
* @param left - Operand to check for null
|
|
173
173
|
* @returns Null expression node with IS NULL operator
|
|
174
174
|
*/
|
|
175
|
-
export const isNull = (left: OperandNode |
|
|
175
|
+
export const isNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
176
176
|
type: 'NullExpression',
|
|
177
177
|
left: toNode(left),
|
|
178
178
|
operator: 'IS NULL'
|
|
@@ -183,7 +183,7 @@ export const isNull = (left: OperandNode | ColumnDef): NullExpressionNode => ({
|
|
|
183
183
|
* @param left - Operand to check for non-null
|
|
184
184
|
* @returns Null expression node with IS NOT NULL operator
|
|
185
185
|
*/
|
|
186
|
-
export const isNotNull = (left: OperandNode |
|
|
186
|
+
export const isNotNull = (left: OperandNode | ColumnRef): NullExpressionNode => ({
|
|
187
187
|
type: 'NullExpression',
|
|
188
188
|
left: toNode(left),
|
|
189
189
|
operator: 'IS NOT NULL'
|
|
@@ -191,7 +191,7 @@ export const isNotNull = (left: OperandNode | ColumnDef): NullExpressionNode =>
|
|
|
191
191
|
|
|
192
192
|
const createInExpression = (
|
|
193
193
|
operator: 'IN' | 'NOT IN',
|
|
194
|
-
left: OperandNode |
|
|
194
|
+
left: OperandNode | ColumnRef,
|
|
195
195
|
values: (string | number | LiteralNode)[]
|
|
196
196
|
): InExpressionNode => ({
|
|
197
197
|
type: 'InExpression',
|
|
@@ -206,7 +206,7 @@ const createInExpression = (
|
|
|
206
206
|
* @param values - Values to check against
|
|
207
207
|
* @returns IN expression node
|
|
208
208
|
*/
|
|
209
|
-
export const inList = (left: OperandNode |
|
|
209
|
+
export const inList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
210
210
|
createInExpression('IN', left, values);
|
|
211
211
|
|
|
212
212
|
/**
|
|
@@ -215,14 +215,14 @@ export const inList = (left: OperandNode | ColumnDef, values: (string | number |
|
|
|
215
215
|
* @param values - Values to check against
|
|
216
216
|
* @returns NOT IN expression node
|
|
217
217
|
*/
|
|
218
|
-
export const notInList = (left: OperandNode |
|
|
218
|
+
export const notInList = (left: OperandNode | ColumnRef, values: (string | number | LiteralNode)[]): InExpressionNode =>
|
|
219
219
|
createInExpression('NOT IN', left, values);
|
|
220
220
|
|
|
221
221
|
const createBetweenExpression = (
|
|
222
222
|
operator: 'BETWEEN' | 'NOT BETWEEN',
|
|
223
|
-
left: OperandNode |
|
|
224
|
-
lower: OperandNode |
|
|
225
|
-
upper: OperandNode |
|
|
223
|
+
left: OperandNode | ColumnRef,
|
|
224
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
225
|
+
upper: OperandNode | ColumnRef | string | number
|
|
226
226
|
): BetweenExpressionNode => ({
|
|
227
227
|
type: 'BetweenExpression',
|
|
228
228
|
left: toNode(left),
|
|
@@ -239,9 +239,9 @@ const createBetweenExpression = (
|
|
|
239
239
|
* @returns BETWEEN expression node
|
|
240
240
|
*/
|
|
241
241
|
export const between = (
|
|
242
|
-
left: OperandNode |
|
|
243
|
-
lower: OperandNode |
|
|
244
|
-
upper: OperandNode |
|
|
242
|
+
left: OperandNode | ColumnRef,
|
|
243
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
244
|
+
upper: OperandNode | ColumnRef | string | number
|
|
245
245
|
): BetweenExpressionNode => createBetweenExpression('BETWEEN', left, lower, upper);
|
|
246
246
|
|
|
247
247
|
/**
|
|
@@ -252,9 +252,9 @@ export const between = (
|
|
|
252
252
|
* @returns NOT BETWEEN expression node
|
|
253
253
|
*/
|
|
254
254
|
export const notBetween = (
|
|
255
|
-
left: OperandNode |
|
|
256
|
-
lower: OperandNode |
|
|
257
|
-
upper: OperandNode |
|
|
255
|
+
left: OperandNode | ColumnRef,
|
|
256
|
+
lower: OperandNode | ColumnRef | string | number,
|
|
257
|
+
upper: OperandNode | ColumnRef | string | number
|
|
258
258
|
): BetweenExpressionNode => createBetweenExpression('NOT BETWEEN', left, lower, upper);
|
|
259
259
|
|
|
260
260
|
/**
|
|
@@ -263,7 +263,7 @@ export const notBetween = (
|
|
|
263
263
|
* @param path - JSON path expression
|
|
264
264
|
* @returns JSON path node
|
|
265
265
|
*/
|
|
266
|
-
export const jsonPath = (col:
|
|
266
|
+
export const jsonPath = (col: ColumnRef | ColumnNode, path: string): JsonPathNode => ({
|
|
267
267
|
type: 'JsonPath',
|
|
268
268
|
column: columnOperand(col),
|
|
269
269
|
path
|
|
@@ -276,8 +276,8 @@ export const jsonPath = (col: ColumnDef | ColumnNode, path: string): JsonPathNod
|
|
|
276
276
|
* @returns CASE expression node
|
|
277
277
|
*/
|
|
278
278
|
export const caseWhen = (
|
|
279
|
-
conditions: { when: ExpressionNode; then: OperandNode |
|
|
280
|
-
elseValue?: OperandNode |
|
|
279
|
+
conditions: { when: ExpressionNode; then: OperandNode | ColumnRef | string | number | boolean | null }[],
|
|
280
|
+
elseValue?: OperandNode | ColumnRef | string | number | boolean | null
|
|
281
281
|
): CaseExpressionNode => ({
|
|
282
282
|
type: 'CaseExpression',
|
|
283
283
|
conditions: conditions.map(c => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import type { SelectQueryNode, OrderByNode } from './query.js';
|
|
2
|
+
import { SqlOperator } from '../sql/sql.js';
|
|
3
|
+
import { ColumnRef } from './types.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* AST node representing a literal value
|
|
@@ -27,15 +27,17 @@ export interface ColumnNode {
|
|
|
27
27
|
/**
|
|
28
28
|
* AST node representing a function call
|
|
29
29
|
*/
|
|
30
|
-
export interface FunctionNode {
|
|
31
|
-
type: 'Function';
|
|
32
|
-
/** Function name (e.g., COUNT, SUM) */
|
|
33
|
-
name: string;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
export interface FunctionNode {
|
|
31
|
+
type: 'Function';
|
|
32
|
+
/** Function name (e.g., COUNT, SUM) */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Optional canonical function key for dialect-aware rendering */
|
|
35
|
+
fn?: string;
|
|
36
|
+
/** Function arguments */
|
|
37
|
+
args: OperandNode[];
|
|
38
|
+
/** Optional alias for the function result */
|
|
39
|
+
alias?: string;
|
|
40
|
+
}
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* AST node representing a JSON path expression
|
|
@@ -118,10 +120,10 @@ export const isOperandNode = (node: any): node is OperandNode => node && operand
|
|
|
118
120
|
export const isFunctionNode = (node: any): node is FunctionNode => node?.type === 'Function';
|
|
119
121
|
export const isCaseExpressionNode = (node: any): node is CaseExpressionNode => node?.type === 'CaseExpression';
|
|
120
122
|
export const isWindowFunctionNode = (node: any): node is WindowFunctionNode => node?.type === 'WindowFunction';
|
|
121
|
-
export const isExpressionSelectionNode = (
|
|
122
|
-
node:
|
|
123
|
-
): node is FunctionNode | CaseExpressionNode | WindowFunctionNode =>
|
|
124
|
-
isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
|
|
123
|
+
export const isExpressionSelectionNode = (
|
|
124
|
+
node: ColumnRef | FunctionNode | CaseExpressionNode | WindowFunctionNode
|
|
125
|
+
): node is FunctionNode | CaseExpressionNode | WindowFunctionNode =>
|
|
126
|
+
isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
|
|
125
127
|
|
|
126
128
|
/**
|
|
127
129
|
* AST node representing a binary expression (e.g., column = value)
|