metal-orm 1.0.8 → 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.
Files changed (153) hide show
  1. package/README.md +12 -1
  2. package/dist/decorators/index.cjs +2564 -0
  3. package/dist/decorators/index.cjs.map +1 -0
  4. package/dist/decorators/index.d.cts +53 -0
  5. package/dist/decorators/index.d.ts +53 -0
  6. package/dist/decorators/index.js +2530 -0
  7. package/dist/decorators/index.js.map +1 -0
  8. package/dist/index.cjs +4227 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +701 -0
  11. package/dist/index.d.ts +701 -0
  12. package/dist/index.js +4131 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/select-654m4qy8.d.cts +1522 -0
  15. package/dist/select-654m4qy8.d.ts +1522 -0
  16. package/package.json +27 -20
  17. package/src/codegen/typescript.ts +405 -393
  18. package/src/core/ast/aggregate-functions.ts +30 -0
  19. package/src/core/ast/builders.ts +43 -0
  20. package/src/core/ast/expression-builders.ts +310 -0
  21. package/src/core/ast/expression-nodes.ts +211 -0
  22. package/src/core/ast/expression-visitor.ts +99 -0
  23. package/src/core/ast/expression.ts +5 -0
  24. package/src/{utils → core/ast}/join-node.ts +20 -20
  25. package/src/{ast → core/ast}/join.ts +18 -18
  26. package/src/{ast → core/ast}/query.ts +113 -113
  27. package/src/core/ast/window-functions.ts +140 -0
  28. package/src/{dialect → core/dialect}/abstract.ts +94 -94
  29. package/src/{dialect → core/dialect}/mssql/index.ts +31 -31
  30. package/src/{dialect → core/dialect}/mysql/index.ts +31 -31
  31. package/src/{dialect → core/dialect}/postgres/index.ts +45 -45
  32. package/src/{dialect → core/dialect}/sqlite/index.ts +45 -45
  33. package/src/{constants → core/sql}/sql-operator-config.ts +39 -39
  34. package/src/decorators/bootstrap.ts +126 -0
  35. package/src/decorators/column.ts +78 -0
  36. package/src/decorators/entity.ts +36 -0
  37. package/src/decorators/index.ts +4 -0
  38. package/src/decorators/relations.ts +107 -0
  39. package/src/global.d.ts +1 -0
  40. package/src/index.ts +22 -22
  41. package/src/orm/db-executor.ts +11 -0
  42. package/src/orm/domain-event-bus.ts +52 -0
  43. package/src/{runtime → orm}/entity-meta.ts +52 -52
  44. package/src/orm/entity-metadata.ts +140 -0
  45. package/src/{runtime → orm}/entity.ts +252 -252
  46. package/src/{runtime → orm}/execute.ts +36 -36
  47. package/src/{runtime → orm}/hydration.ts +103 -103
  48. package/src/orm/identity-map.ts +37 -0
  49. package/src/{runtime → orm}/lazy-batch.ts +205 -205
  50. package/src/orm/orm-context.ts +154 -0
  51. package/src/orm/relation-change-processor.ts +140 -0
  52. package/src/{runtime → orm}/relations/belongs-to.ts +92 -92
  53. package/src/{runtime → orm}/relations/has-many.ts +111 -111
  54. package/src/{runtime → orm}/relations/many-to-many.ts +149 -149
  55. package/src/orm/runtime-types.ts +39 -0
  56. package/src/orm/transaction-runner.ts +17 -0
  57. package/src/orm/unit-of-work.ts +232 -0
  58. package/src/{builder/operations → query-builder}/column-selector.ts +78 -78
  59. package/src/{builder → query-builder}/delete-query-state.ts +38 -42
  60. package/src/{builder → query-builder}/delete.ts +46 -57
  61. package/src/{builder → query-builder}/hydration-manager.ts +87 -87
  62. package/src/{builder → query-builder}/hydration-planner.ts +182 -182
  63. package/src/{builder → query-builder}/insert-query-state.ts +51 -62
  64. package/src/{builder → query-builder}/insert.ts +48 -59
  65. package/src/{builder → query-builder}/query-ast-service.ts +208 -226
  66. package/src/{utils → query-builder}/raw-column-parser.ts +32 -32
  67. package/src/{builder → query-builder}/relation-conditions.ts +112 -112
  68. package/src/{builder/operations → query-builder}/relation-manager.ts +82 -82
  69. package/src/{builder → query-builder}/relation-projection-helper.ts +101 -101
  70. package/src/{builder → query-builder}/relation-service.ts +284 -284
  71. package/src/{builder → query-builder}/relation-types.ts +21 -21
  72. package/src/{builder → query-builder}/relation-utils.ts +12 -12
  73. package/src/{builder → query-builder}/select-query-builder-deps.ts +112 -94
  74. package/src/{builder → query-builder}/select-query-state.ts +179 -179
  75. package/src/{builder → query-builder}/select.ts +78 -69
  76. package/src/{builder → query-builder}/update-query-state.ts +55 -59
  77. package/src/{builder → query-builder}/update.ts +50 -61
  78. package/src/schema/column.ts +25 -25
  79. package/src/schema/relation.ts +116 -116
  80. package/src/schema/table.ts +34 -34
  81. package/src/schema/types.ts +76 -76
  82. package/.github/workflows/publish-metal-orm.yml +0 -38
  83. package/ROADMAP.md +0 -125
  84. package/docs/CHANGES.md +0 -104
  85. package/docs/advanced-features.md +0 -176
  86. package/docs/api-reference.md +0 -31
  87. package/docs/dml-operations.md +0 -156
  88. package/docs/getting-started.md +0 -171
  89. package/docs/hydration.md +0 -115
  90. package/docs/index.md +0 -36
  91. package/docs/multi-dialect-support.md +0 -59
  92. package/docs/query-builder.md +0 -135
  93. package/docs/runtime.md +0 -105
  94. package/docs/schema-definition.md +0 -112
  95. package/metadata.json +0 -5
  96. package/playground/api/playground-api.ts +0 -94
  97. package/playground/index.html +0 -15
  98. package/playground/src/App.css +0 -1
  99. package/playground/src/App.tsx +0 -114
  100. package/playground/src/components/CodeDisplay.tsx +0 -43
  101. package/playground/src/components/QueryExecutor.tsx +0 -189
  102. package/playground/src/components/ResultsTable.tsx +0 -67
  103. package/playground/src/components/ResultsTabs.tsx +0 -105
  104. package/playground/src/components/ScenarioList.tsx +0 -56
  105. package/playground/src/components/logo.svg +0 -45
  106. package/playground/src/data/scenarios.ts +0 -2
  107. package/playground/src/main.tsx +0 -9
  108. package/playground/src/services/PlaygroundApiService.ts +0 -60
  109. package/postcss.config.cjs +0 -5
  110. package/sql_sql-ansi-cheatsheet-2025.md +0 -264
  111. package/src/ast/expression.ts +0 -658
  112. package/src/builder/operations/cte-manager.ts +0 -34
  113. package/src/builder/operations/filter-manager.ts +0 -68
  114. package/src/builder/operations/join-manager.ts +0 -36
  115. package/src/builder/operations/pagination-manager.ts +0 -36
  116. package/src/playground/features/playground/api/types.ts +0 -16
  117. package/src/playground/features/playground/clients/MockClient.ts +0 -17
  118. package/src/playground/features/playground/clients/SqliteClient.ts +0 -57
  119. package/src/playground/features/playground/common/IDatabaseClient.ts +0 -10
  120. package/src/playground/features/playground/data/scenarios/aggregation.ts +0 -36
  121. package/src/playground/features/playground/data/scenarios/basics.ts +0 -25
  122. package/src/playground/features/playground/data/scenarios/edge_cases.ts +0 -57
  123. package/src/playground/features/playground/data/scenarios/filtering.ts +0 -94
  124. package/src/playground/features/playground/data/scenarios/hydration.ts +0 -27
  125. package/src/playground/features/playground/data/scenarios/index.ts +0 -29
  126. package/src/playground/features/playground/data/scenarios/ordering.ts +0 -25
  127. package/src/playground/features/playground/data/scenarios/pagination.ts +0 -16
  128. package/src/playground/features/playground/data/scenarios/relationships.ts +0 -75
  129. package/src/playground/features/playground/data/scenarios/types.ts +0 -70
  130. package/src/playground/features/playground/data/schema.ts +0 -91
  131. package/src/playground/features/playground/data/seed.ts +0 -104
  132. package/src/playground/features/playground/services/QueryExecutionService.ts +0 -121
  133. package/src/runtime/orm-context.ts +0 -539
  134. package/tests/belongs-to-many.test.ts +0 -57
  135. package/tests/between.test.ts +0 -43
  136. package/tests/case-expression.test.ts +0 -58
  137. package/tests/complex-exists.test.ts +0 -230
  138. package/tests/cte.test.ts +0 -118
  139. package/tests/dml.test.ts +0 -206
  140. package/tests/exists.test.ts +0 -127
  141. package/tests/like.test.ts +0 -33
  142. package/tests/orm-runtime.test.ts +0 -254
  143. package/tests/postgres.test.ts +0 -30
  144. package/tests/right-join.test.ts +0 -89
  145. package/tests/subquery-having.test.ts +0 -193
  146. package/tests/window-function.test.ts +0 -151
  147. package/tsconfig.json +0 -30
  148. package/tsup.config.ts +0 -10
  149. package/vite.config.ts +0 -22
  150. package/vitest.config.ts +0 -14
  151. /package/src/{constants → core/sql}/sql.ts +0 -0
  152. /package/src/{runtime → orm}/als.ts +0 -0
  153. /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
- defaultSelectQueryBuilderDependencies,
19
+ resolveSelectQueryBuilderDependencies,
20
20
  SelectQueryBuilderContext,
21
21
  SelectQueryBuilderDependencies,
22
22
  SelectQueryBuilderEnvironment
23
- } from './select-query-builder-deps';
24
- import { ColumnSelector } from './operations/column-selector';
25
- import { CteManager } from './operations/cte-manager';
26
- import { JoinManager } from './operations/join-manager';
27
- import { FilterManager } from './operations/filter-manager';
28
- import { PaginationManager } from './operations/pagination-manager';
29
- import { RelationManager } from './operations/relation-manager';
30
- import { RelationIncludeOptions } from './relation-types';
31
- import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../constants/sql';
32
- import { Entity, RelationMap } from '../schema/types';
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 ?? defaultSelectQueryBuilderDependencies;
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 createChildBuilder<R, TChild extends TableDef>(table: TChild): SelectQueryBuilder<R, TChild> {
97
- return new SelectQueryBuilder(table, undefined, undefined, this.env.deps);
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.cteManager.withCte(this.context, name, subAst, columns, false);
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.cteManager.withCte(this.context, name, subAst, columns, true);
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.joinManager.join(this.context, table, condition, JOIN_KINDS.INNER);
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.joinManager.join(this.context, table, condition, JOIN_KINDS.LEFT);
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.joinManager.join(this.context, table, condition, JOIN_KINDS.RIGHT);
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.filterManager.where(this.context, expr);
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.filterManager.groupBy(this.context, col);
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.filterManager.having(this.context, expr);
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.filterManager.orderBy(this.context, col, direction);
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.paginationManager.limit(this.context, n);
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.paginationManager.offset(this.context, n);
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
- const createTableNode = (table: TableDef): TableNode => ({
6
- type: 'Table',
7
- name: table.name
8
- });
9
-
10
- /**
11
- * Immutable state for UPDATE queries
12
- */
13
- export class UpdateQueryState {
14
- public readonly table: TableDef;
15
- public readonly ast: UpdateQueryNode;
16
-
17
- constructor(table: TableDef, ast?: UpdateQueryNode) {
18
- this.table = table;
19
- this.ast = ast ?? {
20
- type: 'UpdateQuery',
21
- table: createTableNode(table),
22
- set: []
23
- };
24
- }
25
-
26
- private clone(nextAst: UpdateQueryNode): UpdateQueryState {
27
- return new UpdateQueryState(this.table, nextAst);
28
- }
29
-
30
- withSet(values: Record<string, unknown>): UpdateQueryState {
31
- const assignments: UpdateAssignmentNode[] = Object.entries(values).map(([column, value]) => ({
32
- column: {
33
- type: 'Column',
34
- table: this.table.name,
35
- name: column
36
- },
37
- value: valueToOperand(value)
38
- }));
39
-
40
- return this.clone({
41
- ...this.ast,
42
- set: assignments
43
- });
44
- }
45
-
46
- withWhere(expr: ExpressionNode): UpdateQueryState {
47
- return this.clone({
48
- ...this.ast,
49
- where: expr
50
- });
51
- }
52
-
53
- withReturning(columns: ColumnNode[]): UpdateQueryState {
54
- return this.clone({
55
- ...this.ast,
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
- const buildColumnNode = (table: TableDef, column: ColumnDef | ColumnNode): ColumnNode => {
9
- if ((column as ColumnNode).type === 'Column') {
10
- return column as ColumnNode;
11
- }
12
- const def = column as ColumnDef;
13
- return {
14
- type: 'Column',
15
- table: def.table || table.name,
16
- name: def.name
17
- };
18
- };
19
-
20
- /**
21
- * Builder for UPDATE queries
22
- */
23
- export class UpdateQueryBuilder<T> {
24
- private readonly table: TableDef;
25
- private readonly state: UpdateQueryState;
26
-
27
- constructor(table: TableDef, state?: UpdateQueryState) {
28
- this.table = table;
29
- this.state = state ?? new UpdateQueryState(table);
30
- }
31
-
32
- private clone(state: UpdateQueryState): UpdateQueryBuilder<T> {
33
- return new UpdateQueryBuilder(this.table, state);
34
- }
35
-
36
- set(values: Record<string, unknown>): UpdateQueryBuilder<T> {
37
- return this.clone(this.state.withSet(values));
38
- }
39
-
40
- where(expr: ExpressionNode): UpdateQueryBuilder<T> {
41
- return this.clone(this.state.withWhere(expr));
42
- }
43
-
44
- returning(...columns: (ColumnDef | ColumnNode)[]): UpdateQueryBuilder<T> {
45
- if (!columns.length) return this;
46
- const nodes = columns.map(column => buildColumnNode(this.table, column));
47
- return this.clone(this.state.withReturning(nodes));
48
- }
49
-
50
- compile(compiler: UpdateCompiler): CompiledQuery {
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
+ }
@@ -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: ColumnType;
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
+ };