metal-orm 1.0.43 → 1.0.44

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 (84) hide show
  1. package/README.md +173 -30
  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 +68 -98
  56. package/src/orm/relations/has-many.ts +44 -0
  57. package/src/query/index.ts +74 -0
  58. package/src/query/target.ts +46 -0
  59. package/src/query-builder/delete-query-state.ts +30 -0
  60. package/src/query-builder/delete.ts +64 -19
  61. package/src/query-builder/hydration-manager.ts +46 -0
  62. package/src/query-builder/insert-query-state.ts +30 -0
  63. package/src/query-builder/insert.ts +46 -2
  64. package/src/query-builder/query-ast-service.ts +5 -0
  65. package/src/query-builder/query-resolution.ts +78 -0
  66. package/src/query-builder/raw-column-parser.ts +5 -0
  67. package/src/query-builder/relation-alias.ts +7 -0
  68. package/src/query-builder/relation-conditions.ts +61 -48
  69. package/src/query-builder/relation-service.ts +68 -63
  70. package/src/query-builder/relation-utils.ts +3 -0
  71. package/src/query-builder/select/cte-facet.ts +40 -0
  72. package/src/query-builder/select/from-facet.ts +80 -0
  73. package/src/query-builder/select/join-facet.ts +62 -0
  74. package/src/query-builder/select/predicate-facet.ts +103 -0
  75. package/src/query-builder/select/projection-facet.ts +69 -0
  76. package/src/query-builder/select/relation-facet.ts +81 -0
  77. package/src/query-builder/select/setop-facet.ts +36 -0
  78. package/src/query-builder/select-helpers.ts +13 -0
  79. package/src/query-builder/select-query-builder-deps.ts +19 -1
  80. package/src/query-builder/select-query-state.ts +2 -1
  81. package/src/query-builder/select.ts +795 -1163
  82. package/src/query-builder/update-query-state.ts +52 -0
  83. package/src/query-builder/update.ts +69 -19
  84. package/src/schema/table-guards.ts +31 -0
@@ -20,12 +20,28 @@ const hideInternal = (obj: object, keys: string[]): void => {
20
20
  }
21
21
  };
22
22
 
23
+ /**
24
+ * Default implementation of HasManyCollection for managing one-to-many relationships.
25
+ * @template TChild - The type of child entities in the collection
26
+ */
23
27
  export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChild> {
24
28
  private loaded = false;
25
29
  private items: TChild[] = [];
26
30
  private readonly added = new Set<TChild>();
27
31
  private readonly removed = new Set<TChild>();
28
32
 
33
+ /**
34
+ * Creates a new DefaultHasManyCollection instance.
35
+ * @param ctx - The entity context
36
+ * @param meta - The entity metadata
37
+ * @param root - The root entity
38
+ * @param relationName - The relation name
39
+ * @param relation - The relation definition
40
+ * @param rootTable - The root table definition
41
+ * @param loader - The loader function for lazy loading
42
+ * @param createEntity - Function to create entities from rows
43
+ * @param localKey - The local key for the relation
44
+ */
29
45
  constructor(
30
46
  private readonly ctx: EntityContext,
31
47
  private readonly meta: EntityMeta<TableDef>,
@@ -41,6 +57,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
41
57
  this.hydrateFromCache();
42
58
  }
43
59
 
60
+ /**
61
+ * Loads the related entities if not already loaded.
62
+ * @returns Promise resolving to the array of child entities
63
+ */
44
64
  async load(): Promise<TChild[]> {
45
65
  if (this.loaded) return this.items;
46
66
  const map = await this.loader();
@@ -51,10 +71,19 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
51
71
  return this.items;
52
72
  }
53
73
 
74
+ /**
75
+ * Gets the current items in the collection.
76
+ * @returns Array of child entities
77
+ */
54
78
  getItems(): TChild[] {
55
79
  return this.items;
56
80
  }
57
81
 
82
+ /**
83
+ * Adds a new child entity to the collection.
84
+ * @param data - Partial data for the new entity
85
+ * @returns The created entity
86
+ */
58
87
  add(data: Partial<TChild>): TChild {
59
88
  const keyValue = (this.root as Record<string, unknown>)[this.localKey];
60
89
  const childRow: Record<string, unknown> = {
@@ -75,6 +104,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
75
104
  return entity;
76
105
  }
77
106
 
107
+ /**
108
+ * Attaches an existing entity to the collection.
109
+ * @param entity - The entity to attach
110
+ */
78
111
  attach(entity: TChild): void {
79
112
  const keyValue = this.root[this.localKey];
80
113
  (entity as Record<string, unknown>)[this.relation.foreignKey] = keyValue;
@@ -90,6 +123,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
90
123
  );
91
124
  }
92
125
 
126
+ /**
127
+ * Removes an entity from the collection.
128
+ * @param entity - The entity to remove
129
+ */
93
130
  remove(entity: TChild): void {
94
131
  this.items = this.items.filter(item => item !== entity);
95
132
  this.removed.add(entity);
@@ -103,6 +140,9 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
103
140
  );
104
141
  }
105
142
 
143
+ /**
144
+ * Clears all entities from the collection.
145
+ */
106
146
  clear(): void {
107
147
  for (const entity of [...this.items]) {
108
148
  this.remove(entity);
@@ -122,6 +162,10 @@ export class DefaultHasManyCollection<TChild> implements HasManyCollection<TChil
122
162
  this.loaded = true;
123
163
  }
124
164
 
165
+ /**
166
+ * Returns the items for JSON serialization.
167
+ * @returns Array of child entities
168
+ */
125
169
  toJSON(): TChild[] {
126
170
  return this.items;
127
171
  }
@@ -0,0 +1,74 @@
1
+ import { TableDef } from '../schema/table.js';
2
+ import { SelectQueryBuilder } from '../query-builder/select.js';
3
+ import { InsertQueryBuilder } from '../query-builder/insert.js';
4
+ import { UpdateQueryBuilder } from '../query-builder/update.js';
5
+ import { DeleteQueryBuilder } from '../query-builder/delete.js';
6
+ import { QueryTarget, resolveTable } from './target.js';
7
+
8
+ /**
9
+ * Creates a SELECT query builder for the specified table or entity.
10
+ *
11
+ * @template TTable - The table definition type
12
+ * @param target - The table definition or entity constructor to query from
13
+ * @returns A new SelectQueryBuilder instance for building SELECT queries
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const query = selectFrom(UserTable).select('id', 'name');
18
+ * ```
19
+ */
20
+ export const selectFrom = <TTable extends TableDef>(target: QueryTarget<TTable>): SelectQueryBuilder<unknown, TTable> => {
21
+ const table = resolveTable(target);
22
+ return new SelectQueryBuilder(table);
23
+ };
24
+
25
+ /**
26
+ * Creates an INSERT query builder for the specified table or entity.
27
+ *
28
+ * @template TTable - The table definition type
29
+ * @param target - The table definition or entity constructor to insert into
30
+ * @returns A new InsertQueryBuilder instance for building INSERT queries
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const query = insertInto(UserTable).values({ name: 'John', email: 'john@example.com' });
35
+ * ```
36
+ */
37
+ export const insertInto = <TTable extends TableDef>(target: QueryTarget<TTable>): InsertQueryBuilder<unknown> => {
38
+ const table = resolveTable(target);
39
+ return new InsertQueryBuilder(table);
40
+ };
41
+
42
+ /**
43
+ * Creates an UPDATE query builder for the specified table or entity.
44
+ *
45
+ * @template TTable - The table definition type
46
+ * @param target - The table definition or entity constructor to update
47
+ * @returns A new UpdateQueryBuilder instance for building UPDATE queries
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const query = update(UserTable).set({ name: 'Jane' }).where(eq(UserTable.id, 1));
52
+ * ```
53
+ */
54
+ export const update = <TTable extends TableDef>(target: QueryTarget<TTable>): UpdateQueryBuilder<unknown> => {
55
+ const table = resolveTable(target);
56
+ return new UpdateQueryBuilder(table);
57
+ };
58
+
59
+ /**
60
+ * Creates a DELETE query builder for the specified table or entity.
61
+ *
62
+ * @template TTable - The table definition type
63
+ * @param target - The table definition or entity constructor to delete from
64
+ * @returns A new DeleteQueryBuilder instance for building DELETE queries
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const query = deleteFrom(UserTable).where(eq(UserTable.id, 1));
69
+ * ```
70
+ */
71
+ export const deleteFrom = <TTable extends TableDef>(target: QueryTarget<TTable>): DeleteQueryBuilder<unknown> => {
72
+ const table = resolveTable(target);
73
+ return new DeleteQueryBuilder(table);
74
+ };
@@ -0,0 +1,46 @@
1
+ import { TableDef } from '../schema/table.js';
2
+ import { isTableDef } from '../schema/table-guards.js';
3
+ import { EntityConstructor } from '../orm/entity-metadata.js';
4
+ import { getTableDefFromEntity } from '../decorators/bootstrap.js';
5
+
6
+ /**
7
+ * Represents a target for query operations, which can be either a table definition
8
+ * or an entity constructor. This type allows flexible targeting of database tables
9
+ * through either direct table definitions or entity classes decorated with ORM metadata.
10
+ *
11
+ * @template TTable - The table definition type, defaults to TableDef
12
+ */
13
+ export type QueryTarget<TTable extends TableDef = TableDef> = TTable | EntityConstructor;
14
+
15
+ const resolveEntityTarget = <TTable extends TableDef>(ctor: EntityConstructor): TTable => {
16
+ const table = getTableDefFromEntity(ctor);
17
+ if (!table) {
18
+ throw new Error(`Entity '${ctor.name}' is not registered with decorators`);
19
+ }
20
+ return table as TTable;
21
+ };
22
+
23
+ /**
24
+ * Resolves a QueryTarget to its corresponding table definition.
25
+ *
26
+ * If the target is already a TableDef, it returns it directly.
27
+ * If the target is an EntityConstructor, it retrieves the associated table definition
28
+ * from the entity's metadata.
29
+ *
30
+ * @template TTable - The table definition type
31
+ * @param target - The query target to resolve
32
+ * @returns The resolved table definition
33
+ * @throws Error if the entity constructor is not registered with decorators
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const table = resolveTable(UserTable); // Returns UserTable directly
38
+ * const table2 = resolveTable(UserEntity); // Returns table def from UserEntity metadata
39
+ * ```
40
+ */
41
+ export const resolveTable = <TTable extends TableDef>(target: QueryTarget<TTable>): TTable => {
42
+ if (isTableDef(target)) {
43
+ return target as TTable;
44
+ }
45
+ return resolveEntityTarget(target as EntityConstructor);
46
+ };
@@ -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
  }