metal-orm 1.0.43 → 1.0.45

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 (85) hide show
  1. package/README.md +700 -557
  2. package/dist/index.cjs +896 -476
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1146 -275
  5. package/dist/index.d.ts +1146 -275
  6. package/dist/index.js +896 -474
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/core/ast/adapters.ts +8 -2
  10. package/src/core/ast/builders.ts +105 -81
  11. package/src/core/ast/expression-builders.ts +430 -390
  12. package/src/core/ast/expression-visitor.ts +47 -8
  13. package/src/core/ast/helpers.ts +23 -0
  14. package/src/core/ast/join-node.ts +17 -1
  15. package/src/core/ddl/dialects/base-schema-dialect.ts +7 -1
  16. package/src/core/ddl/dialects/index.ts +1 -0
  17. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -0
  18. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -0
  19. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -0
  20. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -0
  21. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  22. package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
  23. package/src/core/ddl/introspect/context.ts +6 -0
  24. package/src/core/ddl/introspect/functions/postgres.ts +13 -0
  25. package/src/core/ddl/introspect/mssql.ts +11 -0
  26. package/src/core/ddl/introspect/mysql.ts +2 -0
  27. package/src/core/ddl/introspect/postgres.ts +14 -0
  28. package/src/core/ddl/introspect/registry.ts +14 -0
  29. package/src/core/ddl/introspect/run-select.ts +13 -0
  30. package/src/core/ddl/introspect/sqlite.ts +22 -0
  31. package/src/core/ddl/introspect/utils.ts +18 -0
  32. package/src/core/ddl/naming-strategy.ts +6 -0
  33. package/src/core/ddl/schema-dialect.ts +19 -6
  34. package/src/core/ddl/schema-diff.ts +22 -0
  35. package/src/core/ddl/schema-generator.ts +22 -0
  36. package/src/core/ddl/schema-plan-executor.ts +6 -0
  37. package/src/core/ddl/schema-types.ts +6 -0
  38. package/src/core/dialect/abstract.ts +2 -2
  39. package/src/core/execution/pooling/pool.ts +12 -7
  40. package/src/core/functions/datetime.ts +57 -33
  41. package/src/core/functions/numeric.ts +95 -30
  42. package/src/core/functions/standard-strategy.ts +35 -0
  43. package/src/core/functions/text.ts +83 -22
  44. package/src/core/functions/types.ts +23 -8
  45. package/src/decorators/bootstrap.ts +16 -4
  46. package/src/decorators/column.ts +17 -0
  47. package/src/decorators/decorator-metadata.ts +27 -0
  48. package/src/decorators/entity.ts +8 -0
  49. package/src/decorators/index.ts +3 -0
  50. package/src/decorators/relations.ts +32 -0
  51. package/src/orm/als.ts +34 -9
  52. package/src/orm/entity-context.ts +54 -0
  53. package/src/orm/entity-metadata.ts +122 -9
  54. package/src/orm/execute.ts +15 -0
  55. package/src/orm/lazy-batch.ts +158 -98
  56. package/src/orm/relations/has-many.ts +44 -0
  57. package/src/orm/save-graph.ts +45 -0
  58. package/src/query/index.ts +74 -0
  59. package/src/query/target.ts +46 -0
  60. package/src/query-builder/delete-query-state.ts +30 -0
  61. package/src/query-builder/delete.ts +64 -19
  62. package/src/query-builder/hydration-manager.ts +46 -0
  63. package/src/query-builder/insert-query-state.ts +30 -0
  64. package/src/query-builder/insert.ts +46 -2
  65. package/src/query-builder/query-ast-service.ts +5 -0
  66. package/src/query-builder/query-resolution.ts +78 -0
  67. package/src/query-builder/raw-column-parser.ts +5 -0
  68. package/src/query-builder/relation-alias.ts +7 -0
  69. package/src/query-builder/relation-conditions.ts +61 -48
  70. package/src/query-builder/relation-service.ts +68 -63
  71. package/src/query-builder/relation-utils.ts +3 -0
  72. package/src/query-builder/select/cte-facet.ts +40 -0
  73. package/src/query-builder/select/from-facet.ts +80 -0
  74. package/src/query-builder/select/join-facet.ts +62 -0
  75. package/src/query-builder/select/predicate-facet.ts +103 -0
  76. package/src/query-builder/select/projection-facet.ts +69 -0
  77. package/src/query-builder/select/relation-facet.ts +81 -0
  78. package/src/query-builder/select/setop-facet.ts +36 -0
  79. package/src/query-builder/select-helpers.ts +13 -0
  80. package/src/query-builder/select-query-builder-deps.ts +19 -1
  81. package/src/query-builder/select-query-state.ts +2 -1
  82. package/src/query-builder/select.ts +795 -1163
  83. package/src/query-builder/update-query-state.ts +52 -0
  84. package/src/query-builder/update.ts +69 -19
  85. package/src/schema/table-guards.ts +31 -0
@@ -14,6 +14,11 @@ export class DeleteQueryState {
14
14
  public readonly table: TableDef;
15
15
  public readonly ast: DeleteQueryNode;
16
16
 
17
+ /**
18
+ * Creates a new DeleteQueryState instance
19
+ * @param table - The table definition for the DELETE query
20
+ * @param ast - Optional initial AST node, defaults to a basic DELETE query
21
+ */
17
22
  constructor(table: TableDef, ast?: DeleteQueryNode) {
18
23
  this.table = table;
19
24
  this.ast = ast ?? {
@@ -27,6 +32,11 @@ export class DeleteQueryState {
27
32
  return new DeleteQueryState(this.table, nextAst);
28
33
  }
29
34
 
35
+ /**
36
+ * Adds a WHERE clause to the DELETE query
37
+ * @param expr - The expression to use as the WHERE condition
38
+ * @returns A new DeleteQueryState with the WHERE clause added
39
+ */
30
40
  withWhere(expr: ExpressionNode): DeleteQueryState {
31
41
  return this.clone({
32
42
  ...this.ast,
@@ -34,6 +44,11 @@ export class DeleteQueryState {
34
44
  });
35
45
  }
36
46
 
47
+ /**
48
+ * Adds a RETURNING clause to the DELETE query
49
+ * @param columns - The columns to return after deletion
50
+ * @returns A new DeleteQueryState with the RETURNING clause added
51
+ */
37
52
  withReturning(columns: ColumnNode[]): DeleteQueryState {
38
53
  return this.clone({
39
54
  ...this.ast,
@@ -41,6 +56,11 @@ export class DeleteQueryState {
41
56
  });
42
57
  }
43
58
 
59
+ /**
60
+ * Adds a USING clause to the DELETE query
61
+ * @param source - The table source to use in the USING clause
62
+ * @returns A new DeleteQueryState with the USING clause added
63
+ */
44
64
  withUsing(source: TableSourceNode): DeleteQueryState {
45
65
  return this.clone({
46
66
  ...this.ast,
@@ -48,6 +68,11 @@ export class DeleteQueryState {
48
68
  });
49
69
  }
50
70
 
71
+ /**
72
+ * Adds a JOIN clause to the DELETE query
73
+ * @param join - The join node to add
74
+ * @returns A new DeleteQueryState with the JOIN clause added
75
+ */
51
76
  withJoin(join: JoinNode): DeleteQueryState {
52
77
  return this.clone({
53
78
  ...this.ast,
@@ -55,6 +80,11 @@ export class DeleteQueryState {
55
80
  });
56
81
  }
57
82
 
83
+ /**
84
+ * Sets an alias for the table in the DELETE query
85
+ * @param alias - The alias to assign to the table
86
+ * @returns A new DeleteQueryState with the table alias set
87
+ */
58
88
  withTableAlias(alias: string): DeleteQueryState {
59
89
  return this.clone({
60
90
  ...this.ast,
@@ -2,12 +2,14 @@ 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
4
  import { JOIN_KINDS, JoinKind } from '../core/sql/sql.js';
5
- import { CompiledQuery, DeleteCompiler, Dialect } from '../core/dialect/abstract.js';
5
+ import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
6
6
  import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
7
7
  import { TableSourceNode, DeleteQueryNode } from '../core/ast/query.js';
8
8
  import { DeleteQueryState } from './delete-query-state.js';
9
9
  import { createJoinNode } from '../core/ast/join-node.js';
10
10
  import { buildColumnNode } from '../core/ast/builders.js';
11
+ import { OrmSession } from '../orm/orm-session.js';
12
+ import { QueryResult } from '../core/execution/db-executor.js';
11
13
 
12
14
  type DeleteDialectInput = Dialect | DialectKey;
13
15
 
@@ -18,6 +20,11 @@ export class DeleteQueryBuilder<T> {
18
20
  private readonly table: TableDef;
19
21
  private readonly state: DeleteQueryState;
20
22
 
23
+ /**
24
+ * Creates a new DeleteQueryBuilder instance
25
+ * @param table - The table definition for the DELETE query
26
+ * @param state - Optional initial query state, defaults to a new DeleteQueryState
27
+ */
21
28
  constructor(table: TableDef, state?: DeleteQueryState) {
22
29
  this.table = table;
23
30
  this.state = state ?? new DeleteQueryState(table);
@@ -27,18 +34,41 @@ export class DeleteQueryBuilder<T> {
27
34
  return new DeleteQueryBuilder(this.table, state);
28
35
  }
29
36
 
37
+ /**
38
+ * Adds a WHERE clause to the DELETE query
39
+ * @param expr - The expression to use as the WHERE condition
40
+ * @returns A new DeleteQueryBuilder with the WHERE clause added
41
+ */
30
42
  where(expr: ExpressionNode): DeleteQueryBuilder<T> {
31
43
  return this.clone(this.state.withWhere(expr));
32
44
  }
33
45
 
46
+ /**
47
+ * Sets an alias for the table in the DELETE query
48
+ * @param alias - The alias to assign to the table
49
+ * @returns A new DeleteQueryBuilder with the table alias set
50
+ */
34
51
  as(alias: string): DeleteQueryBuilder<T> {
35
52
  return this.clone(this.state.withTableAlias(alias));
36
53
  }
37
54
 
55
+ /**
56
+ * Adds a USING clause to the DELETE query
57
+ * @param source - The table source to use in the USING clause
58
+ * @returns A new DeleteQueryBuilder with the USING clause added
59
+ */
38
60
  using(source: TableDef | TableSourceNode): DeleteQueryBuilder<T> {
39
61
  return this.clone(this.state.withUsing(this.resolveTableSource(source)));
40
62
  }
41
63
 
64
+ /**
65
+ * Adds a JOIN clause to the DELETE query
66
+ * @param table - The table to join with
67
+ * @param condition - The join condition expression
68
+ * @param kind - The type of join (defaults to INNER)
69
+ * @param relationName - Optional name for the relation
70
+ * @returns A new DeleteQueryBuilder with the JOIN clause added
71
+ */
42
72
  join(
43
73
  table: TableDef | TableSourceNode | string,
44
74
  condition: ExpressionNode,
@@ -50,6 +80,11 @@ export class DeleteQueryBuilder<T> {
50
80
  return this.clone(this.state.withJoin(joinNode));
51
81
  }
52
82
 
83
+ /**
84
+ * Adds a RETURNING clause to the DELETE query
85
+ * @param columns - The columns to return after deletion
86
+ * @returns A new DeleteQueryBuilder with the RETURNING clause added
87
+ */
53
88
  returning(...columns: (ColumnDef | ColumnNode)[]): DeleteQueryBuilder<T> {
54
89
  if (!columns.length) return this;
55
90
  const nodes = columns.map(column => buildColumnNode(this.table, column));
@@ -68,29 +103,39 @@ export class DeleteQueryBuilder<T> {
68
103
  return this.resolveTableSource(table);
69
104
  }
70
105
 
71
- // Existing compiler-based compile stays, but we add a new overload.
72
-
73
- // 1) Keep the old behavior (used internally / tests, if any):
74
- compile(compiler: DeleteCompiler): CompiledQuery;
75
- // 2) New ergonomic overload:
76
- compile(dialect: DeleteDialectInput): CompiledQuery;
77
-
78
- compile(arg: DeleteCompiler | DeleteDialectInput): CompiledQuery {
79
- const candidate = arg as { compileDelete?: (ast: DeleteQueryNode) => CompiledQuery };
80
- if (typeof candidate.compileDelete === 'function') {
81
- // DeleteCompiler path – old behavior
82
- return candidate.compileDelete(this.state.ast);
83
- }
106
+ /**
107
+ * Compiles the DELETE query for the specified dialect
108
+ * @param dialect - The SQL dialect to compile for
109
+ * @returns The compiled query with SQL and parameters
110
+ */
111
+ compile(dialect: DeleteDialectInput): CompiledQuery {
112
+ const resolved = resolveDialectInput(dialect);
113
+ return resolved.compileDelete(this.state.ast);
114
+ }
84
115
 
85
- // Dialect | string path – new behavior
86
- const dialect = resolveDialectInput(arg as DeleteDialectInput);
87
- return dialect.compileDelete(this.state.ast);
116
+ /**
117
+ * Returns the SQL string for the DELETE query
118
+ * @param dialect - The SQL dialect to generate SQL for
119
+ * @returns The SQL string representation of the query
120
+ */
121
+ toSql(dialect: DeleteDialectInput): string {
122
+ return this.compile(dialect).sql;
88
123
  }
89
124
 
90
- toSql(arg: DeleteCompiler | DeleteDialectInput): string {
91
- return this.compile(arg as DeleteCompiler).sql;
125
+ /**
126
+ * Executes the DELETE query using the provided session
127
+ * @param session - The ORM session to execute the query with
128
+ * @returns A promise that resolves to the query results
129
+ */
130
+ async execute(session: OrmSession): Promise<QueryResult[]> {
131
+ const compiled = this.compile(session.dialect);
132
+ return session.executor.executeSql(compiled.sql, compiled.params);
92
133
  }
93
134
 
135
+ /**
136
+ * Returns the Abstract Syntax Tree (AST) representation of the query
137
+ * @returns The AST node for the DELETE query
138
+ */
94
139
  getAST(): DeleteQueryNode {
95
140
  return this.state.ast;
96
141
  }
@@ -113,6 +113,11 @@ export class HydrationManager {
113
113
  return hasPagination && this.hasMultiplyingRelations(plan);
114
114
  }
115
115
 
116
+ /**
117
+ * Checks if the hydration plan contains relations that multiply rows
118
+ * @param plan - Hydration plan to check
119
+ * @returns True if plan has HasMany or BelongsToMany relations
120
+ */
116
121
  private hasMultiplyingRelations(plan: HydrationPlan): boolean {
117
122
  return plan.relations.some(
118
123
  rel => rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany
@@ -203,6 +208,12 @@ export class HydrationManager {
203
208
  };
204
209
  }
205
210
 
211
+ /**
212
+ * Generates a unique CTE name by appending a suffix if needed
213
+ * @param existing - Existing CTE nodes
214
+ * @param baseName - Base name for the CTE
215
+ * @returns Unique CTE name
216
+ */
206
217
  private nextCteName(existing: CommonTableExpressionNode[] | undefined, baseName: string): string {
207
218
  const names = new Set((existing ?? []).map(cte => cte.name));
208
219
  let candidate = baseName;
@@ -216,6 +227,11 @@ export class HydrationManager {
216
227
  return candidate;
217
228
  }
218
229
 
230
+ /**
231
+ * Extracts projection names from column nodes
232
+ * @param columns - Projection nodes
233
+ * @returns Array of names or undefined if any column lacks name/alias
234
+ */
219
235
  private getProjectionNames(columns: ProjectionNode[]): string[] | undefined {
220
236
  const names: string[] = [];
221
237
  for (const col of columns) {
@@ -227,6 +243,11 @@ export class HydrationManager {
227
243
  return names;
228
244
  }
229
245
 
246
+ /**
247
+ * Builds a map of column keys to their aliases from projection nodes
248
+ * @param columns - Projection nodes
249
+ * @returns Map of 'table.name' to alias
250
+ */
230
251
  private buildProjectionAliasMap(columns: ProjectionNode[]): Map<string, string> {
231
252
  const map = new Map<string, string>();
232
253
  for (const col of columns) {
@@ -238,6 +259,15 @@ export class HydrationManager {
238
259
  return map;
239
260
  }
240
261
 
262
+ /**
263
+ * Maps order by nodes to use base CTE alias
264
+ * @param orderBy - Original order by nodes
265
+ * @param plan - Hydration plan
266
+ * @param projectionAliases - Map of column aliases
267
+ * @param baseAlias - Base CTE alias
268
+ * @param availableColumns - Set of available column names
269
+ * @returns Mapped order by nodes, null if cannot map
270
+ */
241
271
  private mapOrderBy(
242
272
  orderBy: OrderByNode[] | undefined,
243
273
  plan: HydrationPlan,
@@ -261,6 +291,15 @@ export class HydrationManager {
261
291
  return mapped;
262
292
  }
263
293
 
294
+ /**
295
+ * Maps a single ordering term to use base CTE alias
296
+ * @param term - Ordering term to map
297
+ * @param plan - Hydration plan
298
+ * @param projectionAliases - Map of column aliases
299
+ * @param baseAlias - Base CTE alias
300
+ * @param availableColumns - Set of available column names
301
+ * @returns Mapped term or null if cannot map
302
+ */
264
303
  private mapOrderingTerm(
265
304
  term: OrderByNode['term'],
266
305
  plan: HydrationPlan,
@@ -285,6 +324,13 @@ export class HydrationManager {
285
324
  return null;
286
325
  }
287
326
 
327
+ /**
328
+ * Builds column nodes for paging CTE
329
+ * @param primaryKey - Primary key name
330
+ * @param orderBy - Order by nodes
331
+ * @param tableAlias - Table alias for columns
332
+ * @returns Array of column nodes for paging
333
+ */
288
334
  private buildPagingColumns(primaryKey: string, orderBy: OrderByNode[] | undefined, tableAlias: string): ColumnNode[] {
289
335
  const columns: ColumnNode[] = [{ type: 'Column', table: tableAlias, name: primaryKey, alias: primaryKey }];
290
336
 
@@ -20,6 +20,11 @@ export class InsertQueryState {
20
20
  public readonly table: TableDef;
21
21
  public readonly ast: InsertQueryNode;
22
22
 
23
+ /**
24
+ * Creates a new InsertQueryState instance
25
+ * @param table - The table definition for the INSERT query
26
+ * @param ast - Optional initial AST node, defaults to a basic INSERT query
27
+ */
23
28
  constructor(table: TableDef, ast?: InsertQueryNode) {
24
29
  this.table = table;
25
30
  this.ast = ast ?? {
@@ -55,6 +60,13 @@ export class InsertQueryState {
55
60
  return buildColumnNodes(this.table, names);
56
61
  }
57
62
 
63
+ /**
64
+ * Adds VALUES clause to the INSERT query
65
+ * @param rows - Array of row objects to insert
66
+ * @returns A new InsertQueryState with the VALUES clause added
67
+ * @throws Error if mixing VALUES with SELECT source
68
+ * @throws Error if invalid values are provided
69
+ */
58
70
  withValues(rows: Record<string, unknown>[]): InsertQueryState {
59
71
  if (!rows.length) return this;
60
72
 
@@ -88,6 +100,11 @@ export class InsertQueryState {
88
100
  });
89
101
  }
90
102
 
103
+ /**
104
+ * Sets the columns for the INSERT query
105
+ * @param columns - Column nodes to insert into
106
+ * @returns A new InsertQueryState with the specified columns
107
+ */
91
108
  withColumns(columns: ColumnNode[]): InsertQueryState {
92
109
  if (!columns.length) return this;
93
110
  return this.clone({
@@ -96,6 +113,14 @@ export class InsertQueryState {
96
113
  });
97
114
  }
98
115
 
116
+ /**
117
+ * Adds SELECT source to the INSERT query
118
+ * @param query - The SELECT query to use as source
119
+ * @param columns - Target columns for the INSERT
120
+ * @returns A new InsertQueryState with the SELECT source
121
+ * @throws Error if mixing SELECT with VALUES source
122
+ * @throws Error if no destination columns specified
123
+ */
99
124
  withSelect(query: SelectQueryNode, columns: ColumnNode[]): InsertQueryState {
100
125
  const targetColumns =
101
126
  columns.length
@@ -122,6 +147,11 @@ export class InsertQueryState {
122
147
  });
123
148
  }
124
149
 
150
+ /**
151
+ * Adds a RETURNING clause to the INSERT query
152
+ * @param columns - Columns to return after insertion
153
+ * @returns A new InsertQueryState with the RETURNING clause added
154
+ */
125
155
  withReturning(columns: ColumnNode[]): InsertQueryState {
126
156
  return this.clone({
127
157
  ...this.ast,
@@ -17,6 +17,11 @@ export class InsertQueryBuilder<T> {
17
17
  private readonly table: TableDef;
18
18
  private readonly state: InsertQueryState;
19
19
 
20
+ /**
21
+ * Creates a new InsertQueryBuilder instance
22
+ * @param table - The table definition for the INSERT query
23
+ * @param state - Optional initial query state, defaults to a new InsertQueryState
24
+ */
20
25
  constructor(table: TableDef, state?: InsertQueryState) {
21
26
  this.table = table;
22
27
  this.state = state ?? new InsertQueryState(table);
@@ -26,17 +31,34 @@ export class InsertQueryBuilder<T> {
26
31
  return new InsertQueryBuilder(this.table, state);
27
32
  }
28
33
 
34
+ /**
35
+ * Adds VALUES to the INSERT query
36
+ * @param rowOrRows - Single row object or array of row objects to insert
37
+ * @returns A new InsertQueryBuilder with the VALUES clause added
38
+ */
29
39
  values(rowOrRows: Record<string, unknown> | Record<string, unknown>[]): InsertQueryBuilder<T> {
30
40
  const rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];
31
41
  if (!rows.length) return this;
32
42
  return this.clone(this.state.withValues(rows));
33
43
  }
34
44
 
45
+ /**
46
+ * Specifies the columns for the INSERT query
47
+ * @param columns - Column definitions or nodes to insert into
48
+ * @returns A new InsertQueryBuilder with the specified columns
49
+ */
35
50
  columns(...columns: (ColumnDef | ColumnNode)[]): InsertQueryBuilder<T> {
36
51
  if (!columns.length) return this;
37
52
  return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
38
53
  }
39
54
 
55
+ /**
56
+ * Sets the source of the INSERT query to a SELECT query
57
+ * @template TSource - The source table type
58
+ * @param query - The SELECT query or query builder to use as source
59
+ * @param columns - Optional target columns for the INSERT
60
+ * @returns A new InsertQueryBuilder with the SELECT source
61
+ */
40
62
  fromSelect<TSource extends TableDef>(
41
63
  query: SelectQueryNode | SelectQueryBuilder<unknown, TSource>,
42
64
  columns: (ColumnDef | ColumnNode)[] = []
@@ -46,6 +68,11 @@ export class InsertQueryBuilder<T> {
46
68
  return this.clone(this.state.withSelect(ast, nodes));
47
69
  }
48
70
 
71
+ /**
72
+ * Adds a RETURNING clause to the INSERT query
73
+ * @param columns - Columns to return after insertion
74
+ * @returns A new InsertQueryBuilder with the RETURNING clause added
75
+ */
49
76
  returning(...columns: (ColumnDef | ColumnNode)[]): InsertQueryBuilder<T> {
50
77
  if (!columns.length) return this;
51
78
  const nodes = columns.map(column => buildColumnNode(this.table, column));
@@ -68,9 +95,17 @@ export class InsertQueryBuilder<T> {
68
95
 
69
96
  // Existing compiler-based compile stays, but we add a new overload.
70
97
 
71
- // 1) Keep the old behavior (used internally / tests, if any):
98
+ /**
99
+ * Compiles the INSERT query
100
+ * @param compiler - The INSERT compiler to use
101
+ * @returns The compiled query with SQL and parameters
102
+ */
72
103
  compile(compiler: InsertCompiler): CompiledQuery;
73
- // 2) New ergonomic overload:
104
+ /**
105
+ * Compiles the INSERT query for the specified dialect
106
+ * @param dialect - The SQL dialect to compile for
107
+ * @returns The compiled query with SQL and parameters
108
+ */
74
109
  compile(dialect: InsertDialectInput): CompiledQuery;
75
110
 
76
111
  compile(arg: InsertCompiler | InsertDialectInput): CompiledQuery {
@@ -85,10 +120,19 @@ export class InsertQueryBuilder<T> {
85
120
  return dialect.compileInsert(this.state.ast);
86
121
  }
87
122
 
123
+ /**
124
+ * Returns the SQL string for the INSERT query
125
+ * @param arg - The compiler or dialect to generate SQL for
126
+ * @returns The SQL string representation of the query
127
+ */
88
128
  toSql(arg: InsertCompiler | InsertDialectInput): string {
89
129
  return this.compile(arg as InsertCompiler).sql;
90
130
  }
91
131
 
132
+ /**
133
+ * Returns the Abstract Syntax Tree (AST) representation of the query
134
+ * @returns The AST node for the INSERT query
135
+ */
92
136
  getAST(): InsertQueryNode {
93
137
  return this.state.ast;
94
138
  }
@@ -251,6 +251,11 @@ export class QueryAstService {
251
251
  return existing ? and(existing, next) : next;
252
252
  }
253
253
 
254
+ /**
255
+ * Normalizes an ordering term to a standard OrderingTerm
256
+ * @param term - Column definition or ordering term to normalize
257
+ * @returns Normalized ordering term
258
+ */
254
259
  private normalizeOrderingTerm(term: ColumnDef | OrderingTerm): OrderingTerm {
255
260
  const from = this.state.ast.from;
256
261
  const tableRef = from.type === 'Table' && from.alias ? { ...this.table, alias: from.alias } : this.table;
@@ -0,0 +1,78 @@
1
+ import { SelectQueryNode, UpdateQueryNode, DeleteQueryNode, TableSourceNode } from '../core/ast/query.js';
2
+ import { TableDef } from '../schema/table.js';
3
+ import type { SelectQueryBuilder } from './select.js';
4
+ import type { UpdateQueryBuilder } from './update.js';
5
+ import type { DeleteQueryBuilder } from './delete.js';
6
+
7
+ /**
8
+ * Resolves a SelectQueryBuilder or SelectQueryNode to a SelectQueryNode AST
9
+ * @param query - Query builder or AST node
10
+ * @returns SelectQueryNode AST
11
+ */
12
+ export function resolveSelectQuery<TSub extends TableDef>(
13
+ query: SelectQueryBuilder<unknown, TSub> | SelectQueryNode
14
+ ): SelectQueryNode {
15
+ const candidate = query as { getAST?: () => SelectQueryNode };
16
+ return typeof candidate.getAST === 'function' && candidate.getAST
17
+ ? candidate.getAST()
18
+ : (query as SelectQueryNode);
19
+ }
20
+
21
+ /**
22
+ * Resolves a UpdateQueryBuilder or UpdateQueryNode to a UpdateQueryNode AST
23
+ * @param query - Query builder or AST node
24
+ * @returns UpdateQueryNode AST
25
+ */
26
+ export function resolveUpdateQuery<T>(
27
+ query: UpdateQueryBuilder<T> | UpdateQueryNode
28
+ ): UpdateQueryNode {
29
+ const candidate = query as { getAST?: () => UpdateQueryNode };
30
+ return typeof candidate.getAST === 'function' && candidate.getAST
31
+ ? candidate.getAST()
32
+ : (query as UpdateQueryNode);
33
+ }
34
+
35
+ /**
36
+ * Resolves a DeleteQueryBuilder or DeleteQueryNode to a DeleteQueryNode AST
37
+ * @param query - Query builder or AST node
38
+ * @returns DeleteQueryNode AST
39
+ */
40
+ export function resolveDeleteQuery<T>(
41
+ query: DeleteQueryBuilder<T> | DeleteQueryNode
42
+ ): DeleteQueryNode {
43
+ const candidate = query as { getAST?: () => DeleteQueryNode };
44
+ return typeof candidate.getAST === 'function' && candidate.getAST
45
+ ? candidate.getAST()
46
+ : (query as DeleteQueryNode);
47
+ }
48
+
49
+ /**
50
+ * Resolves a TableDef or TableSourceNode to a TableSourceNode
51
+ * @param source - Table definition or source node
52
+ * @returns TableSourceNode
53
+ */
54
+ export function resolveTableSource(source: TableDef | TableSourceNode): TableSourceNode {
55
+ if (isTableSourceNode(source)) {
56
+ return source;
57
+ }
58
+ return { type: 'Table', name: source.name, schema: source.schema };
59
+ }
60
+
61
+ /**
62
+ * Resolves a join target (TableDef, TableSourceNode, or string relation name)
63
+ * @param table - Join target
64
+ * @returns TableSourceNode or string
65
+ */
66
+ export function resolveJoinTarget(table: TableDef | TableSourceNode | string): TableSourceNode | string {
67
+ if (typeof table === 'string') return table;
68
+ return resolveTableSource(table);
69
+ }
70
+
71
+ /**
72
+ * Type guard to check if a value is a TableSourceNode
73
+ * @param source - Value to check
74
+ * @returns True if value is a TableSourceNode
75
+ */
76
+ function isTableSourceNode(source: TableDef | TableSourceNode): source is TableSourceNode {
77
+ return typeof (source as TableSourceNode).type === 'string';
78
+ }
@@ -4,6 +4,11 @@ import { CommonTableExpressionNode } from '../core/ast/query.js';
4
4
  /**
5
5
  * Best-effort helper that tries to convert a raw column expression into a `ColumnNode`.
6
6
  * This parser is intentionally limited; use it only for simple references or function calls.
7
+ *
8
+ * @param col - Raw column expression string (e.g., "column", "table.column", "COUNT(column)")
9
+ * @param tableName - Default table name to use when no table is specified
10
+ * @param ctes - Optional array of CTEs for context when parsing column references
11
+ * @returns A ColumnNode representing the parsed column expression
7
12
  */
8
13
  export const parseRawColumn = (
9
14
  col: string,
@@ -19,6 +19,9 @@ export interface RelationAliasParts {
19
19
 
20
20
  /**
21
21
  * Builds a relation alias from the relation name and column name components.
22
+ * @param relationName - The name of the relation
23
+ * @param columnName - The name of the column within the relation
24
+ * @returns A relation alias string in the format "relationName__columnName"
22
25
  */
23
26
  export const makeRelationAlias = (relationName: string, columnName: string): string =>
24
27
  `${relationName}${RELATION_SEPARATOR}${columnName}`;
@@ -26,6 +29,8 @@ export const makeRelationAlias = (relationName: string, columnName: string): str
26
29
  /**
27
30
  * Parses a relation alias into its relation/column components.
28
31
  * Returns `null` when the alias does not follow the `relation__column` pattern.
32
+ * @param alias - The relation alias string to parse
33
+ * @returns Parsed relation alias parts or null if not a valid relation alias
29
34
  */
30
35
  export const parseRelationAlias = (alias: string): RelationAliasParts | null => {
31
36
  const idx = alias.indexOf(RELATION_SEPARATOR);
@@ -38,6 +43,8 @@ export const parseRelationAlias = (alias: string): RelationAliasParts | null =>
38
43
 
39
44
  /**
40
45
  * Determines whether an alias represents a relation column by checking the `__` convention.
46
+ * @param alias - The alias string to check
47
+ * @returns True if the alias follows the relation alias pattern
41
48
  */
42
49
  export const isRelationAlias = (alias?: string): boolean =>
43
50
  !!alias && alias.includes(RELATION_SEPARATOR);