@mikro-orm/sql 7.0.15-dev.9 → 7.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/AbstractSqlConnection.d.ts +94 -58
  2. package/AbstractSqlConnection.js +235 -238
  3. package/AbstractSqlDriver.d.ts +410 -155
  4. package/AbstractSqlDriver.js +2100 -1972
  5. package/AbstractSqlPlatform.d.ts +86 -76
  6. package/AbstractSqlPlatform.js +169 -167
  7. package/PivotCollectionPersister.d.ts +33 -15
  8. package/PivotCollectionPersister.js +158 -160
  9. package/README.md +1 -1
  10. package/SqlEntityManager.d.ts +67 -22
  11. package/SqlEntityManager.js +54 -38
  12. package/SqlEntityRepository.d.ts +14 -14
  13. package/SqlEntityRepository.js +23 -23
  14. package/SqlMikroORM.d.ts +49 -8
  15. package/SqlMikroORM.js +8 -8
  16. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -12
  17. package/dialects/mssql/MsSqlNativeQueryBuilder.js +199 -201
  18. package/dialects/mysql/BaseMySqlPlatform.d.ts +65 -46
  19. package/dialects/mysql/BaseMySqlPlatform.js +137 -134
  20. package/dialects/mysql/MySqlExceptionConverter.d.ts +6 -6
  21. package/dialects/mysql/MySqlExceptionConverter.js +91 -77
  22. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +3 -3
  23. package/dialects/mysql/MySqlNativeQueryBuilder.js +66 -69
  24. package/dialects/mysql/MySqlSchemaHelper.d.ts +58 -39
  25. package/dialects/mysql/MySqlSchemaHelper.js +327 -319
  26. package/dialects/oracledb/OracleDialect.d.ts +81 -52
  27. package/dialects/oracledb/OracleDialect.js +155 -149
  28. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +12 -12
  29. package/dialects/oracledb/OracleNativeQueryBuilder.js +239 -243
  30. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +110 -107
  31. package/dialects/postgresql/BasePostgreSqlPlatform.js +370 -369
  32. package/dialects/postgresql/FullTextType.d.ts +10 -6
  33. package/dialects/postgresql/FullTextType.js +51 -51
  34. package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +5 -5
  35. package/dialects/postgresql/PostgreSqlExceptionConverter.js +55 -43
  36. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
  37. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +4 -4
  38. package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +117 -82
  39. package/dialects/postgresql/PostgreSqlSchemaHelper.js +748 -712
  40. package/dialects/sqlite/BaseSqliteConnection.d.ts +3 -5
  41. package/dialects/sqlite/BaseSqliteConnection.js +21 -19
  42. package/dialects/sqlite/NodeSqliteDialect.d.ts +1 -1
  43. package/dialects/sqlite/NodeSqliteDialect.js +23 -23
  44. package/dialects/sqlite/SqliteDriver.d.ts +1 -1
  45. package/dialects/sqlite/SqliteDriver.js +3 -3
  46. package/dialects/sqlite/SqliteExceptionConverter.d.ts +6 -6
  47. package/dialects/sqlite/SqliteExceptionConverter.js +67 -51
  48. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +2 -2
  49. package/dialects/sqlite/SqliteNativeQueryBuilder.js +7 -7
  50. package/dialects/sqlite/SqlitePlatform.d.ts +64 -73
  51. package/dialects/sqlite/SqlitePlatform.js +143 -143
  52. package/dialects/sqlite/SqliteSchemaHelper.d.ts +78 -61
  53. package/dialects/sqlite/SqliteSchemaHelper.js +541 -522
  54. package/package.json +3 -3
  55. package/plugin/index.d.ts +42 -35
  56. package/plugin/index.js +43 -36
  57. package/plugin/transformer.d.ts +137 -95
  58. package/plugin/transformer.js +1012 -881
  59. package/query/ArrayCriteriaNode.d.ts +4 -4
  60. package/query/ArrayCriteriaNode.js +18 -18
  61. package/query/CriteriaNode.d.ts +35 -25
  62. package/query/CriteriaNode.js +142 -132
  63. package/query/CriteriaNodeFactory.d.ts +49 -6
  64. package/query/CriteriaNodeFactory.js +97 -94
  65. package/query/NativeQueryBuilder.d.ts +120 -120
  66. package/query/NativeQueryBuilder.js +507 -501
  67. package/query/ObjectCriteriaNode.d.ts +12 -12
  68. package/query/ObjectCriteriaNode.js +298 -282
  69. package/query/QueryBuilder.d.ts +1558 -906
  70. package/query/QueryBuilder.js +2346 -2217
  71. package/query/QueryBuilderHelper.d.ts +153 -72
  72. package/query/QueryBuilderHelper.js +1084 -1032
  73. package/query/ScalarCriteriaNode.d.ts +3 -3
  74. package/query/ScalarCriteriaNode.js +53 -46
  75. package/query/enums.d.ts +14 -14
  76. package/query/enums.js +14 -14
  77. package/query/raw.d.ts +16 -6
  78. package/query/raw.js +10 -10
  79. package/schema/DatabaseSchema.d.ts +74 -50
  80. package/schema/DatabaseSchema.js +359 -331
  81. package/schema/DatabaseTable.d.ts +96 -73
  82. package/schema/DatabaseTable.js +1046 -974
  83. package/schema/SchemaComparator.d.ts +70 -66
  84. package/schema/SchemaComparator.js +790 -765
  85. package/schema/SchemaHelper.d.ts +128 -97
  86. package/schema/SchemaHelper.js +683 -668
  87. package/schema/SqlSchemaGenerator.d.ts +79 -59
  88. package/schema/SqlSchemaGenerator.js +525 -495
  89. package/typings.d.ts +405 -275
@@ -1,507 +1,513 @@
1
- import { isRaw, LockMode, raw, Utils, } from '@mikro-orm/core';
1
+ import { isRaw, LockMode, raw, Utils } from '@mikro-orm/core';
2
2
  import { QueryType } from './enums.js';
3
3
  /** @internal */
4
4
  export class NativeQueryBuilder {
5
- platform;
6
- type;
7
- parts = [];
8
- params = [];
9
- options = {};
10
- constructor(platform) {
11
- this.platform = platform;
12
- }
13
- select(fields) {
14
- this.type = QueryType.SELECT;
15
- this.options.select ??= [];
16
- this.options.select.push(...Utils.asArray(fields));
17
- return this;
18
- }
19
- count(fields = '*', distinct) {
20
- this.type = QueryType.COUNT;
21
- this.options.select = Utils.asArray(fields);
22
- this.options.distinct = distinct;
23
- return this;
24
- }
25
- into(tableName, options) {
26
- return this.from(tableName, options);
27
- }
28
- from(tableName, options) {
29
- if (tableName instanceof NativeQueryBuilder) {
30
- tableName = tableName.toRaw();
31
- }
32
- if (typeof tableName === 'string') {
33
- const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
34
- const alias = options?.alias ? `${asKeyword}${this.platform.quoteIdentifier(options.alias)}` : '';
35
- const schema = options?.schema && options.schema !== this.platform.getDefaultSchemaName() ? `${options.schema}.` : '';
36
- tableName = this.quote(schema + tableName) + alias;
37
- }
38
- this.options.tableName = tableName;
39
- this.options.indexHint = options?.indexHint;
40
- return this;
41
- }
42
- where(sql, params) {
43
- this.options.where = { sql, params };
44
- return this;
45
- }
46
- having(sql, params) {
47
- this.options.having = { sql, params };
48
- return this;
49
- }
50
- groupBy(groupBy) {
51
- this.options.groupBy = groupBy;
52
- return this;
53
- }
54
- join(sql, params) {
55
- this.options.joins ??= [];
56
- this.options.joins.push({ sql, params });
57
- return this;
58
- }
59
- orderBy(orderBy) {
60
- this.options.orderBy = orderBy;
61
- return this;
62
- }
63
- /**
64
- * The sub-query is compiled eagerly at call time — later mutations to the
65
- * sub-query builder will not be reflected in this CTE.
66
- */
67
- with(name, query, options) {
68
- return this.addCte(name, query, options);
69
- }
70
- /**
71
- * Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
72
- * The sub-query is compiled eagerly later mutations will not be reflected.
73
- */
74
- withRecursive(name, query, options) {
75
- return this.addCte(name, query, options, true);
76
- }
77
- addCte(name, query, options, recursive) {
78
- this.options.ctes ??= [];
79
- if (this.options.ctes.some(cte => cte.name === name)) {
80
- throw new Error(`CTE with name '${name}' already exists`);
81
- }
82
- const { sql, params } = query instanceof NativeQueryBuilder ? query.compile() : { sql: query.sql, params: [...query.params] };
83
- this.options.ctes.push({
84
- name,
85
- sql,
86
- params,
87
- recursive,
88
- columns: options?.columns,
89
- materialized: options?.materialized,
90
- });
91
- return this;
92
- }
93
- toString() {
94
- const { sql, params } = this.compile();
95
- return this.platform.formatQuery(sql, params);
96
- }
97
- compile() {
98
- if (!this.type) {
99
- throw new Error('No query type provided');
100
- }
101
- this.parts.length = 0;
102
- this.params.length = 0;
103
- if (this.options.comment) {
104
- this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
105
- }
106
- this.compileCtes();
107
- switch (this.type) {
108
- case QueryType.SELECT:
109
- case QueryType.COUNT:
110
- this.compileSelect();
111
- break;
112
- case QueryType.INSERT:
113
- this.compileInsert();
114
- break;
115
- case QueryType.UPDATE:
116
- this.compileUpdate();
117
- break;
118
- case QueryType.DELETE:
119
- this.compileDelete();
120
- break;
121
- case QueryType.TRUNCATE:
122
- this.compileTruncate();
123
- break;
124
- }
125
- this.addOnConflictClause();
126
- if (this.options.returning && this.platform.usesReturningStatement()) {
127
- const fields = this.options.returning.map(field => this.quote(field));
128
- this.parts.push(`returning ${fields.join(', ')}`);
129
- }
130
- this.addLockClause();
131
- return this.combineParts();
132
- }
133
- addLockClause() {
134
- if (!this.options.lockMode) {
135
- return;
136
- }
137
- if ([LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_READ_OR_FAIL].includes(this.options.lockMode)) {
138
- this.parts.push('for share');
139
- }
140
- if ([LockMode.PESSIMISTIC_WRITE, LockMode.PESSIMISTIC_PARTIAL_WRITE, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(this.options.lockMode)) {
141
- this.parts.push('for update');
142
- }
143
- if (this.options.lockTables?.length) {
144
- const fields = this.options.lockTables.map(field => this.quote(field));
145
- this.parts.push(`of ${fields.join(', ')}`);
146
- }
147
- if ([LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_PARTIAL_WRITE].includes(this.options.lockMode)) {
148
- this.parts.push('skip locked');
149
- }
150
- if ([LockMode.PESSIMISTIC_READ_OR_FAIL, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(this.options.lockMode)) {
151
- this.parts.push('nowait');
152
- }
153
- }
154
- addOnConflictClause() {
155
- const clause = this.options.onConflict;
156
- if (!clause) {
157
- return;
158
- }
159
- this.parts.push('on conflict');
160
- if (isRaw(clause.fields)) {
161
- this.parts.push(clause.fields.sql);
162
- this.params.push(...clause.fields.params);
163
- }
164
- else if (clause.fields.length > 0) {
165
- const fields = clause.fields.map(field => this.quote(field));
166
- this.parts.push(`(${fields.join(', ')})`);
167
- }
168
- if (clause.ignore) {
169
- this.parts.push('do nothing');
170
- }
171
- if (Utils.isObject(clause.merge)) {
172
- this.parts.push('do update set');
173
- const fields = Object.keys(clause.merge).map(field => {
174
- this.params.push(clause.merge[field]);
175
- return `${this.quote(field)} = ?`;
176
- });
177
- this.parts.push(fields.join(', '));
178
- }
179
- else if (clause.merge) {
180
- this.parts.push('do update set');
181
- if (clause.merge.length) {
182
- const fields = clause.merge.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
183
- this.parts.push(fields.join(', '));
184
- }
185
- else {
186
- const dataAsArray = Utils.asArray(this.options.data);
187
- const keys = Object.keys(dataAsArray[0]);
188
- const fields = keys.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
189
- this.parts.push(fields.join(', '));
190
- }
191
- }
192
- if (clause.where) {
193
- this.parts.push(`where ${clause.where.sql}`);
194
- this.params.push(...clause.where.params);
195
- }
196
- }
197
- combineParts() {
198
- let sql = this.parts.join(' ');
199
- if (this.options.wrap) {
200
- const [a, b] = this.options.wrap;
201
- sql = `${a}${sql}${b}`;
202
- }
203
- return { sql, params: this.params };
204
- }
205
- limit(limit) {
206
- this.options.limit = limit;
207
- return this;
208
- }
209
- offset(offset) {
210
- this.options.offset = offset;
211
- return this;
212
- }
213
- insert(data) {
214
- this.type = QueryType.INSERT;
215
- this.options.data = data;
216
- return this;
217
- }
218
- update(data) {
219
- this.type = QueryType.UPDATE;
220
- this.options.data ??= {};
221
- Object.assign(this.options.data, data);
222
- return this;
223
- }
224
- delete() {
225
- this.type = QueryType.DELETE;
226
- return this;
227
- }
228
- truncate() {
229
- this.type = QueryType.TRUNCATE;
230
- return this;
231
- }
232
- distinct() {
233
- this.options.distinct = true;
234
- return this;
235
- }
236
- distinctOn(fields) {
237
- this.options.distinctOn = fields;
238
- return this;
239
- }
240
- onConflict(options) {
241
- this.options.onConflict = options;
242
- return options;
243
- }
244
- returning(fields) {
245
- this.options.returning = fields;
246
- return this;
247
- }
248
- lockMode(lockMode, lockTables) {
249
- this.options.lockMode = lockMode;
250
- this.options.lockTables = lockTables;
251
- return this;
252
- }
253
- comment(comment) {
254
- this.options.comment ??= [];
255
- this.options.comment.push(...Utils.asArray(comment));
256
- return this;
257
- }
258
- hintComment(comment) {
259
- this.options.hintComment ??= [];
260
- this.options.hintComment.push(...Utils.asArray(comment));
261
- return this;
262
- }
263
- setFlags(flags) {
264
- this.options.flags = flags;
265
- return this;
266
- }
267
- clear(clause) {
268
- delete this.options[clause];
269
- return this;
270
- }
271
- wrap(prefix, suffix) {
272
- this.options.wrap = [prefix, suffix];
273
- return this;
274
- }
275
- as(alias) {
276
- this.wrap('(', `) as ${this.platform.quoteIdentifier(alias)}`);
277
- return this;
278
- }
279
- toRaw() {
280
- const { sql, params } = this.compile();
281
- return raw(sql, params);
282
- }
283
- compileSelect() {
284
- const wrapCountSubquery = this.needsCountSubquery();
285
- if (wrapCountSubquery) {
286
- this.parts.push(`select count(*) as ${this.quote('count')} from (`);
287
- }
288
- this.parts.push('select');
289
- this.addHintComment();
290
- this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
291
- if (this.options.joins) {
292
- for (const join of this.options.joins) {
293
- this.parts.push(join.sql);
294
- this.params.push(...join.params);
295
- }
296
- }
297
- if (this.options.where?.sql.trim()) {
298
- this.parts.push(`where ${this.options.where.sql}`);
299
- this.options.where.params.forEach(p => this.params.push(p));
300
- }
301
- if (this.options.groupBy) {
302
- const fields = this.options.groupBy.map(field => this.quote(field));
303
- this.parts.push(`group by ${fields.join(', ')}`);
304
- }
305
- if (this.options.having) {
306
- this.parts.push(`having ${this.options.having.sql}`);
307
- this.params.push(...this.options.having.params);
308
- }
309
- if (!wrapCountSubquery) {
310
- if (this.options.orderBy) {
311
- this.parts.push(`order by ${this.options.orderBy}`);
312
- }
313
- if (this.options.limit != null) {
314
- this.parts.push(`limit ?`);
315
- this.params.push(this.options.limit);
316
- }
317
- if (this.options.offset != null) {
318
- this.parts.push(`offset ?`);
319
- this.params.push(this.options.offset);
320
- }
321
- }
322
- if (wrapCountSubquery) {
323
- const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
324
- this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
325
- }
326
- }
327
- /** Whether this COUNT query needs a subquery wrapper for multi-column distinct. */
328
- needsCountSubquery() {
329
- return (this.type === QueryType.COUNT &&
330
- !!this.options.distinct &&
331
- this.options.select.length > 1 &&
332
- !this.platform.supportsMultiColumnCountDistinct());
333
- }
334
- getFields(countSubquery) {
335
- if (!this.options.select || this.options.select.length === 0) {
336
- throw new Error('No fields selected');
337
- }
338
- let fields = this.options.select.map(field => this.quote(field)).join(', ');
339
- // count subquery emits just `distinct col1, col2` — the outer wrapper adds count(*)
340
- if (countSubquery) {
341
- return `distinct ${fields}`;
342
- }
343
- if (this.options.distinct) {
344
- fields = `distinct ${fields}`;
345
- }
346
- else if (this.options.distinctOn) {
347
- fields = `distinct on (${this.options.distinctOn.map(field => this.quote(field)).join(', ')}) ${fields}`;
348
- }
349
- if (this.type === QueryType.COUNT) {
350
- fields = `count(${fields}) as ${this.quote('count')}`;
351
- }
352
- return fields;
353
- }
354
- compileInsert() {
355
- if (!this.options.data) {
356
- throw new Error('No data provided');
357
- }
358
- this.parts.push('insert');
359
- this.addHintComment();
360
- this.parts.push(`into ${this.getTableName()}`);
361
- if (Object.keys(this.options.data).length === 0) {
362
- this.addOutputClause('inserted');
363
- this.parts.push('default values');
364
- return;
365
- }
366
- const parts = this.processInsertData();
367
- this.parts.push(parts.join(', '));
368
- }
369
- addOutputClause(type) {
370
- if (this.options.returning && this.platform.usesOutputStatement()) {
371
- const fields = this.options.returning.map(field => `${type}.${this.quote(field)}`);
372
- this.parts.push(`output ${fields.join(', ')}`);
373
- }
374
- }
375
- processInsertData() {
5
+ platform;
6
+ type;
7
+ parts = [];
8
+ params = [];
9
+ options = {};
10
+ constructor(platform) {
11
+ this.platform = platform;
12
+ }
13
+ select(fields) {
14
+ this.type = QueryType.SELECT;
15
+ this.options.select ??= [];
16
+ this.options.select.push(...Utils.asArray(fields));
17
+ return this;
18
+ }
19
+ count(fields = '*', distinct) {
20
+ this.type = QueryType.COUNT;
21
+ this.options.select = Utils.asArray(fields);
22
+ this.options.distinct = distinct;
23
+ return this;
24
+ }
25
+ into(tableName, options) {
26
+ return this.from(tableName, options);
27
+ }
28
+ from(tableName, options) {
29
+ if (tableName instanceof NativeQueryBuilder) {
30
+ tableName = tableName.toRaw();
31
+ }
32
+ if (typeof tableName === 'string') {
33
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
34
+ const alias = options?.alias ? `${asKeyword}${this.platform.quoteIdentifier(options.alias)}` : '';
35
+ const schema =
36
+ options?.schema && options.schema !== this.platform.getDefaultSchemaName() ? `${options.schema}.` : '';
37
+ tableName = this.quote(schema + tableName) + alias;
38
+ }
39
+ this.options.tableName = tableName;
40
+ this.options.indexHint = options?.indexHint;
41
+ return this;
42
+ }
43
+ where(sql, params) {
44
+ this.options.where = { sql, params };
45
+ return this;
46
+ }
47
+ having(sql, params) {
48
+ this.options.having = { sql, params };
49
+ return this;
50
+ }
51
+ groupBy(groupBy) {
52
+ this.options.groupBy = groupBy;
53
+ return this;
54
+ }
55
+ join(sql, params) {
56
+ this.options.joins ??= [];
57
+ this.options.joins.push({ sql, params });
58
+ return this;
59
+ }
60
+ orderBy(orderBy) {
61
+ this.options.orderBy = orderBy;
62
+ return this;
63
+ }
64
+ /**
65
+ * The sub-query is compiled eagerly at call time later mutations to the
66
+ * sub-query builder will not be reflected in this CTE.
67
+ */
68
+ with(name, query, options) {
69
+ return this.addCte(name, query, options);
70
+ }
71
+ /**
72
+ * Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
73
+ * The sub-query is compiled eagerly — later mutations will not be reflected.
74
+ */
75
+ withRecursive(name, query, options) {
76
+ return this.addCte(name, query, options, true);
77
+ }
78
+ addCte(name, query, options, recursive) {
79
+ this.options.ctes ??= [];
80
+ if (this.options.ctes.some(cte => cte.name === name)) {
81
+ throw new Error(`CTE with name '${name}' already exists`);
82
+ }
83
+ const { sql, params } =
84
+ query instanceof NativeQueryBuilder ? query.compile() : { sql: query.sql, params: [...query.params] };
85
+ this.options.ctes.push({
86
+ name,
87
+ sql,
88
+ params,
89
+ recursive,
90
+ columns: options?.columns,
91
+ materialized: options?.materialized,
92
+ });
93
+ return this;
94
+ }
95
+ toString() {
96
+ const { sql, params } = this.compile();
97
+ return this.platform.formatQuery(sql, params);
98
+ }
99
+ compile() {
100
+ if (!this.type) {
101
+ throw new Error('No query type provided');
102
+ }
103
+ this.parts.length = 0;
104
+ this.params.length = 0;
105
+ if (this.options.comment) {
106
+ this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
107
+ }
108
+ this.compileCtes();
109
+ switch (this.type) {
110
+ case QueryType.SELECT:
111
+ case QueryType.COUNT:
112
+ this.compileSelect();
113
+ break;
114
+ case QueryType.INSERT:
115
+ this.compileInsert();
116
+ break;
117
+ case QueryType.UPDATE:
118
+ this.compileUpdate();
119
+ break;
120
+ case QueryType.DELETE:
121
+ this.compileDelete();
122
+ break;
123
+ case QueryType.TRUNCATE:
124
+ this.compileTruncate();
125
+ break;
126
+ }
127
+ this.addOnConflictClause();
128
+ if (this.options.returning && this.platform.usesReturningStatement()) {
129
+ const fields = this.options.returning.map(field => this.quote(field));
130
+ this.parts.push(`returning ${fields.join(', ')}`);
131
+ }
132
+ this.addLockClause();
133
+ return this.combineParts();
134
+ }
135
+ addLockClause() {
136
+ if (!this.options.lockMode) {
137
+ return;
138
+ }
139
+ if (
140
+ [LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_READ_OR_FAIL].includes(
141
+ this.options.lockMode,
142
+ )
143
+ ) {
144
+ this.parts.push('for share');
145
+ }
146
+ if (
147
+ [LockMode.PESSIMISTIC_WRITE, LockMode.PESSIMISTIC_PARTIAL_WRITE, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(
148
+ this.options.lockMode,
149
+ )
150
+ ) {
151
+ this.parts.push('for update');
152
+ }
153
+ if (this.options.lockTables?.length) {
154
+ const fields = this.options.lockTables.map(field => this.quote(field));
155
+ this.parts.push(`of ${fields.join(', ')}`);
156
+ }
157
+ if ([LockMode.PESSIMISTIC_PARTIAL_READ, LockMode.PESSIMISTIC_PARTIAL_WRITE].includes(this.options.lockMode)) {
158
+ this.parts.push('skip locked');
159
+ }
160
+ if ([LockMode.PESSIMISTIC_READ_OR_FAIL, LockMode.PESSIMISTIC_WRITE_OR_FAIL].includes(this.options.lockMode)) {
161
+ this.parts.push('nowait');
162
+ }
163
+ }
164
+ addOnConflictClause() {
165
+ const clause = this.options.onConflict;
166
+ if (!clause) {
167
+ return;
168
+ }
169
+ this.parts.push('on conflict');
170
+ if (isRaw(clause.fields)) {
171
+ this.parts.push(clause.fields.sql);
172
+ this.params.push(...clause.fields.params);
173
+ } else if (clause.fields.length > 0) {
174
+ const fields = clause.fields.map(field => this.quote(field));
175
+ this.parts.push(`(${fields.join(', ')})`);
176
+ }
177
+ if (clause.ignore) {
178
+ this.parts.push('do nothing');
179
+ }
180
+ if (Utils.isObject(clause.merge)) {
181
+ this.parts.push('do update set');
182
+ const fields = Object.keys(clause.merge).map(field => {
183
+ this.params.push(clause.merge[field]);
184
+ return `${this.quote(field)} = ?`;
185
+ });
186
+ this.parts.push(fields.join(', '));
187
+ } else if (clause.merge) {
188
+ this.parts.push('do update set');
189
+ if (clause.merge.length) {
190
+ const fields = clause.merge.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
191
+ this.parts.push(fields.join(', '));
192
+ } else {
376
193
  const dataAsArray = Utils.asArray(this.options.data);
377
194
  const keys = Object.keys(dataAsArray[0]);
378
- const values = keys.map(() => '?');
379
- const parts = [];
380
- this.parts.push(`(${keys.map(key => this.quote(key)).join(', ')})`);
381
- this.addOutputClause('inserted');
382
- this.parts.push('values');
383
- for (const data of dataAsArray) {
384
- for (const key of keys) {
385
- if (typeof data[key] === 'undefined') {
386
- this.params.push(this.platform.usesDefaultKeyword() ? raw('default') : null);
387
- }
388
- else {
389
- this.params.push(data[key]);
390
- }
391
- }
392
- parts.push(`(${values.join(', ')})`);
393
- }
394
- return parts;
395
- }
396
- compileUpdate() {
397
- if (!this.options.data || Object.keys(this.options.data).length === 0) {
398
- throw new Error('No data provided');
399
- }
400
- this.parts.push('update');
401
- this.addHintComment();
402
- this.parts.push(this.getTableName());
403
- if (this.options.joins) {
404
- for (const join of this.options.joins) {
405
- this.parts.push(join.sql);
406
- this.params.push(...join.params);
407
- }
408
- }
409
- this.parts.push('set');
410
- if (this.options.data) {
411
- const parts = [];
412
- for (const key of Object.keys(this.options.data)) {
413
- parts.push(`${this.quote(key)} = ?`);
414
- this.params.push(this.options.data[key]);
415
- }
416
- this.parts.push(parts.join(', '));
417
- }
418
- this.addOutputClause('inserted');
419
- if (this.options.where?.sql.trim()) {
420
- this.parts.push(`where ${this.options.where.sql}`);
421
- this.params.push(...this.options.where.params);
422
- }
423
- }
424
- compileDelete() {
425
- this.parts.push('delete');
426
- this.addHintComment();
427
- this.parts.push(`from ${this.getTableName()}`);
428
- this.addOutputClause('deleted');
429
- if (this.options.where?.sql.trim()) {
430
- this.parts.push(`where ${this.options.where.sql}`);
431
- this.params.push(...this.options.where.params);
432
- }
433
- }
434
- compileTruncate() {
435
- const sql = `truncate table ${this.getTableName()}`;
436
- this.parts.push(sql);
437
- }
438
- addHintComment() {
439
- if (this.options.hintComment) {
440
- this.parts.push(`/*+ ${this.options.hintComment.join(' ')} */`);
441
- }
442
- }
443
- compileCtes() {
444
- const ctes = this.options.ctes;
445
- if (!ctes || ctes.length === 0) {
446
- return;
447
- }
448
- const hasRecursive = ctes.some(cte => cte.recursive);
449
- const keyword = this.getCteKeyword(hasRecursive);
450
- const cteParts = [];
451
- for (const cte of ctes) {
452
- let part = this.quote(cte.name);
453
- if (cte.columns?.length) {
454
- part += ` (${cte.columns.map(c => this.quote(c)).join(', ')})`;
455
- }
456
- part += ' as';
457
- if (cte.materialized === true) {
458
- part += ' materialized';
459
- }
460
- else if (cte.materialized === false) {
461
- part += ' not materialized';
462
- }
463
- part += ` (${cte.sql})`;
464
- this.params.push(...cte.params);
465
- cteParts.push(part);
466
- }
467
- this.parts.push(`${keyword} ${cteParts.join(', ')}`);
468
- }
469
- getCteKeyword(hasRecursive) {
470
- return hasRecursive ? 'with recursive' : 'with';
471
- }
472
- getTableName() {
473
- if (!this.options.tableName) {
474
- throw new Error('No table name provided');
475
- }
476
- const indexHint = this.options.indexHint ? ' ' + this.options.indexHint : '';
477
- if (isRaw(this.options.tableName)) {
478
- this.params.push(...this.options.tableName.params);
479
- return this.options.tableName.sql + indexHint;
480
- }
481
- return this.options.tableName + indexHint;
482
- }
483
- quote(id) {
484
- if (isRaw(id)) {
485
- return this.platform.formatQuery(id.sql, id.params);
486
- }
487
- if (id instanceof NativeQueryBuilder) {
488
- const { sql, params } = id.compile();
489
- return this.platform.formatQuery(sql, params);
490
- }
491
- if (id.endsWith('.*')) {
492
- const schema = this.platform.quoteIdentifier(id.substring(0, id.indexOf('.')));
493
- return schema + '.*';
494
- }
495
- if (id.toLowerCase().includes(' as ')) {
496
- const parts = id.split(/ as /i);
497
- const a = this.platform.quoteIdentifier(parts[0]);
498
- const b = this.platform.quoteIdentifier(parts[1]);
499
- const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
500
- return `${a}${asKeyword}${b}`;
501
- }
502
- if (id === '*') {
503
- return id;
504
- }
505
- return this.platform.quoteIdentifier(id);
506
- }
195
+ const fields = keys.map(field => `${this.quote(field)} = excluded.${this.quote(field)}`);
196
+ this.parts.push(fields.join(', '));
197
+ }
198
+ }
199
+ if (clause.where) {
200
+ this.parts.push(`where ${clause.where.sql}`);
201
+ this.params.push(...clause.where.params);
202
+ }
203
+ }
204
+ combineParts() {
205
+ let sql = this.parts.join(' ');
206
+ if (this.options.wrap) {
207
+ const [a, b] = this.options.wrap;
208
+ sql = `${a}${sql}${b}`;
209
+ }
210
+ return { sql, params: this.params };
211
+ }
212
+ limit(limit) {
213
+ this.options.limit = limit;
214
+ return this;
215
+ }
216
+ offset(offset) {
217
+ this.options.offset = offset;
218
+ return this;
219
+ }
220
+ insert(data) {
221
+ this.type = QueryType.INSERT;
222
+ this.options.data = data;
223
+ return this;
224
+ }
225
+ update(data) {
226
+ this.type = QueryType.UPDATE;
227
+ this.options.data ??= {};
228
+ Object.assign(this.options.data, data);
229
+ return this;
230
+ }
231
+ delete() {
232
+ this.type = QueryType.DELETE;
233
+ return this;
234
+ }
235
+ truncate() {
236
+ this.type = QueryType.TRUNCATE;
237
+ return this;
238
+ }
239
+ distinct() {
240
+ this.options.distinct = true;
241
+ return this;
242
+ }
243
+ distinctOn(fields) {
244
+ this.options.distinctOn = fields;
245
+ return this;
246
+ }
247
+ onConflict(options) {
248
+ this.options.onConflict = options;
249
+ return options;
250
+ }
251
+ returning(fields) {
252
+ this.options.returning = fields;
253
+ return this;
254
+ }
255
+ lockMode(lockMode, lockTables) {
256
+ this.options.lockMode = lockMode;
257
+ this.options.lockTables = lockTables;
258
+ return this;
259
+ }
260
+ comment(comment) {
261
+ this.options.comment ??= [];
262
+ this.options.comment.push(...Utils.asArray(comment));
263
+ return this;
264
+ }
265
+ hintComment(comment) {
266
+ this.options.hintComment ??= [];
267
+ this.options.hintComment.push(...Utils.asArray(comment));
268
+ return this;
269
+ }
270
+ setFlags(flags) {
271
+ this.options.flags = flags;
272
+ return this;
273
+ }
274
+ clear(clause) {
275
+ delete this.options[clause];
276
+ return this;
277
+ }
278
+ wrap(prefix, suffix) {
279
+ this.options.wrap = [prefix, suffix];
280
+ return this;
281
+ }
282
+ as(alias) {
283
+ this.wrap('(', `) as ${this.platform.quoteIdentifier(alias)}`);
284
+ return this;
285
+ }
286
+ toRaw() {
287
+ const { sql, params } = this.compile();
288
+ return raw(sql, params);
289
+ }
290
+ compileSelect() {
291
+ const wrapCountSubquery = this.needsCountSubquery();
292
+ if (wrapCountSubquery) {
293
+ this.parts.push(`select count(*) as ${this.quote('count')} from (`);
294
+ }
295
+ this.parts.push('select');
296
+ this.addHintComment();
297
+ this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
298
+ if (this.options.joins) {
299
+ for (const join of this.options.joins) {
300
+ this.parts.push(join.sql);
301
+ this.params.push(...join.params);
302
+ }
303
+ }
304
+ if (this.options.where?.sql.trim()) {
305
+ this.parts.push(`where ${this.options.where.sql}`);
306
+ this.options.where.params.forEach(p => this.params.push(p));
307
+ }
308
+ if (this.options.groupBy) {
309
+ const fields = this.options.groupBy.map(field => this.quote(field));
310
+ this.parts.push(`group by ${fields.join(', ')}`);
311
+ }
312
+ if (this.options.having) {
313
+ this.parts.push(`having ${this.options.having.sql}`);
314
+ this.params.push(...this.options.having.params);
315
+ }
316
+ if (!wrapCountSubquery) {
317
+ if (this.options.orderBy) {
318
+ this.parts.push(`order by ${this.options.orderBy}`);
319
+ }
320
+ if (this.options.limit != null) {
321
+ this.parts.push(`limit ?`);
322
+ this.params.push(this.options.limit);
323
+ }
324
+ if (this.options.offset != null) {
325
+ this.parts.push(`offset ?`);
326
+ this.params.push(this.options.offset);
327
+ }
328
+ }
329
+ if (wrapCountSubquery) {
330
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
331
+ this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
332
+ }
333
+ }
334
+ /** Whether this COUNT query needs a subquery wrapper for multi-column distinct. */
335
+ needsCountSubquery() {
336
+ return (
337
+ this.type === QueryType.COUNT &&
338
+ !!this.options.distinct &&
339
+ this.options.select.length > 1 &&
340
+ !this.platform.supportsMultiColumnCountDistinct()
341
+ );
342
+ }
343
+ getFields(countSubquery) {
344
+ if (!this.options.select || this.options.select.length === 0) {
345
+ throw new Error('No fields selected');
346
+ }
347
+ let fields = this.options.select.map(field => this.quote(field)).join(', ');
348
+ // count subquery emits just `distinct col1, col2` — the outer wrapper adds count(*)
349
+ if (countSubquery) {
350
+ return `distinct ${fields}`;
351
+ }
352
+ if (this.options.distinct) {
353
+ fields = `distinct ${fields}`;
354
+ } else if (this.options.distinctOn) {
355
+ fields = `distinct on (${this.options.distinctOn.map(field => this.quote(field)).join(', ')}) ${fields}`;
356
+ }
357
+ if (this.type === QueryType.COUNT) {
358
+ fields = `count(${fields}) as ${this.quote('count')}`;
359
+ }
360
+ return fields;
361
+ }
362
+ compileInsert() {
363
+ if (!this.options.data) {
364
+ throw new Error('No data provided');
365
+ }
366
+ this.parts.push('insert');
367
+ this.addHintComment();
368
+ this.parts.push(`into ${this.getTableName()}`);
369
+ if (Object.keys(this.options.data).length === 0) {
370
+ this.addOutputClause('inserted');
371
+ this.parts.push('default values');
372
+ return;
373
+ }
374
+ const parts = this.processInsertData();
375
+ this.parts.push(parts.join(', '));
376
+ }
377
+ addOutputClause(type) {
378
+ if (this.options.returning && this.platform.usesOutputStatement()) {
379
+ const fields = this.options.returning.map(field => `${type}.${this.quote(field)}`);
380
+ this.parts.push(`output ${fields.join(', ')}`);
381
+ }
382
+ }
383
+ processInsertData() {
384
+ const dataAsArray = Utils.asArray(this.options.data);
385
+ const keys = Object.keys(dataAsArray[0]);
386
+ const values = keys.map(() => '?');
387
+ const parts = [];
388
+ this.parts.push(`(${keys.map(key => this.quote(key)).join(', ')})`);
389
+ this.addOutputClause('inserted');
390
+ this.parts.push('values');
391
+ for (const data of dataAsArray) {
392
+ for (const key of keys) {
393
+ if (typeof data[key] === 'undefined') {
394
+ this.params.push(this.platform.usesDefaultKeyword() ? raw('default') : null);
395
+ } else {
396
+ this.params.push(data[key]);
397
+ }
398
+ }
399
+ parts.push(`(${values.join(', ')})`);
400
+ }
401
+ return parts;
402
+ }
403
+ compileUpdate() {
404
+ if (!this.options.data || Object.keys(this.options.data).length === 0) {
405
+ throw new Error('No data provided');
406
+ }
407
+ this.parts.push('update');
408
+ this.addHintComment();
409
+ this.parts.push(this.getTableName());
410
+ if (this.options.joins) {
411
+ for (const join of this.options.joins) {
412
+ this.parts.push(join.sql);
413
+ this.params.push(...join.params);
414
+ }
415
+ }
416
+ this.parts.push('set');
417
+ if (this.options.data) {
418
+ const parts = [];
419
+ for (const key of Object.keys(this.options.data)) {
420
+ parts.push(`${this.quote(key)} = ?`);
421
+ this.params.push(this.options.data[key]);
422
+ }
423
+ this.parts.push(parts.join(', '));
424
+ }
425
+ this.addOutputClause('inserted');
426
+ if (this.options.where?.sql.trim()) {
427
+ this.parts.push(`where ${this.options.where.sql}`);
428
+ this.params.push(...this.options.where.params);
429
+ }
430
+ }
431
+ compileDelete() {
432
+ this.parts.push('delete');
433
+ this.addHintComment();
434
+ this.parts.push(`from ${this.getTableName()}`);
435
+ this.addOutputClause('deleted');
436
+ if (this.options.where?.sql.trim()) {
437
+ this.parts.push(`where ${this.options.where.sql}`);
438
+ this.params.push(...this.options.where.params);
439
+ }
440
+ }
441
+ compileTruncate() {
442
+ const sql = `truncate table ${this.getTableName()}`;
443
+ this.parts.push(sql);
444
+ }
445
+ addHintComment() {
446
+ if (this.options.hintComment) {
447
+ this.parts.push(`/*+ ${this.options.hintComment.join(' ')} */`);
448
+ }
449
+ }
450
+ compileCtes() {
451
+ const ctes = this.options.ctes;
452
+ if (!ctes || ctes.length === 0) {
453
+ return;
454
+ }
455
+ const hasRecursive = ctes.some(cte => cte.recursive);
456
+ const keyword = this.getCteKeyword(hasRecursive);
457
+ const cteParts = [];
458
+ for (const cte of ctes) {
459
+ let part = this.quote(cte.name);
460
+ if (cte.columns?.length) {
461
+ part += ` (${cte.columns.map(c => this.quote(c)).join(', ')})`;
462
+ }
463
+ part += ' as';
464
+ if (cte.materialized === true) {
465
+ part += ' materialized';
466
+ } else if (cte.materialized === false) {
467
+ part += ' not materialized';
468
+ }
469
+ part += ` (${cte.sql})`;
470
+ this.params.push(...cte.params);
471
+ cteParts.push(part);
472
+ }
473
+ this.parts.push(`${keyword} ${cteParts.join(', ')}`);
474
+ }
475
+ getCteKeyword(hasRecursive) {
476
+ return hasRecursive ? 'with recursive' : 'with';
477
+ }
478
+ getTableName() {
479
+ if (!this.options.tableName) {
480
+ throw new Error('No table name provided');
481
+ }
482
+ const indexHint = this.options.indexHint ? ' ' + this.options.indexHint : '';
483
+ if (isRaw(this.options.tableName)) {
484
+ this.params.push(...this.options.tableName.params);
485
+ return this.options.tableName.sql + indexHint;
486
+ }
487
+ return this.options.tableName + indexHint;
488
+ }
489
+ quote(id) {
490
+ if (isRaw(id)) {
491
+ return this.platform.formatQuery(id.sql, id.params);
492
+ }
493
+ if (id instanceof NativeQueryBuilder) {
494
+ const { sql, params } = id.compile();
495
+ return this.platform.formatQuery(sql, params);
496
+ }
497
+ if (id.endsWith('.*')) {
498
+ const schema = this.platform.quoteIdentifier(id.substring(0, id.indexOf('.')));
499
+ return schema + '.*';
500
+ }
501
+ if (id.toLowerCase().includes(' as ')) {
502
+ const parts = id.split(/ as /i);
503
+ const a = this.platform.quoteIdentifier(parts[0]);
504
+ const b = this.platform.quoteIdentifier(parts[1]);
505
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
506
+ return `${a}${asKeyword}${b}`;
507
+ }
508
+ if (id === '*') {
509
+ return id;
510
+ }
511
+ return this.platform.quoteIdentifier(id);
512
+ }
507
513
  }