metal-orm 1.0.7 → 1.0.9
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 +133 -121
- package/dist/decorators/index.cjs +2564 -0
- package/dist/decorators/index.cjs.map +1 -0
- package/dist/decorators/index.d.cts +53 -0
- package/dist/decorators/index.d.ts +53 -0
- package/dist/decorators/index.js +2530 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.cjs +4227 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +701 -0
- package/dist/index.d.ts +701 -0
- package/dist/index.js +4131 -0
- package/dist/index.js.map +1 -0
- package/dist/select-654m4qy8.d.cts +1522 -0
- package/dist/select-654m4qy8.d.ts +1522 -0
- package/package.json +27 -20
- package/src/codegen/typescript.ts +405 -393
- package/src/core/ast/aggregate-functions.ts +30 -0
- package/src/core/ast/builders.ts +43 -0
- package/src/core/ast/expression-builders.ts +310 -0
- package/src/core/ast/expression-nodes.ts +211 -0
- package/src/core/ast/expression-visitor.ts +99 -0
- package/src/core/ast/expression.ts +5 -0
- package/src/{utils → core/ast}/join-node.ts +20 -20
- package/src/{ast → core/ast}/join.ts +18 -18
- package/src/{ast → core/ast}/query.ts +113 -113
- package/src/core/ast/window-functions.ts +140 -0
- package/src/{dialect → core/dialect}/abstract.ts +94 -94
- package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
- package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
- package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
- package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
- package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
- package/src/decorators/bootstrap.ts +126 -0
- package/src/decorators/column.ts +78 -0
- package/src/decorators/entity.ts +36 -0
- package/src/decorators/index.ts +4 -0
- package/src/decorators/relations.ts +107 -0
- package/src/global.d.ts +1 -0
- package/src/index.ts +22 -22
- package/src/orm/db-executor.ts +11 -0
- package/src/orm/domain-event-bus.ts +52 -0
- package/src/{runtime → orm}/entity-meta.ts +52 -52
- package/src/orm/entity-metadata.ts +140 -0
- package/src/{runtime → orm}/entity.ts +252 -252
- package/src/{runtime → orm}/execute.ts +36 -36
- package/src/{runtime → orm}/hydration.ts +103 -103
- package/src/orm/identity-map.ts +37 -0
- package/src/{runtime → orm}/lazy-batch.ts +205 -205
- package/src/orm/orm-context.ts +154 -0
- package/src/orm/relation-change-processor.ts +140 -0
- package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
- package/src/{runtime → orm}/relations/has-many.ts +111 -111
- package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
- package/src/orm/runtime-types.ts +39 -0
- package/src/orm/transaction-runner.ts +17 -0
- package/src/orm/unit-of-work.ts +232 -0
- package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
- package/src/{builder → query-builder}/delete-query-state.ts +38 -42
- package/src/{builder → query-builder}/delete.ts +46 -57
- package/src/{builder → query-builder}/hydration-manager.ts +87 -87
- package/src/{builder → query-builder}/hydration-planner.ts +182 -182
- package/src/{builder → query-builder}/insert-query-state.ts +51 -62
- package/src/{builder → query-builder}/insert.ts +48 -59
- package/src/{builder → query-builder}/query-ast-service.ts +208 -226
- package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
- package/src/{builder → query-builder}/relation-conditions.ts +112 -112
- package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
- package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
- package/src/{builder → query-builder}/relation-service.ts +284 -284
- package/src/{builder → query-builder}/relation-types.ts +21 -21
- package/src/{builder → query-builder}/relation-utils.ts +12 -12
- package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
- package/src/{builder → query-builder}/select-query-state.ts +179 -179
- package/src/{builder → query-builder}/select.ts +78 -69
- package/src/{builder → query-builder}/update-query-state.ts +55 -59
- package/src/{builder → query-builder}/update.ts +50 -61
- package/src/schema/column.ts +25 -25
- package/src/schema/relation.ts +116 -116
- package/src/schema/table.ts +34 -34
- package/src/schema/types.ts +76 -76
- package/.github/workflows/publish-metal-orm.yml +0 -38
- package/ROADMAP.md +0 -125
- package/docs/CHANGES.md +0 -104
- package/docs/advanced-features.md +0 -176
- package/docs/api-reference.md +0 -31
- package/docs/dml-operations.md +0 -156
- package/docs/getting-started.md +0 -171
- package/docs/hydration.md +0 -115
- package/docs/index.md +0 -36
- package/docs/multi-dialect-support.md +0 -59
- package/docs/query-builder.md +0 -135
- package/docs/runtime.md +0 -105
- package/docs/schema-definition.md +0 -112
- package/metadata.json +0 -5
- package/playground/api/playground-api.ts +0 -94
- package/playground/index.html +0 -15
- package/playground/src/App.css +0 -1
- package/playground/src/App.tsx +0 -114
- package/playground/src/components/CodeDisplay.tsx +0 -43
- package/playground/src/components/QueryExecutor.tsx +0 -189
- package/playground/src/components/ResultsTable.tsx +0 -67
- package/playground/src/components/ResultsTabs.tsx +0 -105
- package/playground/src/components/ScenarioList.tsx +0 -56
- package/playground/src/components/logo.svg +0 -45
- package/playground/src/data/scenarios.ts +0 -2
- package/playground/src/main.tsx +0 -9
- package/playground/src/services/PlaygroundApiService.ts +0 -60
- package/postcss.config.cjs +0 -5
- package/sql_sql-ansi-cheatsheet-2025.md +0 -264
- package/src/ast/expression.ts +0 -658
- package/src/builder/operations/cte-manager.ts +0 -34
- package/src/builder/operations/filter-manager.ts +0 -68
- package/src/builder/operations/join-manager.ts +0 -36
- package/src/builder/operations/pagination-manager.ts +0 -36
- package/src/playground/features/playground/api/types.ts +0 -16
- package/src/playground/features/playground/clients/MockClient.ts +0 -17
- package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
- package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
- package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
- package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
- package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
- package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
- package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
- package/src/playground/features/playground/data/scenarios/index.ts +0 -29
- package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
- package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
- package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
- package/src/playground/features/playground/data/scenarios/types.ts +0 -70
- package/src/playground/features/playground/data/schema.ts +0 -91
- package/src/playground/features/playground/data/seed.ts +0 -104
- package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
- package/src/runtime/orm-context.ts +0 -539
- package/tests/belongs-to-many.test.ts +0 -57
- package/tests/between.test.ts +0 -43
- package/tests/case-expression.test.ts +0 -58
- package/tests/complex-exists.test.ts +0 -230
- package/tests/cte.test.ts +0 -118
- package/tests/dml.test.ts +0 -206
- package/tests/exists.test.ts +0 -127
- package/tests/like.test.ts +0 -33
- package/tests/orm-runtime.test.ts +0 -254
- package/tests/postgres.test.ts +0 -30
- package/tests/right-join.test.ts +0 -89
- package/tests/subquery-having.test.ts +0 -193
- package/tests/window-function.test.ts +0 -151
- package/tsconfig.json +0 -30
- package/tsup.config.ts +0 -10
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -14
- /package/src/{constants → core/sql}/sql.ts +0 -0
- /package/src/{runtime → orm}/als.ts +0 -0
- /package/src/{utils → query-builder}/relation-alias.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table';
|
|
2
|
-
import { ColumnDef } from '../schema/column';
|
|
3
|
-
import { SelectQueryNode, HydrationPlan } from '../ast/query';
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { ColumnDef } from '../schema/column.js';
|
|
3
|
+
import { SelectQueryNode, HydrationPlan } from '../core/ast/query.js';
|
|
4
4
|
import {
|
|
5
5
|
ColumnNode,
|
|
6
6
|
ExpressionNode,
|
|
@@ -11,27 +11,25 @@ import {
|
|
|
11
11
|
WindowFunctionNode,
|
|
12
12
|
exists,
|
|
13
13
|
notExists
|
|
14
|
-
} from '../ast/expression';
|
|
15
|
-
import { CompiledQuery, Dialect } from '../dialect/abstract';
|
|
16
|
-
import { SelectQueryState } from './select-query-state';
|
|
17
|
-
import { HydrationManager } from './hydration-manager';
|
|
14
|
+
} from '../core/ast/expression.js';
|
|
15
|
+
import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
|
|
16
|
+
import { SelectQueryState } from './select-query-state.js';
|
|
17
|
+
import { HydrationManager } from './hydration-manager.js';
|
|
18
18
|
import {
|
|
19
|
-
|
|
19
|
+
resolveSelectQueryBuilderDependencies,
|
|
20
20
|
SelectQueryBuilderContext,
|
|
21
21
|
SelectQueryBuilderDependencies,
|
|
22
22
|
SelectQueryBuilderEnvironment
|
|
23
|
-
} from './select-query-builder-deps';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import { OrmContext } from '../runtime/orm-context';
|
|
34
|
-
import { executeHydrated } from '../runtime/execute';
|
|
23
|
+
} from './select-query-builder-deps.js';
|
|
24
|
+
import { QueryAstService } from './query-ast-service.js';
|
|
25
|
+
import { ColumnSelector } from './column-selector.js';
|
|
26
|
+
import { RelationManager } from './relation-manager.js';
|
|
27
|
+
import { RelationIncludeOptions } from './relation-types.js';
|
|
28
|
+
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../core/sql/sql.js';
|
|
29
|
+
import { Entity, RelationMap } from '../schema/types.js';
|
|
30
|
+
import { OrmContext } from '../orm/orm-context.js';
|
|
31
|
+
import { executeHydrated } from '../orm/execute.js';
|
|
32
|
+
import { createJoinNode } from '../core/ast/join-node.js';
|
|
35
33
|
|
|
36
34
|
/**
|
|
37
35
|
* Main query builder class for constructing SQL SELECT queries
|
|
@@ -42,10 +40,6 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
42
40
|
private readonly env: SelectQueryBuilderEnvironment;
|
|
43
41
|
private readonly context: SelectQueryBuilderContext;
|
|
44
42
|
private readonly columnSelector: ColumnSelector;
|
|
45
|
-
private readonly cteManager: CteManager;
|
|
46
|
-
private readonly joinManager: JoinManager;
|
|
47
|
-
private readonly filterManager: FilterManager;
|
|
48
|
-
private readonly paginationManager: PaginationManager;
|
|
49
43
|
private readonly relationManager: RelationManager;
|
|
50
44
|
private readonly lazyRelations: Set<string>;
|
|
51
45
|
|
|
@@ -60,10 +54,10 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
60
54
|
table: TTable,
|
|
61
55
|
state?: SelectQueryState,
|
|
62
56
|
hydration?: HydrationManager,
|
|
63
|
-
dependencies?: SelectQueryBuilderDependencies
|
|
57
|
+
dependencies?: Partial<SelectQueryBuilderDependencies>,
|
|
64
58
|
lazyRelations?: Set<string>
|
|
65
59
|
) {
|
|
66
|
-
const deps = dependencies
|
|
60
|
+
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
67
61
|
this.env = { table, deps };
|
|
68
62
|
const initialState = state ?? deps.createState(table);
|
|
69
63
|
const initialHydration = hydration ?? deps.createHydration(table);
|
|
@@ -73,10 +67,6 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
73
67
|
};
|
|
74
68
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
75
69
|
this.columnSelector = new ColumnSelector(this.env);
|
|
76
|
-
this.cteManager = new CteManager(this.env);
|
|
77
|
-
this.joinManager = new JoinManager(this.env);
|
|
78
|
-
this.filterManager = new FilterManager(this.env);
|
|
79
|
-
this.paginationManager = new PaginationManager(this.env);
|
|
80
70
|
this.relationManager = new RelationManager(this.env);
|
|
81
71
|
}
|
|
82
72
|
|
|
@@ -87,15 +77,34 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
87
77
|
return new SelectQueryBuilder(this.env.table as TTable, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
private resolveQueryNode(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryNode {
|
|
91
|
-
return typeof (query as any).getAST === 'function'
|
|
92
|
-
? (query as SelectQueryBuilder<any, TableDef<any>>).getAST()
|
|
93
|
-
: (query as SelectQueryNode);
|
|
94
|
-
}
|
|
80
|
+
private resolveQueryNode(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryNode {
|
|
81
|
+
return typeof (query as any).getAST === 'function'
|
|
82
|
+
? (query as SelectQueryBuilder<any, TableDef<any>>).getAST()
|
|
83
|
+
: (query as SelectQueryNode);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private createChildBuilder<R, TChild extends TableDef>(table: TChild): SelectQueryBuilder<R, TChild> {
|
|
87
|
+
return new SelectQueryBuilder(table, undefined, undefined, this.env.deps);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private applyAst(
|
|
91
|
+
context: SelectQueryBuilderContext,
|
|
92
|
+
mutator: (service: QueryAstService) => SelectQueryState
|
|
93
|
+
): SelectQueryBuilderContext {
|
|
94
|
+
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
95
|
+
const nextState = mutator(astService);
|
|
96
|
+
return { state: nextState, hydration: context.hydration };
|
|
97
|
+
}
|
|
95
98
|
|
|
96
|
-
private
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
private applyJoin(
|
|
100
|
+
context: SelectQueryBuilderContext,
|
|
101
|
+
table: TableDef,
|
|
102
|
+
condition: BinaryExpressionNode,
|
|
103
|
+
kind: JoinKind
|
|
104
|
+
): SelectQueryBuilderContext {
|
|
105
|
+
const joinNode = createJoinNode(kind, table.name, condition);
|
|
106
|
+
return this.applyAst(context, service => service.withJoin(joinNode));
|
|
107
|
+
}
|
|
99
108
|
|
|
100
109
|
/**
|
|
101
110
|
* Selects specific columns for the query
|
|
@@ -122,9 +131,9 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
122
131
|
* @param columns - Optional column names for the CTE
|
|
123
132
|
* @returns New query builder instance with the CTE
|
|
124
133
|
*/
|
|
125
|
-
with(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
134
|
+
with(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
126
135
|
const subAst = this.resolveQueryNode(query);
|
|
127
|
-
const nextContext = this.
|
|
136
|
+
const nextContext = this.applyAst(this.context, service => service.withCte(name, subAst, columns, false));
|
|
128
137
|
return this.clone(nextContext);
|
|
129
138
|
}
|
|
130
139
|
|
|
@@ -135,9 +144,9 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
135
144
|
* @param columns - Optional column names for the CTE
|
|
136
145
|
* @returns New query builder instance with the recursive CTE
|
|
137
146
|
*/
|
|
138
|
-
withRecursive(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
147
|
+
withRecursive(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
139
148
|
const subAst = this.resolveQueryNode(query);
|
|
140
|
-
const nextContext = this.
|
|
149
|
+
const nextContext = this.applyAst(this.context, service => service.withCte(name, subAst, columns, true));
|
|
141
150
|
return this.clone(nextContext);
|
|
142
151
|
}
|
|
143
152
|
|
|
@@ -147,7 +156,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
147
156
|
* @param sub - Query builder or query node for the subquery
|
|
148
157
|
* @returns New query builder instance with the subquery selection
|
|
149
158
|
*/
|
|
150
|
-
selectSubquery(alias: string, sub: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
159
|
+
selectSubquery(alias: string, sub: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
151
160
|
const query = this.resolveQueryNode(sub);
|
|
152
161
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
153
162
|
}
|
|
@@ -159,7 +168,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
159
168
|
* @returns New query builder instance with the INNER JOIN
|
|
160
169
|
*/
|
|
161
170
|
innerJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
162
|
-
const nextContext = this.
|
|
171
|
+
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
163
172
|
return this.clone(nextContext);
|
|
164
173
|
}
|
|
165
174
|
|
|
@@ -170,7 +179,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
170
179
|
* @returns New query builder instance with the LEFT JOIN
|
|
171
180
|
*/
|
|
172
181
|
leftJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
173
|
-
const nextContext = this.
|
|
182
|
+
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
174
183
|
return this.clone(nextContext);
|
|
175
184
|
}
|
|
176
185
|
|
|
@@ -181,7 +190,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
181
190
|
* @returns New query builder instance with the RIGHT JOIN
|
|
182
191
|
*/
|
|
183
192
|
rightJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
184
|
-
const nextContext = this.
|
|
193
|
+
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
185
194
|
return this.clone(nextContext);
|
|
186
195
|
}
|
|
187
196
|
|
|
@@ -223,7 +232,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
223
232
|
return this.clone(nextContext);
|
|
224
233
|
}
|
|
225
234
|
|
|
226
|
-
includeLazy<K extends keyof RelationMap<TTable>>(relationName: K): SelectQueryBuilder<T, TTable> {
|
|
235
|
+
includeLazy<K extends keyof RelationMap<TTable>>(relationName: K): SelectQueryBuilder<T, TTable> {
|
|
227
236
|
const nextLazy = new Set(this.lazyRelations);
|
|
228
237
|
nextLazy.add(relationName as string);
|
|
229
238
|
return this.clone(this.context, nextLazy);
|
|
@@ -247,7 +256,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
247
256
|
* @returns New query builder instance with the WHERE condition
|
|
248
257
|
*/
|
|
249
258
|
where(expr: ExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
250
|
-
const nextContext = this.
|
|
259
|
+
const nextContext = this.applyAst(this.context, service => service.withWhere(expr));
|
|
251
260
|
return this.clone(nextContext);
|
|
252
261
|
}
|
|
253
262
|
|
|
@@ -257,7 +266,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
257
266
|
* @returns New query builder instance with the GROUP BY clause
|
|
258
267
|
*/
|
|
259
268
|
groupBy(col: ColumnDef | ColumnNode): SelectQueryBuilder<T, TTable> {
|
|
260
|
-
const nextContext = this.
|
|
269
|
+
const nextContext = this.applyAst(this.context, service => service.withGroupBy(col));
|
|
261
270
|
return this.clone(nextContext);
|
|
262
271
|
}
|
|
263
272
|
|
|
@@ -267,7 +276,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
267
276
|
* @returns New query builder instance with the HAVING condition
|
|
268
277
|
*/
|
|
269
278
|
having(expr: ExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
270
|
-
const nextContext = this.
|
|
279
|
+
const nextContext = this.applyAst(this.context, service => service.withHaving(expr));
|
|
271
280
|
return this.clone(nextContext);
|
|
272
281
|
}
|
|
273
282
|
|
|
@@ -278,7 +287,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
278
287
|
* @returns New query builder instance with the ORDER BY clause
|
|
279
288
|
*/
|
|
280
289
|
orderBy(col: ColumnDef | ColumnNode, direction: OrderDirection = ORDER_DIRECTIONS.ASC): SelectQueryBuilder<T, TTable> {
|
|
281
|
-
const nextContext = this.
|
|
290
|
+
const nextContext = this.applyAst(this.context, service => service.withOrderBy(col, direction));
|
|
282
291
|
return this.clone(nextContext);
|
|
283
292
|
}
|
|
284
293
|
|
|
@@ -297,7 +306,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
297
306
|
* @returns New query builder instance with the LIMIT clause
|
|
298
307
|
*/
|
|
299
308
|
limit(n: number): SelectQueryBuilder<T, TTable> {
|
|
300
|
-
const nextContext = this.
|
|
309
|
+
const nextContext = this.applyAst(this.context, service => service.withLimit(n));
|
|
301
310
|
return this.clone(nextContext);
|
|
302
311
|
}
|
|
303
312
|
|
|
@@ -307,7 +316,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
307
316
|
* @returns New query builder instance with the OFFSET clause
|
|
308
317
|
*/
|
|
309
318
|
offset(n: number): SelectQueryBuilder<T, TTable> {
|
|
310
|
-
const nextContext = this.
|
|
319
|
+
const nextContext = this.applyAst(this.context, service => service.withOffset(n));
|
|
311
320
|
return this.clone(nextContext);
|
|
312
321
|
}
|
|
313
322
|
|
|
@@ -316,7 +325,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
316
325
|
* @param subquery - Subquery to check for existence
|
|
317
326
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
318
327
|
*/
|
|
319
|
-
whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
328
|
+
whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
320
329
|
const subAst = this.resolveQueryNode(subquery);
|
|
321
330
|
return this.where(exists(subAst));
|
|
322
331
|
}
|
|
@@ -326,7 +335,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
326
335
|
* @param subquery - Subquery to check for non-existence
|
|
327
336
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
328
337
|
*/
|
|
329
|
-
whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
338
|
+
whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
330
339
|
const subAst = this.resolveQueryNode(subquery);
|
|
331
340
|
return this.where(notExists(subAst));
|
|
332
341
|
}
|
|
@@ -337,18 +346,18 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
337
346
|
* @param callback - Optional callback to modify the relationship query
|
|
338
347
|
* @returns New query builder instance with the relationship existence check
|
|
339
348
|
*/
|
|
340
|
-
whereHas(
|
|
341
|
-
relationName: string,
|
|
342
|
-
callback?: <TChildTable extends TableDef>(
|
|
343
|
-
qb: SelectQueryBuilder<any, TChildTable>
|
|
344
|
-
) => SelectQueryBuilder<any, TChildTable>
|
|
345
|
-
): SelectQueryBuilder<T, TTable> {
|
|
349
|
+
whereHas(
|
|
350
|
+
relationName: string,
|
|
351
|
+
callback?: <TChildTable extends TableDef>(
|
|
352
|
+
qb: SelectQueryBuilder<any, TChildTable>
|
|
353
|
+
) => SelectQueryBuilder<any, TChildTable>
|
|
354
|
+
): SelectQueryBuilder<T, TTable> {
|
|
346
355
|
const relation = this.env.table.relations[relationName];
|
|
347
356
|
if (!relation) {
|
|
348
357
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
349
358
|
}
|
|
350
359
|
|
|
351
|
-
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
360
|
+
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
352
361
|
if (callback) {
|
|
353
362
|
subQb = callback(subQb);
|
|
354
363
|
}
|
|
@@ -364,18 +373,18 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
|
364
373
|
* @param callback - Optional callback to modify the relationship query
|
|
365
374
|
* @returns New query builder instance with the relationship non-existence check
|
|
366
375
|
*/
|
|
367
|
-
whereHasNot(
|
|
368
|
-
relationName: string,
|
|
369
|
-
callback?: <TChildTable extends TableDef>(
|
|
370
|
-
qb: SelectQueryBuilder<any, TChildTable>
|
|
371
|
-
) => SelectQueryBuilder<any, TChildTable>
|
|
372
|
-
): SelectQueryBuilder<T, TTable> {
|
|
376
|
+
whereHasNot(
|
|
377
|
+
relationName: string,
|
|
378
|
+
callback?: <TChildTable extends TableDef>(
|
|
379
|
+
qb: SelectQueryBuilder<any, TChildTable>
|
|
380
|
+
) => SelectQueryBuilder<any, TChildTable>
|
|
381
|
+
): SelectQueryBuilder<T, TTable> {
|
|
373
382
|
const relation = this.env.table.relations[relationName];
|
|
374
383
|
if (!relation) {
|
|
375
384
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
376
385
|
}
|
|
377
386
|
|
|
378
|
-
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
387
|
+
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
379
388
|
if (callback) {
|
|
380
389
|
subQb = callback(subQb);
|
|
381
390
|
}
|
|
@@ -1,59 +1,55 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table';
|
|
2
|
-
import { ColumnNode, ExpressionNode, valueToOperand } from '../ast/expression';
|
|
3
|
-
import { TableNode, UpdateQueryNode, UpdateAssignmentNode } from '../ast/query';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
returning: [...columns]
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { ColumnNode, ExpressionNode, valueToOperand } from '../core/ast/expression.js';
|
|
3
|
+
import { TableNode, UpdateQueryNode, UpdateAssignmentNode } from '../core/ast/query.js';
|
|
4
|
+
import { createTableNode } from '../core/ast/builders.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Immutable state for UPDATE queries
|
|
8
|
+
*/
|
|
9
|
+
export class UpdateQueryState {
|
|
10
|
+
public readonly table: TableDef;
|
|
11
|
+
public readonly ast: UpdateQueryNode;
|
|
12
|
+
|
|
13
|
+
constructor(table: TableDef, ast?: UpdateQueryNode) {
|
|
14
|
+
this.table = table;
|
|
15
|
+
this.ast = ast ?? {
|
|
16
|
+
type: 'UpdateQuery',
|
|
17
|
+
table: createTableNode(table),
|
|
18
|
+
set: []
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private clone(nextAst: UpdateQueryNode): UpdateQueryState {
|
|
23
|
+
return new UpdateQueryState(this.table, nextAst);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
withSet(values: Record<string, unknown>): UpdateQueryState {
|
|
27
|
+
const assignments: UpdateAssignmentNode[] = Object.entries(values).map(([column, value]) => ({
|
|
28
|
+
column: {
|
|
29
|
+
type: 'Column',
|
|
30
|
+
table: this.table.name,
|
|
31
|
+
name: column
|
|
32
|
+
},
|
|
33
|
+
value: valueToOperand(value)
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
return this.clone({
|
|
37
|
+
...this.ast,
|
|
38
|
+
set: assignments
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
withWhere(expr: ExpressionNode): UpdateQueryState {
|
|
43
|
+
return this.clone({
|
|
44
|
+
...this.ast,
|
|
45
|
+
where: expr
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
withReturning(columns: ColumnNode[]): UpdateQueryState {
|
|
50
|
+
return this.clone({
|
|
51
|
+
...this.ast,
|
|
52
|
+
returning: [...columns]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -1,61 +1,50 @@
|
|
|
1
|
-
import { TableDef } from '../schema/table';
|
|
2
|
-
import { ColumnDef } from '../schema/column';
|
|
3
|
-
import { ColumnNode, ExpressionNode } from '../ast/expression';
|
|
4
|
-
import { CompiledQuery, UpdateCompiler } from '../dialect/abstract';
|
|
5
|
-
import { UpdateQueryNode } from '../ast/query';
|
|
6
|
-
import { UpdateQueryState } from './update-query-state';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return compiler.compileUpdate(this.state.ast);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
toSql(compiler: UpdateCompiler): string {
|
|
55
|
-
return this.compile(compiler).sql;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
getAST(): UpdateQueryNode {
|
|
59
|
-
return this.state.ast;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
import { TableDef } from '../schema/table.js';
|
|
2
|
+
import { ColumnDef } from '../schema/column.js';
|
|
3
|
+
import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
|
|
4
|
+
import { CompiledQuery, UpdateCompiler } from '../core/dialect/abstract.js';
|
|
5
|
+
import { UpdateQueryNode } from '../core/ast/query.js';
|
|
6
|
+
import { UpdateQueryState } from './update-query-state.js';
|
|
7
|
+
import { buildColumnNode } from '../core/ast/builders.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Builder for UPDATE queries
|
|
11
|
+
*/
|
|
12
|
+
export class UpdateQueryBuilder<T> {
|
|
13
|
+
private readonly table: TableDef;
|
|
14
|
+
private readonly state: UpdateQueryState;
|
|
15
|
+
|
|
16
|
+
constructor(table: TableDef, state?: UpdateQueryState) {
|
|
17
|
+
this.table = table;
|
|
18
|
+
this.state = state ?? new UpdateQueryState(table);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private clone(state: UpdateQueryState): UpdateQueryBuilder<T> {
|
|
22
|
+
return new UpdateQueryBuilder(this.table, state);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
set(values: Record<string, unknown>): UpdateQueryBuilder<T> {
|
|
26
|
+
return this.clone(this.state.withSet(values));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
where(expr: ExpressionNode): UpdateQueryBuilder<T> {
|
|
30
|
+
return this.clone(this.state.withWhere(expr));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
returning(...columns: (ColumnDef | ColumnNode)[]): UpdateQueryBuilder<T> {
|
|
34
|
+
if (!columns.length) return this;
|
|
35
|
+
const nodes = columns.map(column => buildColumnNode(this.table, column));
|
|
36
|
+
return this.clone(this.state.withReturning(nodes));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
compile(compiler: UpdateCompiler): CompiledQuery {
|
|
40
|
+
return compiler.compileUpdate(this.state.ast);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toSql(compiler: UpdateCompiler): string {
|
|
44
|
+
return this.compile(compiler).sql;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getAST(): UpdateQueryNode {
|
|
48
|
+
return this.state.ast;
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/schema/column.ts
CHANGED
|
@@ -20,54 +20,54 @@ export type ColumnType =
|
|
|
20
20
|
/**
|
|
21
21
|
* Definition of a database column
|
|
22
22
|
*/
|
|
23
|
-
export interface ColumnDef {
|
|
24
|
-
/** Column name (filled at runtime by defineTable) */
|
|
25
|
-
name: string;
|
|
26
|
-
/** Data type of the column */
|
|
27
|
-
type:
|
|
28
|
-
/** Whether this column is a primary key */
|
|
29
|
-
primary?: boolean;
|
|
30
|
-
/** Whether this column cannot be null */
|
|
31
|
-
notNull?: boolean;
|
|
32
|
-
/** Additional arguments for the column type (e.g., VARCHAR length) */
|
|
33
|
-
args?: any[];
|
|
34
|
-
/** Table name this column belongs to (filled at runtime by defineTable) */
|
|
35
|
-
table?: string;
|
|
36
|
-
}
|
|
23
|
+
export interface ColumnDef<T extends ColumnType = ColumnType> {
|
|
24
|
+
/** Column name (filled at runtime by defineTable) */
|
|
25
|
+
name: string;
|
|
26
|
+
/** Data type of the column */
|
|
27
|
+
type: T;
|
|
28
|
+
/** Whether this column is a primary key */
|
|
29
|
+
primary?: boolean;
|
|
30
|
+
/** Whether this column cannot be null */
|
|
31
|
+
notNull?: boolean;
|
|
32
|
+
/** Additional arguments for the column type (e.g., VARCHAR length) */
|
|
33
|
+
args?: any[];
|
|
34
|
+
/** Table name this column belongs to (filled at runtime by defineTable) */
|
|
35
|
+
table?: string;
|
|
36
|
+
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Factory for creating column definitions with common data types
|
|
40
40
|
*/
|
|
41
|
-
export const col = {
|
|
42
|
-
/**
|
|
43
|
-
* Creates an integer column definition
|
|
44
|
-
* @returns ColumnDef with INT type
|
|
45
|
-
*/
|
|
46
|
-
int: (): ColumnDef => ({ name: '', type: 'INT' }),
|
|
41
|
+
export const col = {
|
|
42
|
+
/**
|
|
43
|
+
* Creates an integer column definition
|
|
44
|
+
* @returns ColumnDef with INT type
|
|
45
|
+
*/
|
|
46
|
+
int: (): ColumnDef<'INT'> => ({ name: '', type: 'INT' }),
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Creates a variable character column definition
|
|
50
50
|
* @param length - Maximum length of the string
|
|
51
51
|
* @returns ColumnDef with VARCHAR type
|
|
52
52
|
*/
|
|
53
|
-
varchar: (length: number): ColumnDef => ({ name: '', type: 'VARCHAR', args: [length] }),
|
|
53
|
+
varchar: (length: number): ColumnDef<'VARCHAR'> => ({ name: '', type: 'VARCHAR', args: [length] }),
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Creates a JSON column definition
|
|
57
57
|
* @returns ColumnDef with JSON type
|
|
58
58
|
*/
|
|
59
|
-
json: (): ColumnDef => ({ name: '', type: 'JSON' }),
|
|
59
|
+
json: (): ColumnDef<'JSON'> => ({ name: '', type: 'JSON' }),
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Creates a boolean column definition
|
|
63
63
|
* @returns ColumnDef with BOOLEAN type
|
|
64
64
|
*/
|
|
65
|
-
boolean: (): ColumnDef => ({ name: '', type: 'BOOLEAN' }),
|
|
65
|
+
boolean: (): ColumnDef<'BOOLEAN'> => ({ name: '', type: 'BOOLEAN' }),
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Marks a column definition as a primary key
|
|
69
69
|
* @param def - Column definition to modify
|
|
70
70
|
* @returns Modified ColumnDef with primary: true
|
|
71
71
|
*/
|
|
72
|
-
primaryKey: (def: ColumnDef): ColumnDef => ({ ...def, primary: true })
|
|
73
|
-
};
|
|
72
|
+
primaryKey: <T extends ColumnType>(def: ColumnDef<T>): ColumnDef<T> => ({ ...def, primary: true })
|
|
73
|
+
};
|