metal-orm 1.0.14 → 1.0.15

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 (115) hide show
  1. package/README.md +40 -45
  2. package/dist/decorators/index.cjs +1600 -27
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -2
  5. package/dist/decorators/index.d.ts +6 -2
  6. package/dist/decorators/index.js +1599 -27
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +4608 -3429
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +511 -159
  11. package/dist/index.d.ts +511 -159
  12. package/dist/index.js +4526 -3415
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-Bkv8g8u_.d.cts} +193 -67
  15. package/dist/{select-CCp1oz9p.d.ts → select-Bkv8g8u_.d.ts} +193 -67
  16. package/package.json +1 -1
  17. package/src/codegen/typescript.ts +38 -35
  18. package/src/core/ast/adapters.ts +21 -0
  19. package/src/core/ast/aggregate-functions.ts +13 -13
  20. package/src/core/ast/builders.ts +56 -43
  21. package/src/core/ast/expression-builders.ts +34 -34
  22. package/src/core/ast/expression-nodes.ts +18 -16
  23. package/src/core/ast/expression-visitor.ts +122 -69
  24. package/src/core/ast/expression.ts +6 -4
  25. package/src/core/ast/join-metadata.ts +15 -0
  26. package/src/core/ast/join-node.ts +22 -20
  27. package/src/core/ast/join.ts +5 -5
  28. package/src/core/ast/query.ts +52 -88
  29. package/src/core/ast/types.ts +20 -0
  30. package/src/core/ast/window-functions.ts +55 -55
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  35. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  36. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  37. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  38. package/src/core/ddl/introspect/context.ts +9 -0
  39. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  40. package/src/core/ddl/introspect/mssql.ts +149 -149
  41. package/src/core/ddl/introspect/mysql.ts +99 -99
  42. package/src/core/ddl/introspect/postgres.ts +245 -154
  43. package/src/core/ddl/introspect/registry.ts +26 -0
  44. package/src/core/ddl/introspect/run-select.ts +25 -0
  45. package/src/core/ddl/introspect/sqlite.ts +7 -7
  46. package/src/core/ddl/introspect/types.ts +23 -19
  47. package/src/core/ddl/introspect/utils.ts +1 -1
  48. package/src/core/ddl/naming-strategy.ts +10 -0
  49. package/src/core/ddl/schema-dialect.ts +41 -0
  50. package/src/core/ddl/schema-diff.ts +211 -179
  51. package/src/core/ddl/schema-generator.ts +16 -90
  52. package/src/core/ddl/schema-introspect.ts +25 -32
  53. package/src/core/ddl/schema-plan-executor.ts +17 -0
  54. package/src/core/ddl/schema-types.ts +46 -39
  55. package/src/core/ddl/sql-writing.ts +170 -0
  56. package/src/core/dialect/abstract.ts +144 -126
  57. package/src/core/dialect/base/cte-compiler.ts +33 -0
  58. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  59. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  60. package/src/core/dialect/base/join-compiler.ts +26 -0
  61. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  62. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  63. package/src/core/dialect/base/returning-strategy.ts +56 -0
  64. package/src/core/dialect/base/sql-dialect.ts +181 -204
  65. package/src/core/dialect/dialect-factory.ts +91 -0
  66. package/src/core/dialect/mssql/functions.ts +101 -0
  67. package/src/core/dialect/mssql/index.ts +128 -126
  68. package/src/core/dialect/mysql/functions.ts +101 -0
  69. package/src/core/dialect/mysql/index.ts +20 -18
  70. package/src/core/dialect/postgres/functions.ts +95 -0
  71. package/src/core/dialect/postgres/index.ts +30 -28
  72. package/src/core/dialect/sqlite/functions.ts +115 -0
  73. package/src/core/dialect/sqlite/index.ts +30 -28
  74. package/src/core/driver/database-driver.ts +11 -0
  75. package/src/core/driver/mssql-driver.ts +20 -0
  76. package/src/core/driver/mysql-driver.ts +20 -0
  77. package/src/core/driver/postgres-driver.ts +20 -0
  78. package/src/core/driver/sqlite-driver.ts +20 -0
  79. package/src/core/execution/db-executor.ts +63 -0
  80. package/src/core/execution/executors/mssql-executor.ts +39 -0
  81. package/src/core/execution/executors/mysql-executor.ts +47 -0
  82. package/src/core/execution/executors/postgres-executor.ts +32 -0
  83. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  84. package/src/core/functions/datetime.ts +132 -0
  85. package/src/core/functions/numeric.ts +179 -0
  86. package/src/core/functions/standard-strategy.ts +47 -0
  87. package/src/core/functions/text.ts +147 -0
  88. package/src/core/functions/types.ts +18 -0
  89. package/src/core/hydration/types.ts +57 -0
  90. package/src/decorators/bootstrap.ts +10 -0
  91. package/src/decorators/relations.ts +15 -0
  92. package/src/index.ts +30 -19
  93. package/src/orm/entity-metadata.ts +7 -0
  94. package/src/orm/entity.ts +58 -27
  95. package/src/orm/hydration.ts +25 -17
  96. package/src/orm/lazy-batch.ts +46 -2
  97. package/src/orm/orm-context.ts +60 -60
  98. package/src/orm/query-logger.ts +1 -1
  99. package/src/orm/relation-change-processor.ts +43 -2
  100. package/src/orm/relations/has-one.ts +139 -0
  101. package/src/orm/transaction-runner.ts +1 -1
  102. package/src/orm/unit-of-work.ts +60 -60
  103. package/src/query-builder/delete.ts +22 -5
  104. package/src/query-builder/hydration-manager.ts +2 -1
  105. package/src/query-builder/hydration-planner.ts +8 -7
  106. package/src/query-builder/insert.ts +22 -5
  107. package/src/query-builder/relation-conditions.ts +9 -8
  108. package/src/query-builder/relation-service.ts +3 -2
  109. package/src/query-builder/select.ts +66 -61
  110. package/src/query-builder/update.ts +22 -5
  111. package/src/schema/column.ts +246 -246
  112. package/src/schema/relation.ts +35 -1
  113. package/src/schema/table.ts +28 -28
  114. package/src/schema/types.ts +41 -31
  115. package/src/orm/db-executor.ts +0 -11
@@ -1,11 +1,11 @@
1
- import { ColumnNode, eq } from '../core/ast/expression.js';
2
- import type { Dialect, CompiledQuery } from '../core/dialect/abstract.js';
1
+ import { ColumnNode, eq } from '../core/ast/expression.js';
2
+ import type { Dialect, CompiledQuery } from '../core/dialect/abstract.js';
3
3
  import { InsertQueryBuilder } from '../query-builder/insert.js';
4
4
  import { UpdateQueryBuilder } from '../query-builder/update.js';
5
5
  import { DeleteQueryBuilder } from '../query-builder/delete.js';
6
6
  import { findPrimaryKey } from '../query-builder/hydration-planner.js';
7
7
  import type { TableDef, TableHooks } from '../schema/table.js';
8
- import type { DbExecutor, QueryResult } from './db-executor.js';
8
+ import type { DbExecutor, QueryResult } from '../core/execution/db-executor.js';
9
9
  import { IdentityMap } from './identity-map.js';
10
10
  import { EntityStatus } from './runtime-types.js';
11
11
  import type { TrackedEntity } from './runtime-types.js';
@@ -120,14 +120,14 @@ export class UnitOfWork {
120
120
  private async flushInsert(tracked: TrackedEntity): Promise<void> {
121
121
  await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
122
122
 
123
- const payload = this.extractColumns(tracked.table, tracked.entity);
124
- let builder = new InsertQueryBuilder(tracked.table).values(payload);
125
- if (this.dialect.supportsReturning()) {
126
- builder = builder.returning(...this.getReturningColumns(tracked.table));
127
- }
128
- const compiled = builder.compile(this.dialect);
129
- const results = await this.executeCompiled(compiled);
130
- this.applyReturningResults(tracked, results);
123
+ const payload = this.extractColumns(tracked.table, tracked.entity);
124
+ let builder = new InsertQueryBuilder(tracked.table).values(payload);
125
+ if (this.dialect.supportsReturning()) {
126
+ builder = builder.returning(...this.getReturningColumns(tracked.table));
127
+ }
128
+ const compiled = builder.compile(this.dialect);
129
+ const results = await this.executeCompiled(compiled);
130
+ this.applyReturningResults(tracked, results);
131
131
 
132
132
  tracked.status = EntityStatus.Managed;
133
133
  tracked.original = this.createSnapshot(tracked.table, tracked.entity);
@@ -150,17 +150,17 @@ export class UnitOfWork {
150
150
  const pkColumn = tracked.table.columns[findPrimaryKey(tracked.table)];
151
151
  if (!pkColumn) return;
152
152
 
153
- let builder = new UpdateQueryBuilder(tracked.table)
154
- .set(changes)
155
- .where(eq(pkColumn, tracked.pk));
156
-
157
- if (this.dialect.supportsReturning()) {
158
- builder = builder.returning(...this.getReturningColumns(tracked.table));
159
- }
160
-
161
- const compiled = builder.compile(this.dialect);
162
- const results = await this.executeCompiled(compiled);
163
- this.applyReturningResults(tracked, results);
153
+ let builder = new UpdateQueryBuilder(tracked.table)
154
+ .set(changes)
155
+ .where(eq(pkColumn, tracked.pk));
156
+
157
+ if (this.dialect.supportsReturning()) {
158
+ builder = builder.returning(...this.getReturningColumns(tracked.table));
159
+ }
160
+
161
+ const compiled = builder.compile(this.dialect);
162
+ const results = await this.executeCompiled(compiled);
163
+ this.applyReturningResults(tracked, results);
164
164
 
165
165
  tracked.status = EntityStatus.Managed;
166
166
  tracked.original = this.createSnapshot(tracked.table, tracked.entity);
@@ -215,44 +215,44 @@ export class UnitOfWork {
215
215
  return payload;
216
216
  }
217
217
 
218
- private async executeCompiled(compiled: CompiledQuery): Promise<QueryResult[]> {
219
- return this.executor.executeSql(compiled.sql, compiled.params);
220
- }
221
-
222
- private getReturningColumns(table: TableDef): ColumnNode[] {
223
- return Object.values(table.columns).map(column => ({
224
- type: 'Column',
225
- table: table.name,
226
- name: column.name,
227
- alias: column.name
228
- }));
229
- }
230
-
231
- private applyReturningResults(tracked: TrackedEntity, results: QueryResult[]): void {
232
- if (!this.dialect.supportsReturning()) return;
233
- const first = results[0];
234
- if (!first || first.values.length === 0) return;
235
-
236
- const row = first.values[0];
237
- for (let i = 0; i < first.columns.length; i++) {
238
- const columnName = this.normalizeColumnName(first.columns[i]);
239
- if (!(columnName in tracked.table.columns)) continue;
240
- tracked.entity[columnName] = row[i];
241
- }
242
- }
243
-
244
- private normalizeColumnName(column: string): string {
245
- const parts = column.split('.');
246
- const candidate = parts[parts.length - 1];
247
- return candidate.replace(/^["`[\]]+|["`[\]]+$/g, '');
248
- }
249
-
250
- private registerIdentity(tracked: TrackedEntity): void {
251
- if (tracked.pk == null) return;
252
- this.identityMap.register(tracked);
253
- }
254
-
255
- private createSnapshot(table: TableDef, entity: any): Record<string, any> {
218
+ private async executeCompiled(compiled: CompiledQuery): Promise<QueryResult[]> {
219
+ return this.executor.executeSql(compiled.sql, compiled.params);
220
+ }
221
+
222
+ private getReturningColumns(table: TableDef): ColumnNode[] {
223
+ return Object.values(table.columns).map(column => ({
224
+ type: 'Column',
225
+ table: table.name,
226
+ name: column.name,
227
+ alias: column.name
228
+ }));
229
+ }
230
+
231
+ private applyReturningResults(tracked: TrackedEntity, results: QueryResult[]): void {
232
+ if (!this.dialect.supportsReturning()) return;
233
+ const first = results[0];
234
+ if (!first || first.values.length === 0) return;
235
+
236
+ const row = first.values[0];
237
+ for (let i = 0; i < first.columns.length; i++) {
238
+ const columnName = this.normalizeColumnName(first.columns[i]);
239
+ if (!(columnName in tracked.table.columns)) continue;
240
+ tracked.entity[columnName] = row[i];
241
+ }
242
+ }
243
+
244
+ private normalizeColumnName(column: string): string {
245
+ const parts = column.split('.');
246
+ const candidate = parts[parts.length - 1];
247
+ return candidate.replace(/^["`[\]]+|["`[\]]+$/g, '');
248
+ }
249
+
250
+ private registerIdentity(tracked: TrackedEntity): void {
251
+ if (tracked.pk == null) return;
252
+ this.identityMap.register(tracked);
253
+ }
254
+
255
+ private createSnapshot(table: TableDef, entity: any): Record<string, any> {
256
256
  const snapshot: Record<string, any> = {};
257
257
  for (const column of Object.keys(table.columns)) {
258
258
  snapshot[column] = entity[column];
@@ -1,11 +1,14 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { ColumnDef } from '../schema/column.js';
3
3
  import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
4
- import { CompiledQuery, DeleteCompiler } from '../core/dialect/abstract.js';
4
+ import { CompiledQuery, DeleteCompiler, Dialect } from '../core/dialect/abstract.js';
5
+ import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
5
6
  import { DeleteQueryNode } from '../core/ast/query.js';
6
7
  import { DeleteQueryState } from './delete-query-state.js';
7
8
  import { buildColumnNode } from '../core/ast/builders.js';
8
9
 
10
+ type DeleteDialectInput = Dialect | DialectKey;
11
+
9
12
  /**
10
13
  * Builder for DELETE queries
11
14
  */
@@ -32,12 +35,26 @@ export class DeleteQueryBuilder<T> {
32
35
  return this.clone(this.state.withReturning(nodes));
33
36
  }
34
37
 
35
- compile(compiler: DeleteCompiler): CompiledQuery {
36
- return compiler.compileDelete(this.state.ast);
38
+ // Existing compiler-based compile stays, but we add a new overload.
39
+
40
+ // 1) Keep the old behavior (used internally / tests, if any):
41
+ compile(compiler: DeleteCompiler): CompiledQuery;
42
+ // 2) New ergonomic overload:
43
+ compile(dialect: DeleteDialectInput): CompiledQuery;
44
+
45
+ compile(arg: DeleteCompiler | DeleteDialectInput): CompiledQuery {
46
+ if (typeof (arg as any).compileDelete === 'function') {
47
+ // DeleteCompiler path – old behavior
48
+ return (arg as DeleteCompiler).compileDelete(this.state.ast);
49
+ }
50
+
51
+ // Dialect | string path – new behavior
52
+ const dialect = resolveDialectInput(arg as DeleteDialectInput);
53
+ return dialect.compileDelete(this.state.ast);
37
54
  }
38
55
 
39
- toSql(compiler: DeleteCompiler): string {
40
- return this.compile(compiler).sql;
56
+ toSql(arg: DeleteCompiler | DeleteDialectInput): string {
57
+ return this.compile(arg as any).sql;
41
58
  }
42
59
 
43
60
  getAST(): DeleteQueryNode {
@@ -1,6 +1,7 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { RelationDef, RelationKinds } from '../schema/relation.js';
3
- import { CommonTableExpressionNode, HydrationPlan, OrderByNode, SelectQueryNode } from '../core/ast/query.js';
3
+ import { CommonTableExpressionNode, OrderByNode, SelectQueryNode } from '../core/ast/query.js';
4
+ import { HydrationPlan } from '../core/hydration/types.js';
4
5
  import { HydrationPlanner } from './hydration-planner.js';
5
6
  import { ProjectionNode, SelectQueryState } from './select-query-state.js';
6
7
  import { ColumnNode, eq } from '../core/ast/expression.js';
@@ -1,7 +1,7 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { RelationDef, RelationKinds, BelongsToManyRelation } from '../schema/relation.js';
3
3
  import { ProjectionNode } from './select-query-state.js';
4
- import { HydrationPlan, HydrationRelationPlan } from '../core/ast/query.js';
4
+ import { HydrationPlan, HydrationRelationPlan } from '../core/hydration/types.js';
5
5
  import { isRelationAlias } from './relation-alias.js';
6
6
  import { buildDefaultPivotColumns } from './relation-utils.js';
7
7
 
@@ -111,12 +111,13 @@ export class HydrationPlanner {
111
111
  pivot?: { aliasPrefix: string; columns: string[] }
112
112
  ): HydrationRelationPlan {
113
113
  switch (rel.type) {
114
- case RelationKinds.HasMany: {
115
- const localKey = rel.localKey || findPrimaryKey(this.table);
116
- return {
117
- name: relationName,
118
- aliasPrefix,
119
- type: rel.type,
114
+ case RelationKinds.HasMany:
115
+ case RelationKinds.HasOne: {
116
+ const localKey = rel.localKey || findPrimaryKey(this.table);
117
+ return {
118
+ name: relationName,
119
+ aliasPrefix,
120
+ type: rel.type,
120
121
  targetTable: rel.target.name,
121
122
  targetPrimaryKey: findPrimaryKey(rel.target),
122
123
  foreignKey: rel.foreignKey,
@@ -1,11 +1,14 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { ColumnDef } from '../schema/column.js';
3
3
  import { ColumnNode } from '../core/ast/expression.js';
4
- import { CompiledQuery, InsertCompiler } from '../core/dialect/abstract.js';
4
+ import { CompiledQuery, InsertCompiler, Dialect } from '../core/dialect/abstract.js';
5
+ import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
5
6
  import { InsertQueryNode } from '../core/ast/query.js';
6
7
  import { InsertQueryState } from './insert-query-state.js';
7
8
  import { buildColumnNode } from '../core/ast/builders.js';
8
9
 
10
+ type InsertDialectInput = Dialect | DialectKey;
11
+
9
12
  /**
10
13
  * Builder for INSERT queries
11
14
  */
@@ -34,12 +37,26 @@ export class InsertQueryBuilder<T> {
34
37
  return this.clone(this.state.withReturning(nodes));
35
38
  }
36
39
 
37
- compile(compiler: InsertCompiler): CompiledQuery {
38
- return compiler.compileInsert(this.state.ast);
40
+ // Existing compiler-based compile stays, but we add a new overload.
41
+
42
+ // 1) Keep the old behavior (used internally / tests, if any):
43
+ compile(compiler: InsertCompiler): CompiledQuery;
44
+ // 2) New ergonomic overload:
45
+ compile(dialect: InsertDialectInput): CompiledQuery;
46
+
47
+ compile(arg: InsertCompiler | InsertDialectInput): CompiledQuery {
48
+ if (typeof (arg as any).compileInsert === 'function') {
49
+ // InsertCompiler path – old behavior
50
+ return (arg as InsertCompiler).compileInsert(this.state.ast);
51
+ }
52
+
53
+ // Dialect | string path – new behavior
54
+ const dialect = resolveDialectInput(arg as InsertDialectInput);
55
+ return dialect.compileInsert(this.state.ast);
39
56
  }
40
57
 
41
- toSql(compiler: InsertCompiler): string {
42
- return this.compile(compiler).sql;
58
+ toSql(arg: InsertCompiler | InsertDialectInput): string {
59
+ return this.compile(arg as any).sql;
43
60
  }
44
61
 
45
62
  getAST(): InsertQueryNode {
@@ -23,17 +23,18 @@ const assertNever = (value: never): never => {
23
23
  */
24
24
  const baseRelationCondition = (root: TableDef, relation: RelationDef): ExpressionNode => {
25
25
  const defaultLocalKey =
26
- relation.type === RelationKinds.HasMany
27
- ? findPrimaryKey(root)
28
- : findPrimaryKey(relation.target);
26
+ relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne
27
+ ? findPrimaryKey(root)
28
+ : findPrimaryKey(relation.target);
29
29
  const localKey = relation.localKey || defaultLocalKey;
30
30
 
31
31
  switch (relation.type) {
32
- case RelationKinds.HasMany:
33
- return eq(
34
- { type: 'Column', table: relation.target.name, name: relation.foreignKey },
35
- { type: 'Column', table: root.name, name: localKey }
36
- );
32
+ case RelationKinds.HasMany:
33
+ case RelationKinds.HasOne:
34
+ return eq(
35
+ { type: 'Column', table: relation.target.name, name: relation.foreignKey },
36
+ { type: 'Column', table: root.name, name: localKey }
37
+ );
37
38
  case RelationKinds.BelongsTo:
38
39
  return eq(
39
40
  { type: 'Column', table: relation.target.name, name: localKey },
@@ -20,7 +20,8 @@ import {
20
20
  } from './relation-conditions.js';
21
21
  import { JoinKind, JOIN_KINDS } from '../core/sql/sql.js';
22
22
  import { RelationIncludeOptions } from './relation-types.js';
23
- import { createJoinNode } from '../core/ast/join-node.js';
23
+ import { createJoinNode } from '../core/ast/join-node.js';
24
+ import { getJoinRelationName } from '../core/ast/join-metadata.js';
24
25
  import { makeRelationAlias } from './relation-alias.js';
25
26
  import { buildDefaultPivotColumns } from './relation-utils.js';
26
27
 
@@ -93,7 +94,7 @@ export class RelationService {
93
94
 
94
95
  const relation = this.getRelation(relationName);
95
96
  const aliasPrefix = options?.aliasPrefix ?? relationName;
96
- const alreadyJoined = state.ast.joins.some(j => j.relationName === relationName);
97
+ const alreadyJoined = state.ast.joins.some(j => getJoinRelationName(j) === relationName);
97
98
 
98
99
  if (!alreadyJoined) {
99
100
  const joined = this.joinRelation(relationName, options?.joinKind ?? JOIN_KINDS.LEFT, options?.filter);
@@ -1,6 +1,7 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { ColumnDef } from '../schema/column.js';
3
- import { SelectQueryNode, HydrationPlan, SetOperationKind } from '../core/ast/query.js';
3
+ import { SelectQueryNode, SetOperationKind } from '../core/ast/query.js';
4
+ import { HydrationPlan } from '../core/hydration/types.js';
4
5
  import {
5
6
  ColumnNode,
6
7
  ExpressionNode,
@@ -13,6 +14,9 @@ import {
13
14
  notExists
14
15
  } from '../core/ast/expression.js';
15
16
  import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
17
+ import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
18
+
19
+ type SelectDialectInput = Dialect | DialectKey;
16
20
  import { SelectQueryState } from './select-query-state.js';
17
21
  import { HydrationManager } from './hydration-manager.js';
18
22
  import {
@@ -96,23 +100,23 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
96
100
  return { state: nextState, hydration: context.hydration };
97
101
  }
98
102
 
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
- }
108
-
109
- private applySetOperation(
110
- operator: SetOperationKind,
111
- query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode
112
- ): SelectQueryBuilderContext {
113
- const subAst = this.resolveQueryNode(query);
114
- return this.applyAst(this.context, service => service.withSetOperation(operator, subAst));
115
- }
103
+ private applyJoin(
104
+ context: SelectQueryBuilderContext,
105
+ table: TableDef,
106
+ condition: BinaryExpressionNode,
107
+ kind: JoinKind
108
+ ): SelectQueryBuilderContext {
109
+ const joinNode = createJoinNode(kind, table.name, condition);
110
+ return this.applyAst(context, service => service.withJoin(joinNode));
111
+ }
112
+
113
+ private applySetOperation(
114
+ operator: SetOperationKind,
115
+ query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode
116
+ ): SelectQueryBuilderContext {
117
+ const subAst = this.resolveQueryNode(query);
118
+ return this.applyAst(this.context, service => service.withSetOperation(operator, subAst));
119
+ }
116
120
 
117
121
  /**
118
122
  * Selects specific columns for the query
@@ -323,46 +327,46 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
323
327
  * @param n - Number of rows to skip
324
328
  * @returns New query builder instance with the OFFSET clause
325
329
  */
326
- offset(n: number): SelectQueryBuilder<T, TTable> {
327
- const nextContext = this.applyAst(this.context, service => service.withOffset(n));
328
- return this.clone(nextContext);
329
- }
330
-
331
- /**
332
- * Combines this query with another using UNION
333
- * @param query - Query to union with
334
- * @returns New query builder instance with the set operation
335
- */
336
- union(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
337
- return this.clone(this.applySetOperation('UNION', query));
338
- }
339
-
340
- /**
341
- * Combines this query with another using UNION ALL
342
- * @param query - Query to union with
343
- * @returns New query builder instance with the set operation
344
- */
345
- unionAll(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
346
- return this.clone(this.applySetOperation('UNION ALL', query));
347
- }
348
-
349
- /**
350
- * Combines this query with another using INTERSECT
351
- * @param query - Query to intersect with
352
- * @returns New query builder instance with the set operation
353
- */
354
- intersect(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
355
- return this.clone(this.applySetOperation('INTERSECT', query));
356
- }
357
-
358
- /**
359
- * Combines this query with another using EXCEPT
360
- * @param query - Query to subtract
361
- * @returns New query builder instance with the set operation
362
- */
363
- except(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
364
- return this.clone(this.applySetOperation('EXCEPT', query));
365
- }
330
+ offset(n: number): SelectQueryBuilder<T, TTable> {
331
+ const nextContext = this.applyAst(this.context, service => service.withOffset(n));
332
+ return this.clone(nextContext);
333
+ }
334
+
335
+ /**
336
+ * Combines this query with another using UNION
337
+ * @param query - Query to union with
338
+ * @returns New query builder instance with the set operation
339
+ */
340
+ union(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
341
+ return this.clone(this.applySetOperation('UNION', query));
342
+ }
343
+
344
+ /**
345
+ * Combines this query with another using UNION ALL
346
+ * @param query - Query to union with
347
+ * @returns New query builder instance with the set operation
348
+ */
349
+ unionAll(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
350
+ return this.clone(this.applySetOperation('UNION ALL', query));
351
+ }
352
+
353
+ /**
354
+ * Combines this query with another using INTERSECT
355
+ * @param query - Query to intersect with
356
+ * @returns New query builder instance with the set operation
357
+ */
358
+ intersect(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
359
+ return this.clone(this.applySetOperation('INTERSECT', query));
360
+ }
361
+
362
+ /**
363
+ * Combines this query with another using EXCEPT
364
+ * @param query - Query to subtract
365
+ * @returns New query builder instance with the set operation
366
+ */
367
+ except(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
368
+ return this.clone(this.applySetOperation('EXCEPT', query));
369
+ }
366
370
 
367
371
  /**
368
372
  * Adds a WHERE EXISTS condition to the query
@@ -443,8 +447,9 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
443
447
  * @param dialect - Database dialect to compile for
444
448
  * @returns Compiled query with SQL and parameters
445
449
  */
446
- compile(dialect: Dialect): CompiledQuery {
447
- return dialect.compileSelect(this.context.state.ast);
450
+ compile(dialect: SelectDialectInput): CompiledQuery {
451
+ const resolved = resolveDialectInput(dialect);
452
+ return resolved.compileSelect(this.context.state.ast);
448
453
  }
449
454
 
450
455
  /**
@@ -452,7 +457,7 @@ export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
452
457
  * @param dialect - Database dialect to generate SQL for
453
458
  * @returns SQL string representation of the query
454
459
  */
455
- toSql(dialect: Dialect): string {
460
+ toSql(dialect: SelectDialectInput): string {
456
461
  return this.compile(dialect).sql;
457
462
  }
458
463
 
@@ -1,11 +1,14 @@
1
1
  import { TableDef } from '../schema/table.js';
2
2
  import { ColumnDef } from '../schema/column.js';
3
3
  import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
4
- import { CompiledQuery, UpdateCompiler } from '../core/dialect/abstract.js';
4
+ import { CompiledQuery, UpdateCompiler, Dialect } from '../core/dialect/abstract.js';
5
+ import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
5
6
  import { UpdateQueryNode } from '../core/ast/query.js';
6
7
  import { UpdateQueryState } from './update-query-state.js';
7
8
  import { buildColumnNode } from '../core/ast/builders.js';
8
9
 
10
+ type UpdateDialectInput = Dialect | DialectKey;
11
+
9
12
  /**
10
13
  * Builder for UPDATE queries
11
14
  */
@@ -36,12 +39,26 @@ export class UpdateQueryBuilder<T> {
36
39
  return this.clone(this.state.withReturning(nodes));
37
40
  }
38
41
 
39
- compile(compiler: UpdateCompiler): CompiledQuery {
40
- return compiler.compileUpdate(this.state.ast);
42
+ // Existing compiler-based compile stays, but we add a new overload.
43
+
44
+ // 1) Keep the old behavior (used internally / tests, if any):
45
+ compile(compiler: UpdateCompiler): CompiledQuery;
46
+ // 2) New ergonomic overload:
47
+ compile(dialect: UpdateDialectInput): CompiledQuery;
48
+
49
+ compile(arg: UpdateCompiler | UpdateDialectInput): CompiledQuery {
50
+ if (typeof (arg as any).compileUpdate === 'function') {
51
+ // UpdateCompiler path – old behavior
52
+ return (arg as UpdateCompiler).compileUpdate(this.state.ast);
53
+ }
54
+
55
+ // Dialect | string path – new behavior
56
+ const dialect = resolveDialectInput(arg as UpdateDialectInput);
57
+ return dialect.compileUpdate(this.state.ast);
41
58
  }
42
59
 
43
- toSql(compiler: UpdateCompiler): string {
44
- return this.compile(compiler).sql;
60
+ toSql(arg: UpdateCompiler | UpdateDialectInput): string {
61
+ return this.compile(arg as any).sql;
45
62
  }
46
63
 
47
64
  getAST(): UpdateQueryNode {