metal-orm 1.1.10 → 1.1.16

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 (192) hide show
  1. package/README.md +758 -769
  2. package/dist/index.cjs +106 -43
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +5 -5
  5. package/dist/index.d.ts +5 -5
  6. package/dist/index.js +106 -43
  7. package/dist/index.js.map +1 -1
  8. package/package.json +100 -96
  9. package/scripts/generate-entities/render.mjs +21 -12
  10. package/scripts/generate-entities/schema.mjs +209 -195
  11. package/scripts/generate-entities/tree-detection.mjs +159 -153
  12. package/scripts/inflection/pt-br.mjs +468 -468
  13. package/scripts/run-eslint.mjs +33 -34
  14. package/scripts/show-sql-seed.sql +102 -0
  15. package/scripts/show-sql.mjs +321 -325
  16. package/src/bulk/bulk-delete-executor.ts +3 -5
  17. package/src/bulk/bulk-insert-executor.ts +7 -7
  18. package/src/bulk/bulk-update-executor.ts +2 -2
  19. package/src/bulk/bulk-upsert-executor.ts +5 -7
  20. package/src/codegen/naming-strategy.ts +54 -54
  21. package/src/codegen/typescript.ts +482 -482
  22. package/src/core/ast/adapters.ts +1 -1
  23. package/src/core/ast/builders.ts +123 -123
  24. package/src/core/ast/expression-builders.ts +745 -745
  25. package/src/core/ast/expression-nodes.ts +304 -304
  26. package/src/core/ast/expression-visitor.ts +212 -212
  27. package/src/core/ast/expression.ts +20 -20
  28. package/src/core/ast/helpers.ts +14 -14
  29. package/src/core/ast/join.ts +18 -18
  30. package/src/core/ast/query.ts +200 -200
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
  35. package/src/core/ddl/dialects/render-reference.test.ts +70 -70
  36. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
  37. package/src/core/ddl/introspect/catalogs/index.ts +5 -5
  38. package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
  39. package/src/core/ddl/introspect/context.ts +15 -15
  40. package/src/core/ddl/introspect/functions/postgres.ts +35 -35
  41. package/src/core/ddl/introspect/mysql.ts +113 -36
  42. package/src/core/ddl/introspect/registry.ts +40 -40
  43. package/src/core/ddl/introspect/run-select.ts +35 -35
  44. package/src/core/ddl/introspect/utils.ts +56 -56
  45. package/src/core/ddl/naming-strategy.ts +16 -16
  46. package/src/core/ddl/schema-dialect.ts +56 -56
  47. package/src/core/ddl/schema-diff.ts +234 -234
  48. package/src/core/ddl/schema-generator.ts +1 -1
  49. package/src/core/ddl/schema-introspect.ts +25 -25
  50. package/src/core/ddl/sql-writing.ts +171 -171
  51. package/src/core/dialect/abstract.ts +541 -541
  52. package/src/core/dialect/base/cte-compiler.ts +33 -33
  53. package/src/core/dialect/base/function-table-formatter.ts +103 -103
  54. package/src/core/dialect/base/groupby-compiler.ts +21 -21
  55. package/src/core/dialect/base/join-compiler.ts +25 -25
  56. package/src/core/dialect/base/orderby-compiler.ts +35 -35
  57. package/src/core/dialect/base/pagination-strategy.ts +32 -32
  58. package/src/core/dialect/base/returning-strategy.ts +57 -57
  59. package/src/core/dialect/base/sql-dialect.ts +294 -294
  60. package/src/core/dialect/dialect-factory.ts +91 -91
  61. package/src/core/dialect/mssql/functions.ts +120 -120
  62. package/src/core/dialect/mssql/index.ts +317 -317
  63. package/src/core/dialect/mysql/functions.ts +103 -103
  64. package/src/core/dialect/mysql/index.ts +105 -105
  65. package/src/core/dialect/postgres/functions.ts +108 -108
  66. package/src/core/dialect/postgres/index.ts +91 -91
  67. package/src/core/dialect/sqlite/functions.ts +129 -129
  68. package/src/core/dialect/sqlite/index.ts +67 -67
  69. package/src/core/driver/database-driver.ts +19 -19
  70. package/src/core/driver/mssql-driver.ts +23 -23
  71. package/src/core/driver/mysql-driver.ts +23 -23
  72. package/src/core/driver/postgres-driver.ts +23 -23
  73. package/src/core/driver/sqlite-driver.ts +23 -23
  74. package/src/core/execution/db-executor.ts +92 -92
  75. package/src/core/execution/executors/better-sqlite3-executor.ts +94 -94
  76. package/src/core/execution/executors/mssql-executor.ts +184 -184
  77. package/src/core/execution/executors/mysql-executor.ts +88 -88
  78. package/src/core/execution/executors/postgres-executor.ts +26 -26
  79. package/src/core/execution/executors/sqlite-executor.ts +42 -42
  80. package/src/core/execution/pooling/pool-types.ts +30 -30
  81. package/src/core/execution/pooling/pool.ts +275 -275
  82. package/src/core/functions/array.ts +35 -35
  83. package/src/core/functions/control-flow.ts +79 -79
  84. package/src/core/functions/datetime.ts +237 -237
  85. package/src/core/functions/json.ts +70 -70
  86. package/src/core/functions/numeric.ts +297 -297
  87. package/src/core/functions/text.ts +334 -334
  88. package/src/core/functions/types.ts +33 -33
  89. package/src/core/hydration/types.ts +51 -51
  90. package/src/core/sql/sql-operator-config.ts +39 -39
  91. package/src/core/sql/sql.ts +152 -152
  92. package/src/decorators/column-decorator.ts +87 -87
  93. package/src/decorators/decorator-metadata.ts +143 -143
  94. package/src/decorators/entity.ts +93 -93
  95. package/src/decorators/index.ts +39 -39
  96. package/src/decorators/relations.ts +231 -231
  97. package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
  98. package/src/decorators/transformers/transformer-decorators.ts +134 -134
  99. package/src/decorators/transformers/transformer-executor.ts +171 -171
  100. package/src/decorators/transformers/transformer-metadata.ts +73 -73
  101. package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
  102. package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
  103. package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
  104. package/src/decorators/validators/country-validator-registry.ts +64 -64
  105. package/src/decorators/validators/country-validators-decorators.ts +203 -203
  106. package/src/decorators/validators/country-validators.ts +105 -105
  107. package/src/decorators/validators/validator-metadata.ts +59 -59
  108. package/src/dto/dto-types.ts +226 -226
  109. package/src/dto/filter-types.ts +141 -141
  110. package/src/dto/index.ts +95 -95
  111. package/src/dto/openapi/generators/base.ts +29 -29
  112. package/src/dto/openapi/generators/column.ts +37 -37
  113. package/src/dto/openapi/generators/dto.ts +91 -91
  114. package/src/dto/openapi/generators/filter.ts +75 -75
  115. package/src/dto/openapi/generators/nested-dto.ts +618 -618
  116. package/src/dto/openapi/generators/pagination.ts +111 -111
  117. package/src/dto/openapi/generators/relation-filter.ts +228 -228
  118. package/src/dto/openapi/index.ts +12 -12
  119. package/src/dto/openapi/types.ts +101 -101
  120. package/src/dto/openapi/utilities.ts +95 -95
  121. package/src/dto/pagination-utils.ts +150 -150
  122. package/src/dto/transform.ts +197 -197
  123. package/src/index.ts +86 -86
  124. package/src/orm/als.ts +58 -58
  125. package/src/orm/domain-event-bus.ts +119 -119
  126. package/src/orm/entity-context.ts +86 -86
  127. package/src/orm/entity-materializer.ts +159 -159
  128. package/src/orm/entity-meta.ts +97 -97
  129. package/src/orm/entity-registry.ts +39 -39
  130. package/src/orm/entity-relation-cache.ts +39 -39
  131. package/src/orm/execute.ts +194 -194
  132. package/src/orm/execution-context.ts +18 -18
  133. package/src/orm/hydration-context.ts +26 -26
  134. package/src/orm/hydration.ts +112 -112
  135. package/src/orm/identity-map.ts +61 -61
  136. package/src/orm/interceptor-pipeline.ts +16 -16
  137. package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
  138. package/src/orm/lazy-batch/belongs-to.ts +108 -108
  139. package/src/orm/lazy-batch/has-many.ts +69 -69
  140. package/src/orm/lazy-batch/has-one.ts +68 -68
  141. package/src/orm/lazy-batch/shared.ts +125 -125
  142. package/src/orm/orm-session.ts +620 -620
  143. package/src/orm/orm.ts +34 -34
  144. package/src/orm/pooled-executor-factory.ts +121 -121
  145. package/src/orm/query-logger.ts +40 -40
  146. package/src/orm/relation-change-processor.ts +420 -420
  147. package/src/orm/relations/belongs-to.ts +143 -143
  148. package/src/orm/relations/has-many.ts +204 -204
  149. package/src/orm/relations/has-one.ts +174 -174
  150. package/src/orm/relations/many-to-many.ts +288 -288
  151. package/src/orm/relations/morph-many.ts +156 -156
  152. package/src/orm/relations/morph-one.ts +151 -151
  153. package/src/orm/relations/morph-to.ts +162 -162
  154. package/src/orm/runtime-types.ts +92 -92
  155. package/src/orm/save-graph.ts +561 -561
  156. package/src/orm/transaction-runner.ts +24 -24
  157. package/src/orm/unit-of-work.ts +426 -426
  158. package/src/query/index.ts +69 -69
  159. package/src/query/target.ts +46 -46
  160. package/src/query-builder/column-selector.ts +81 -81
  161. package/src/query-builder/delete.ts +141 -141
  162. package/src/query-builder/insert-query-state.ts +149 -149
  163. package/src/query-builder/insert.ts +117 -117
  164. package/src/query-builder/query-ast-service.ts +287 -287
  165. package/src/query-builder/query-resolution.ts +78 -78
  166. package/src/query-builder/raw-column-parser.ts +38 -38
  167. package/src/query-builder/relation-filter-utils.ts +153 -153
  168. package/src/query-builder/relation-join-planner.ts +10 -10
  169. package/src/query-builder/relation-manager.ts +87 -87
  170. package/src/query-builder/relation-projection-helper.ts +102 -102
  171. package/src/query-builder/relation-types.ts +9 -9
  172. package/src/query-builder/relation-utils.ts +15 -15
  173. package/src/query-builder/select/cte-facet.ts +40 -40
  174. package/src/query-builder/select/from-facet.ts +80 -80
  175. package/src/query-builder/select/join-facet.ts +62 -62
  176. package/src/query-builder/select/predicate-facet.ts +104 -104
  177. package/src/query-builder/select/projection-facet.ts +70 -70
  178. package/src/query-builder/select/relation-facet.ts +81 -81
  179. package/src/query-builder/select/setop-facet.ts +36 -36
  180. package/src/query-builder/select-helpers.ts +1 -1
  181. package/src/query-builder/select-query-builder-deps.ts +130 -130
  182. package/src/query-builder/select-query-state.ts +207 -207
  183. package/src/query-builder/update.ts +151 -151
  184. package/src/schema/column-types.ts +322 -322
  185. package/src/schema/table-guards.ts +37 -37
  186. package/src/schema/table.ts +281 -281
  187. package/src/tree/index.ts +13 -13
  188. package/src/tree/nested-set-strategy.ts +545 -545
  189. package/src/tree/tree-decorator.ts +397 -397
  190. package/src/tree/tree-manager.ts +754 -754
  191. package/src/tree/tree-query.ts +427 -427
  192. package/src/tree/tree-types.ts +299 -299
@@ -1,148 +1,148 @@
1
- import { TableDef } from '../schema/table.js';
2
- import { ColumnDef } from '../schema/column-types.js';
3
- import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
4
- import { JOIN_KINDS, JoinKind } from '../core/sql/sql.js';
5
- import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
6
- import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
7
- import { TableSourceNode, DeleteQueryNode } from '../core/ast/query.js';
8
- import { DeleteQueryState } from './delete-query-state.js';
9
- import { createJoinNode } from '../core/ast/join-node.js';
10
- import { buildColumnNode } from '../core/ast/builders.js';
11
- import { OrmSession } from '../orm/orm-session.js';
1
+ import { TableDef } from '../schema/table.js';
2
+ import { ColumnDef } from '../schema/column-types.js';
3
+ import { ColumnNode, ExpressionNode } from '../core/ast/expression.js';
4
+ import { JOIN_KINDS, JoinKind } from '../core/sql/sql.js';
5
+ import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
6
+ import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
7
+ import { TableSourceNode, DeleteQueryNode } from '../core/ast/query.js';
8
+ import { DeleteQueryState } from './delete-query-state.js';
9
+ import { createJoinNode } from '../core/ast/join-node.js';
10
+ import { buildColumnNode } from '../core/ast/builders.js';
11
+ import { OrmSession } from '../orm/orm-session.js';
12
12
  import { payloadResultSets, QueryResult } from '../core/execution/db-executor.js';
13
-
14
- type DeleteDialectInput = Dialect | DialectKey;
15
-
16
- /**
17
- * Builder for DELETE queries
18
- */
19
- export class DeleteQueryBuilder<T> {
20
- private readonly table: TableDef;
21
- private readonly state: DeleteQueryState;
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
- */
28
- constructor(table: TableDef, state?: DeleteQueryState) {
29
- this.table = table;
30
- this.state = state ?? new DeleteQueryState(table);
31
- }
32
-
33
- private clone(state: DeleteQueryState): DeleteQueryBuilder<T> {
34
- return new DeleteQueryBuilder(this.table, state);
35
- }
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
- */
42
- where(expr: ExpressionNode): DeleteQueryBuilder<T> {
43
- return this.clone(this.state.withWhere(expr));
44
- }
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
- */
51
- as(alias: string): DeleteQueryBuilder<T> {
52
- return this.clone(this.state.withTableAlias(alias));
53
- }
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
- */
60
- using(source: TableDef | TableSourceNode): DeleteQueryBuilder<T> {
61
- return this.clone(this.state.withUsing(this.resolveTableSource(source)));
62
- }
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
- */
72
- join(
73
- table: TableDef | TableSourceNode | string,
74
- condition: ExpressionNode,
75
- kind: JoinKind = JOIN_KINDS.INNER,
76
- relationName?: string
77
- ): DeleteQueryBuilder<T> {
78
- const target = this.resolveJoinTarget(table);
79
- const joinNode = createJoinNode(kind, target, condition, relationName);
80
- return this.clone(this.state.withJoin(joinNode));
81
- }
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
- */
88
- returning(...columns: (ColumnDef | ColumnNode)[]): DeleteQueryBuilder<T> {
89
- if (!columns.length) return this;
90
- const nodes = columns.map(column => buildColumnNode(this.table, column));
91
- return this.clone(this.state.withReturning(nodes));
92
- }
93
-
94
- private resolveTableSource(source: TableDef | TableSourceNode): TableSourceNode {
95
- if (isTableSourceNode(source)) {
96
- return source;
97
- }
98
- return { type: 'Table', name: source.name, schema: source.schema };
99
- }
100
-
101
- private resolveJoinTarget(table: TableDef | TableSourceNode | string): TableSourceNode | string {
102
- if (typeof table === 'string') return table;
103
- return this.resolveTableSource(table);
104
- }
105
-
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
- }
115
-
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;
123
- }
124
-
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
- */
13
+
14
+ type DeleteDialectInput = Dialect | DialectKey;
15
+
16
+ /**
17
+ * Builder for DELETE queries
18
+ */
19
+ export class DeleteQueryBuilder<T> {
20
+ private readonly table: TableDef;
21
+ private readonly state: DeleteQueryState;
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
+ */
28
+ constructor(table: TableDef, state?: DeleteQueryState) {
29
+ this.table = table;
30
+ this.state = state ?? new DeleteQueryState(table);
31
+ }
32
+
33
+ private clone(state: DeleteQueryState): DeleteQueryBuilder<T> {
34
+ return new DeleteQueryBuilder(this.table, state);
35
+ }
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
+ */
42
+ where(expr: ExpressionNode): DeleteQueryBuilder<T> {
43
+ return this.clone(this.state.withWhere(expr));
44
+ }
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
+ */
51
+ as(alias: string): DeleteQueryBuilder<T> {
52
+ return this.clone(this.state.withTableAlias(alias));
53
+ }
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
+ */
60
+ using(source: TableDef | TableSourceNode): DeleteQueryBuilder<T> {
61
+ return this.clone(this.state.withUsing(this.resolveTableSource(source)));
62
+ }
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
+ */
72
+ join(
73
+ table: TableDef | TableSourceNode | string,
74
+ condition: ExpressionNode,
75
+ kind: JoinKind = JOIN_KINDS.INNER,
76
+ relationName?: string
77
+ ): DeleteQueryBuilder<T> {
78
+ const target = this.resolveJoinTarget(table);
79
+ const joinNode = createJoinNode(kind, target, condition, relationName);
80
+ return this.clone(this.state.withJoin(joinNode));
81
+ }
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
+ */
88
+ returning(...columns: (ColumnDef | ColumnNode)[]): DeleteQueryBuilder<T> {
89
+ if (!columns.length) return this;
90
+ const nodes = columns.map(column => buildColumnNode(this.table, column));
91
+ return this.clone(this.state.withReturning(nodes));
92
+ }
93
+
94
+ private resolveTableSource(source: TableDef | TableSourceNode): TableSourceNode {
95
+ if (isTableSourceNode(source)) {
96
+ return source;
97
+ }
98
+ return { type: 'Table', name: source.name, schema: source.schema };
99
+ }
100
+
101
+ private resolveJoinTarget(table: TableDef | TableSourceNode | string): TableSourceNode | string {
102
+ if (typeof table === 'string') return table;
103
+ return this.resolveTableSource(table);
104
+ }
105
+
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
+ }
115
+
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;
123
+ }
124
+
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
130
  async execute(session: OrmSession): Promise<QueryResult[]> {
131
131
  const execCtx = session.getExecutionContext();
132
132
  const compiled = this.compile(execCtx.dialect);
133
133
  const payload = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
134
134
  return payloadResultSets(payload);
135
135
  }
136
-
137
- /**
138
- * Returns the Abstract Syntax Tree (AST) representation of the query
139
- * @returns The AST node for the DELETE query
140
- */
141
- getAST(): DeleteQueryNode {
142
- return this.state.ast;
143
- }
144
- }
145
-
146
- const isTableSourceNode = (source: TableDef | TableSourceNode): source is TableSourceNode =>
147
- typeof (source as TableSourceNode).type === 'string';
148
-
136
+
137
+ /**
138
+ * Returns the Abstract Syntax Tree (AST) representation of the query
139
+ * @returns The AST node for the DELETE query
140
+ */
141
+ getAST(): DeleteQueryNode {
142
+ return this.state.ast;
143
+ }
144
+ }
145
+
146
+ const isTableSourceNode = (source: TableDef | TableSourceNode): source is TableSourceNode =>
147
+ typeof (source as TableSourceNode).type === 'string';
148
+
@@ -4,155 +4,155 @@ import {
4
4
  ColumnNode,
5
5
  OperandNode,
6
6
  isValueOperandInput,
7
- valueToOperand
8
- } from '../core/ast/expression.js';
9
- import type { ValueOperandInput } from '../core/ast/expression.js';
10
- import {
11
- buildColumnNodes,
12
- createTableNode
13
- } from '../core/ast/builders.js';
14
-
15
- type InsertRows = Record<string, ValueOperandInput>[];
16
-
17
- /**
18
- * Maintains immutable state for building INSERT queries
19
- */
20
- export class InsertQueryState {
21
- public readonly table: TableDef;
22
- public readonly ast: InsertQueryNode;
23
-
24
- /**
25
- * Creates a new InsertQueryState instance
26
- * @param table - The table definition for the INSERT query
27
- * @param ast - Optional initial AST node, defaults to a basic INSERT query
28
- */
29
- constructor(table: TableDef, ast?: InsertQueryNode) {
30
- this.table = table;
31
- this.ast = ast ?? {
32
- type: 'InsertQuery',
33
- into: createTableNode(table),
34
- columns: [],
35
- source: {
36
- type: 'InsertValues',
37
- rows: []
38
- }
39
- };
40
- }
41
-
42
- private clone(nextAst: InsertQueryNode): InsertQueryState {
43
- return new InsertQueryState(this.table, nextAst);
44
- }
45
-
46
- private ensureColumnsFromRow(rows: InsertRows): ColumnNode[] {
47
- if (this.ast.columns.length) return this.ast.columns;
48
- return buildColumnNodes(this.table, Object.keys(rows[0]));
49
- }
50
-
51
- private appendValues(rows: OperandNode[][]): OperandNode[][] {
52
- if (this.ast.source.type === 'InsertValues') {
53
- return [...this.ast.source.rows, ...rows];
54
- }
55
- return rows;
56
- }
57
-
58
- private getTableColumns(): ColumnNode[] {
59
- const names = Object.keys(this.table.columns);
60
- if (!names.length) return [];
61
- return buildColumnNodes(this.table, names);
62
- }
63
-
64
- /**
65
- * Adds VALUES clause to the INSERT query
66
- * @param rows - Array of row objects to insert
67
- * @returns A new InsertQueryState with the VALUES clause added
68
- * @throws Error if mixing VALUES with SELECT source
69
- * @throws Error if invalid values are provided
70
- */
71
- withValues(rows: InsertRows): InsertQueryState {
72
- if (!rows.length) return this;
73
-
74
- if (this.ast.source.type === 'InsertSelect') {
75
- throw new Error('Cannot mix INSERT ... VALUES with INSERT ... SELECT source.');
76
- }
77
-
78
- const definedColumns = this.ensureColumnsFromRow(rows);
79
-
80
- const newRows: OperandNode[][] = rows.map((row, rowIndex) =>
81
- definedColumns.map(column => {
82
- const rawValue = row[column.name];
83
-
84
- if (!isValueOperandInput(rawValue)) {
85
- throw new Error(
86
- `Invalid insert value for column "${column.name}" in row ${rowIndex}: only string, number, boolean, Date, Buffer, null, or OperandNodes are allowed`
87
- );
88
- }
89
-
90
- return valueToOperand(rawValue);
91
- })
92
- );
93
-
94
- return this.clone({
95
- ...this.ast,
96
- columns: definedColumns,
97
- source: {
98
- type: 'InsertValues',
99
- rows: this.appendValues(newRows)
100
- }
101
- });
102
- }
103
-
104
- /**
105
- * Sets the columns for the INSERT query
106
- * @param columns - Column nodes to insert into
107
- * @returns A new InsertQueryState with the specified columns
108
- */
109
- withColumns(columns: ColumnNode[]): InsertQueryState {
110
- if (!columns.length) return this;
111
- return this.clone({
112
- ...this.ast,
113
- columns: [...columns]
114
- });
115
- }
116
-
117
- /**
118
- * Adds SELECT source to the INSERT query
119
- * @param query - The SELECT query to use as source
120
- * @param columns - Target columns for the INSERT
121
- * @returns A new InsertQueryState with the SELECT source
122
- * @throws Error if mixing SELECT with VALUES source
123
- * @throws Error if no destination columns specified
124
- */
125
- withSelect(query: SelectQueryNode, columns: ColumnNode[]): InsertQueryState {
126
- const targetColumns =
127
- columns.length
128
- ? columns
129
- : this.ast.columns.length
130
- ? this.ast.columns
131
- : this.getTableColumns();
132
-
133
- if (!targetColumns.length) {
134
- throw new Error('INSERT ... SELECT requires specifying destination columns.');
135
- }
136
-
137
- if (this.ast.source.type === 'InsertValues' && this.ast.source.rows.length) {
138
- throw new Error('Cannot mix INSERT ... SELECT with INSERT ... VALUES source.');
139
- }
140
-
141
- return this.clone({
142
- ...this.ast,
143
- columns: [...targetColumns],
144
- source: {
145
- type: 'InsertSelect',
146
- query
147
- }
148
- });
149
- }
150
-
151
- /**
152
- * Adds a RETURNING clause to the INSERT query
153
- * @param columns - Columns to return after insertion
154
- * @returns A new InsertQueryState with the RETURNING clause added
155
- */
7
+ valueToOperand
8
+ } from '../core/ast/expression.js';
9
+ import type { ValueOperandInput } from '../core/ast/expression.js';
10
+ import {
11
+ buildColumnNodes,
12
+ createTableNode
13
+ } from '../core/ast/builders.js';
14
+
15
+ type InsertRows = Record<string, ValueOperandInput>[];
16
+
17
+ /**
18
+ * Maintains immutable state for building INSERT queries
19
+ */
20
+ export class InsertQueryState {
21
+ public readonly table: TableDef;
22
+ public readonly ast: InsertQueryNode;
23
+
24
+ /**
25
+ * Creates a new InsertQueryState instance
26
+ * @param table - The table definition for the INSERT query
27
+ * @param ast - Optional initial AST node, defaults to a basic INSERT query
28
+ */
29
+ constructor(table: TableDef, ast?: InsertQueryNode) {
30
+ this.table = table;
31
+ this.ast = ast ?? {
32
+ type: 'InsertQuery',
33
+ into: createTableNode(table),
34
+ columns: [],
35
+ source: {
36
+ type: 'InsertValues',
37
+ rows: []
38
+ }
39
+ };
40
+ }
41
+
42
+ private clone(nextAst: InsertQueryNode): InsertQueryState {
43
+ return new InsertQueryState(this.table, nextAst);
44
+ }
45
+
46
+ private ensureColumnsFromRow(rows: InsertRows): ColumnNode[] {
47
+ if (this.ast.columns.length) return this.ast.columns;
48
+ return buildColumnNodes(this.table, Object.keys(rows[0]));
49
+ }
50
+
51
+ private appendValues(rows: OperandNode[][]): OperandNode[][] {
52
+ if (this.ast.source.type === 'InsertValues') {
53
+ return [...this.ast.source.rows, ...rows];
54
+ }
55
+ return rows;
56
+ }
57
+
58
+ private getTableColumns(): ColumnNode[] {
59
+ const names = Object.keys(this.table.columns);
60
+ if (!names.length) return [];
61
+ return buildColumnNodes(this.table, names);
62
+ }
63
+
64
+ /**
65
+ * Adds VALUES clause to the INSERT query
66
+ * @param rows - Array of row objects to insert
67
+ * @returns A new InsertQueryState with the VALUES clause added
68
+ * @throws Error if mixing VALUES with SELECT source
69
+ * @throws Error if invalid values are provided
70
+ */
71
+ withValues(rows: InsertRows): InsertQueryState {
72
+ if (!rows.length) return this;
73
+
74
+ if (this.ast.source.type === 'InsertSelect') {
75
+ throw new Error('Cannot mix INSERT ... VALUES with INSERT ... SELECT source.');
76
+ }
77
+
78
+ const definedColumns = this.ensureColumnsFromRow(rows);
79
+
80
+ const newRows: OperandNode[][] = rows.map((row, rowIndex) =>
81
+ definedColumns.map(column => {
82
+ const rawValue = row[column.name];
83
+
84
+ if (!isValueOperandInput(rawValue)) {
85
+ throw new Error(
86
+ `Invalid insert value for column "${column.name}" in row ${rowIndex}: only string, number, boolean, Date, Buffer, null, or OperandNodes are allowed`
87
+ );
88
+ }
89
+
90
+ return valueToOperand(rawValue);
91
+ })
92
+ );
93
+
94
+ return this.clone({
95
+ ...this.ast,
96
+ columns: definedColumns,
97
+ source: {
98
+ type: 'InsertValues',
99
+ rows: this.appendValues(newRows)
100
+ }
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Sets the columns for the INSERT query
106
+ * @param columns - Column nodes to insert into
107
+ * @returns A new InsertQueryState with the specified columns
108
+ */
109
+ withColumns(columns: ColumnNode[]): InsertQueryState {
110
+ if (!columns.length) return this;
111
+ return this.clone({
112
+ ...this.ast,
113
+ columns: [...columns]
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Adds SELECT source to the INSERT query
119
+ * @param query - The SELECT query to use as source
120
+ * @param columns - Target columns for the INSERT
121
+ * @returns A new InsertQueryState with the SELECT source
122
+ * @throws Error if mixing SELECT with VALUES source
123
+ * @throws Error if no destination columns specified
124
+ */
125
+ withSelect(query: SelectQueryNode, columns: ColumnNode[]): InsertQueryState {
126
+ const targetColumns =
127
+ columns.length
128
+ ? columns
129
+ : this.ast.columns.length
130
+ ? this.ast.columns
131
+ : this.getTableColumns();
132
+
133
+ if (!targetColumns.length) {
134
+ throw new Error('INSERT ... SELECT requires specifying destination columns.');
135
+ }
136
+
137
+ if (this.ast.source.type === 'InsertValues' && this.ast.source.rows.length) {
138
+ throw new Error('Cannot mix INSERT ... SELECT with INSERT ... VALUES source.');
139
+ }
140
+
141
+ return this.clone({
142
+ ...this.ast,
143
+ columns: [...targetColumns],
144
+ source: {
145
+ type: 'InsertSelect',
146
+ query
147
+ }
148
+ });
149
+ }
150
+
151
+ /**
152
+ * Adds a RETURNING clause to the INSERT query
153
+ * @param columns - Columns to return after insertion
154
+ * @returns A new InsertQueryState with the RETURNING clause added
155
+ */
156
156
  withReturning(columns: ColumnNode[]): InsertQueryState {
157
157
  return this.clone({
158
158
  ...this.ast,