@mikro-orm/knex 7.0.0-dev.1 → 7.0.0-dev.11
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.
- package/AbstractSqlConnection.d.ts +2 -2
- package/AbstractSqlConnection.js +33 -31
- package/AbstractSqlDriver.d.ts +14 -12
- package/AbstractSqlDriver.js +198 -186
- package/AbstractSqlPlatform.d.ts +4 -4
- package/AbstractSqlPlatform.js +17 -21
- package/PivotCollectionPersister.d.ts +1 -1
- package/PivotCollectionPersister.js +5 -8
- package/SqlEntityManager.d.ts +4 -3
- package/SqlEntityManager.js +2 -6
- package/SqlEntityRepository.d.ts +2 -2
- package/SqlEntityRepository.js +2 -6
- package/dialects/index.d.ts +4 -4
- package/dialects/index.js +4 -20
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +29 -29
- package/dialects/mssql/index.d.ts +1 -1
- package/dialects/mssql/index.js +1 -17
- package/dialects/mysql/MySqlExceptionConverter.js +16 -19
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mysql/MySqlNativeQueryBuilder.js +13 -17
- package/dialects/mysql/MySqlPlatform.d.ts +5 -5
- package/dialects/mysql/MySqlPlatform.js +16 -20
- package/dialects/mysql/MySqlSchemaHelper.d.ts +5 -5
- package/dialects/mysql/MySqlSchemaHelper.js +8 -12
- package/dialects/mysql/index.d.ts +4 -4
- package/dialects/mysql/index.js +4 -20
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +2 -6
- package/dialects/postgresql/index.d.ts +1 -1
- package/dialects/postgresql/index.js +1 -17
- package/dialects/sqlite/BaseSqliteConnection.d.ts +2 -2
- package/dialects/sqlite/BaseSqliteConnection.js +14 -12
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +4 -5
- package/dialects/sqlite/BaseSqlitePlatform.js +11 -19
- package/dialects/sqlite/SqliteExceptionConverter.js +16 -19
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +1 -1
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +2 -6
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +5 -5
- package/dialects/sqlite/SqliteSchemaHelper.js +22 -26
- package/dialects/sqlite/index.d.ts +5 -5
- package/dialects/sqlite/index.js +5 -21
- package/index.d.ts +11 -11
- package/index.js +13 -34
- package/package.json +7 -16
- package/query/ArrayCriteriaNode.d.ts +2 -2
- package/query/ArrayCriteriaNode.js +2 -6
- package/query/CriteriaNode.d.ts +1 -1
- package/query/CriteriaNode.js +25 -33
- package/query/CriteriaNodeFactory.d.ts +1 -1
- package/query/CriteriaNodeFactory.js +17 -21
- package/query/NativeQueryBuilder.d.ts +2 -2
- package/query/NativeQueryBuilder.js +33 -37
- package/query/ObjectCriteriaNode.d.ts +2 -2
- package/query/ObjectCriteriaNode.js +43 -43
- package/query/QueryBuilder.d.ts +17 -15
- package/query/QueryBuilder.js +204 -193
- package/query/QueryBuilderHelper.d.ts +4 -4
- package/query/QueryBuilderHelper.js +86 -96
- package/query/ScalarCriteriaNode.d.ts +2 -2
- package/query/ScalarCriteriaNode.js +12 -16
- package/query/enums.js +4 -7
- package/query/index.d.ts +9 -9
- package/query/index.js +9 -25
- package/schema/DatabaseSchema.d.ts +3 -3
- package/schema/DatabaseSchema.js +7 -11
- package/schema/DatabaseTable.d.ts +3 -3
- package/schema/DatabaseTable.js +44 -33
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +15 -19
- package/schema/SchemaHelper.d.ts +5 -5
- package/schema/SchemaHelper.js +22 -26
- package/schema/SqlSchemaGenerator.d.ts +4 -4
- package/schema/SqlSchemaGenerator.js +23 -36
- package/schema/index.d.ts +5 -5
- package/schema/index.js +5 -21
- package/typings.d.ts +7 -4
- package/typings.js +1 -2
- package/index.mjs +0 -232
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery, RawQueryFragment } from '@mikro-orm/core';
|
|
2
|
-
import { JoinType, QueryType } from './enums';
|
|
3
|
-
import type { Field, JoinOptions } from '../typings';
|
|
4
|
-
import type { AbstractSqlDriver } from '../AbstractSqlDriver';
|
|
5
|
-
import { NativeQueryBuilder } from './NativeQueryBuilder';
|
|
2
|
+
import { JoinType, QueryType } from './enums.js';
|
|
3
|
+
import type { Field, JoinOptions } from '../typings.js';
|
|
4
|
+
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
|
|
5
|
+
import { NativeQueryBuilder } from './NativeQueryBuilder.js';
|
|
6
6
|
/**
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const core_1 = require("@mikro-orm/core");
|
|
6
|
-
const enums_1 = require("./enums");
|
|
7
|
-
const NativeQueryBuilder_1 = require("./NativeQueryBuilder");
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
import { ALIAS_REPLACEMENT, ALIAS_REPLACEMENT_RE, ArrayType, isRaw, LockMode, OptimisticLockError, QueryOperator, QueryOrderNumeric, raw, RawQueryFragment, ReferenceKind, Utils, } from '@mikro-orm/core';
|
|
3
|
+
import { JoinType, QueryType } from './enums.js';
|
|
4
|
+
import { NativeQueryBuilder } from './NativeQueryBuilder.js';
|
|
8
5
|
/**
|
|
9
6
|
* @internal
|
|
10
7
|
*/
|
|
11
|
-
class QueryBuilderHelper {
|
|
8
|
+
export class QueryBuilderHelper {
|
|
12
9
|
entityName;
|
|
13
10
|
alias;
|
|
14
11
|
aliasMap;
|
|
@@ -25,16 +22,16 @@ class QueryBuilderHelper {
|
|
|
25
22
|
this.platform = this.driver.getPlatform();
|
|
26
23
|
this.metadata = this.driver.getMetadata();
|
|
27
24
|
}
|
|
28
|
-
mapper(field, type =
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
25
|
+
mapper(field, type = QueryType.SELECT, value, alias) {
|
|
26
|
+
if (isRaw(field)) {
|
|
27
|
+
return raw(field.sql, field.params);
|
|
31
28
|
}
|
|
32
|
-
/*
|
|
29
|
+
/* v8 ignore next 3 */
|
|
33
30
|
if (typeof field !== 'string') {
|
|
34
31
|
return field;
|
|
35
32
|
}
|
|
36
33
|
const isTableNameAliasRequired = this.isTableNameAliasRequired(type);
|
|
37
|
-
const fields =
|
|
34
|
+
const fields = Utils.splitPrimaryKeys(field);
|
|
38
35
|
if (fields.length > 1) {
|
|
39
36
|
const parts = [];
|
|
40
37
|
for (const p of fields) {
|
|
@@ -42,9 +39,6 @@ class QueryBuilderHelper {
|
|
|
42
39
|
const prop = this.getProperty(f, a);
|
|
43
40
|
const fkIdx2 = prop?.fieldNames.findIndex(name => name === f) ?? -1;
|
|
44
41
|
if (fkIdx2 !== -1) {
|
|
45
|
-
if (prop?.ownColumns && !prop.ownColumns.includes(f)) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
42
|
parts.push(this.mapper(a !== this.alias ? `${a}.${prop.fieldNames[fkIdx2]}` : prop.fieldNames[fkIdx2], type, value, alias));
|
|
49
43
|
}
|
|
50
44
|
else if (prop) {
|
|
@@ -59,18 +53,15 @@ class QueryBuilderHelper {
|
|
|
59
53
|
if (fields.length !== parts.length && Array.isArray(value)) {
|
|
60
54
|
value.forEach(row => {
|
|
61
55
|
if (Array.isArray(row)) {
|
|
62
|
-
const tmp =
|
|
56
|
+
const tmp = Utils.flatten(row);
|
|
63
57
|
row.length = 0;
|
|
64
58
|
row.push(...tmp);
|
|
65
59
|
}
|
|
66
60
|
});
|
|
67
61
|
}
|
|
68
|
-
|
|
69
|
-
return parts[0];
|
|
70
|
-
}
|
|
71
|
-
return (0, core_1.raw)('(' + parts.map(part => this.platform.quoteIdentifier(part)).join(', ') + ')');
|
|
62
|
+
return raw('(' + parts.map(part => this.platform.quoteIdentifier(part)).join(', ') + ')');
|
|
72
63
|
}
|
|
73
|
-
const rawField =
|
|
64
|
+
const rawField = RawQueryFragment.getKnownFragment(field);
|
|
74
65
|
if (rawField) {
|
|
75
66
|
return rawField;
|
|
76
67
|
}
|
|
@@ -89,7 +80,7 @@ class QueryBuilderHelper {
|
|
|
89
80
|
}
|
|
90
81
|
const noPrefix = prop && prop.persist === false;
|
|
91
82
|
if (prop?.fieldNameRaw) {
|
|
92
|
-
return
|
|
83
|
+
return raw(this.prefix(field, isTableNameAliasRequired));
|
|
93
84
|
}
|
|
94
85
|
if (prop?.formula) {
|
|
95
86
|
const alias2 = this.platform.quoteIdentifier(a).toString();
|
|
@@ -99,9 +90,9 @@ class QueryBuilderHelper {
|
|
|
99
90
|
if (!this.isTableNameAliasRequired(type)) {
|
|
100
91
|
value = value.replaceAll(alias2 + '.', '');
|
|
101
92
|
}
|
|
102
|
-
return
|
|
93
|
+
return raw(`${value}${as}`);
|
|
103
94
|
}
|
|
104
|
-
if (prop?.hasConvertToJSValueSQL && type !==
|
|
95
|
+
if (prop?.hasConvertToJSValueSQL && type !== QueryType.UPSERT) {
|
|
105
96
|
let valueSQL;
|
|
106
97
|
if (prop.fieldNames.length > 1 && fkIdx !== -1) {
|
|
107
98
|
const fk = prop.targetMeta.getPrimaryProps()[fkIdx];
|
|
@@ -113,9 +104,9 @@ class QueryBuilderHelper {
|
|
|
113
104
|
valueSQL = prop.customType.convertToJSValueSQL(prefixed, this.platform);
|
|
114
105
|
}
|
|
115
106
|
if (alias === null) {
|
|
116
|
-
return
|
|
107
|
+
return raw(valueSQL);
|
|
117
108
|
}
|
|
118
|
-
return
|
|
109
|
+
return raw(`${valueSQL} as ${this.platform.quoteIdentifier(alias ?? prop.fieldNames[fkIdx])}`);
|
|
119
110
|
}
|
|
120
111
|
// do not wrap custom expressions
|
|
121
112
|
if (!rawField) {
|
|
@@ -135,9 +126,9 @@ class QueryBuilderHelper {
|
|
|
135
126
|
}
|
|
136
127
|
const meta = this.metadata.find(this.entityName);
|
|
137
128
|
data = this.driver.mapDataToFieldNames(data, true, meta?.properties, convertCustomTypes);
|
|
138
|
-
if (!
|
|
139
|
-
/*
|
|
140
|
-
data[meta.getPrimaryProps()[0].fieldNames[0]] = this.platform.usesDefaultKeyword() ?
|
|
129
|
+
if (!Utils.hasObjectKeys(data) && meta && multi) {
|
|
130
|
+
/* v8 ignore next */
|
|
131
|
+
data[meta.getPrimaryProps()[0].fieldNames[0]] = this.platform.usesDefaultKeyword() ? raw('default') : undefined;
|
|
141
132
|
}
|
|
142
133
|
return data;
|
|
143
134
|
}
|
|
@@ -148,7 +139,7 @@ class QueryBuilderHelper {
|
|
|
148
139
|
const inverseJoinColumns = prop.referencedColumnNames;
|
|
149
140
|
const primaryKeys = prop.owner ? prop.joinColumns : prop2.referencedColumnNames;
|
|
150
141
|
schema ??= prop.targetMeta?.schema === '*' ? '*' : this.driver.getSchemaName(prop.targetMeta);
|
|
151
|
-
cond =
|
|
142
|
+
cond = Utils.merge(cond, prop.where);
|
|
152
143
|
return {
|
|
153
144
|
prop, type, cond, ownerAlias, alias, table, schema,
|
|
154
145
|
joinColumns, inverseJoinColumns, primaryKeys,
|
|
@@ -179,7 +170,7 @@ class QueryBuilderHelper {
|
|
|
179
170
|
path: path.endsWith('[pivot]') ? path : `${path}[pivot]`,
|
|
180
171
|
},
|
|
181
172
|
};
|
|
182
|
-
if (type ===
|
|
173
|
+
if (type === JoinType.pivotJoin) {
|
|
183
174
|
return ret;
|
|
184
175
|
}
|
|
185
176
|
const prop2 = prop.owner ? pivotMeta.relations[1] : pivotMeta.relations[0];
|
|
@@ -191,7 +182,7 @@ class QueryBuilderHelper {
|
|
|
191
182
|
}
|
|
192
183
|
processJoins(qb, joins, schema) {
|
|
193
184
|
Object.values(joins).forEach(join => {
|
|
194
|
-
if ([
|
|
185
|
+
if ([JoinType.nestedInnerJoin, JoinType.nestedLeftJoin].includes(join.type)) {
|
|
195
186
|
return;
|
|
196
187
|
}
|
|
197
188
|
const { sql, params } = this.createJoinExpression(join, joins, schema);
|
|
@@ -201,9 +192,9 @@ class QueryBuilderHelper {
|
|
|
201
192
|
createJoinExpression(join, joins, schema) {
|
|
202
193
|
let table = join.table;
|
|
203
194
|
const method = {
|
|
204
|
-
[
|
|
205
|
-
[
|
|
206
|
-
[
|
|
195
|
+
[JoinType.nestedInnerJoin]: 'inner join',
|
|
196
|
+
[JoinType.nestedLeftJoin]: 'left join',
|
|
197
|
+
[JoinType.pivotJoin]: 'left join',
|
|
207
198
|
}[join.type] ?? join.type;
|
|
208
199
|
const conditions = [];
|
|
209
200
|
const params = [];
|
|
@@ -221,7 +212,7 @@ class QueryBuilderHelper {
|
|
|
221
212
|
return;
|
|
222
213
|
}
|
|
223
214
|
const left = join.prop.object && join.prop.fieldNameRaw
|
|
224
|
-
? join.prop.fieldNameRaw.replaceAll(
|
|
215
|
+
? join.prop.fieldNameRaw.replaceAll(ALIAS_REPLACEMENT, join.ownerAlias)
|
|
225
216
|
: this.platform.quoteIdentifier(`${join.ownerAlias}.${primaryKey}`);
|
|
226
217
|
conditions.push(`${left} = ${this.platform.quoteIdentifier(right)}`);
|
|
227
218
|
});
|
|
@@ -249,7 +240,7 @@ class QueryBuilderHelper {
|
|
|
249
240
|
}
|
|
250
241
|
const oldAlias = this.alias;
|
|
251
242
|
this.alias = join.alias;
|
|
252
|
-
const subquery = this._appendQueryCondition(
|
|
243
|
+
const subquery = this._appendQueryCondition(QueryType.SELECT, join.cond);
|
|
253
244
|
this.alias = oldAlias;
|
|
254
245
|
if (subquery.sql) {
|
|
255
246
|
conditions.push(subquery.sql);
|
|
@@ -261,7 +252,7 @@ class QueryBuilderHelper {
|
|
|
261
252
|
return { sql, params };
|
|
262
253
|
}
|
|
263
254
|
mapJoinColumns(type, join) {
|
|
264
|
-
if (join.prop && [
|
|
255
|
+
if (join.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(join.prop.kind)) {
|
|
265
256
|
return join.prop.fieldNames.map((_fieldName, idx) => {
|
|
266
257
|
const columns = join.prop.owner ? join.joinColumns : join.inverseJoinColumns;
|
|
267
258
|
return this.mapper(`${join.alias}.${columns[idx]}`, type, undefined, `${join.alias}__${columns[idx]}`);
|
|
@@ -275,7 +266,7 @@ class QueryBuilderHelper {
|
|
|
275
266
|
isOneToOneInverse(field, meta) {
|
|
276
267
|
meta ??= this.metadata.find(this.entityName);
|
|
277
268
|
const prop = meta.properties[field.replace(/:ref$/, '')];
|
|
278
|
-
return prop && prop.kind ===
|
|
269
|
+
return prop && prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
279
270
|
}
|
|
280
271
|
getTableName(entityName) {
|
|
281
272
|
const meta = this.metadata.find(entityName);
|
|
@@ -316,11 +307,11 @@ class QueryBuilderHelper {
|
|
|
316
307
|
onConflict.forEach(item => {
|
|
317
308
|
const { fields, ignore } = item;
|
|
318
309
|
const sub = qb.onConflict({ fields, ignore });
|
|
319
|
-
|
|
310
|
+
Utils.runIfNotEmpty(() => {
|
|
320
311
|
let mergeParam = item.merge;
|
|
321
|
-
if (
|
|
312
|
+
if (Utils.isObject(item.merge)) {
|
|
322
313
|
mergeParam = {};
|
|
323
|
-
|
|
314
|
+
Utils.keys(item.merge).forEach(key => {
|
|
324
315
|
const k = this.mapper(key, type);
|
|
325
316
|
mergeParam[k] = item.merge[key];
|
|
326
317
|
});
|
|
@@ -372,20 +363,20 @@ class QueryBuilderHelper {
|
|
|
372
363
|
appendQuerySubCondition(type, cond, key) {
|
|
373
364
|
const parts = [];
|
|
374
365
|
const params = [];
|
|
375
|
-
const fields =
|
|
366
|
+
const fields = Utils.splitPrimaryKeys(key);
|
|
376
367
|
if (this.isSimpleRegExp(cond[key])) {
|
|
377
368
|
parts.push(`${this.platform.quoteIdentifier(this.mapper(key, type))} like ?`);
|
|
378
369
|
params.push(this.getRegExpParam(cond[key]));
|
|
379
370
|
return { sql: parts.join(' and '), params };
|
|
380
371
|
}
|
|
381
|
-
if (
|
|
372
|
+
if (Utils.isPlainObject(cond[key]) || cond[key] instanceof RegExp) {
|
|
382
373
|
return this.processObjectSubCondition(cond, key, type);
|
|
383
374
|
}
|
|
384
375
|
const op = cond[key] === null ? 'is' : '=';
|
|
385
|
-
const raw =
|
|
376
|
+
const raw = RawQueryFragment.getKnownFragment(key);
|
|
386
377
|
if (raw) {
|
|
387
|
-
const sql = raw.sql.replaceAll(
|
|
388
|
-
const value =
|
|
378
|
+
const sql = raw.sql.replaceAll(ALIAS_REPLACEMENT, this.alias);
|
|
379
|
+
const value = Utils.asArray(cond[key]);
|
|
389
380
|
params.push(...raw.params);
|
|
390
381
|
if (value.length > 0) {
|
|
391
382
|
const val = this.getValueReplacement(fields, value[0], params, key);
|
|
@@ -408,13 +399,13 @@ class QueryBuilderHelper {
|
|
|
408
399
|
const parts = [];
|
|
409
400
|
const params = [];
|
|
410
401
|
let value = cond[key];
|
|
411
|
-
const size =
|
|
412
|
-
if (
|
|
402
|
+
const size = Utils.getObjectKeysSize(value);
|
|
403
|
+
if (Utils.isPlainObject(value) && size === 0) {
|
|
413
404
|
return { sql: '', params };
|
|
414
405
|
}
|
|
415
406
|
// grouped condition for one field, e.g. `{ age: { $gte: 10, $lt: 50 } }`
|
|
416
407
|
if (size > 1) {
|
|
417
|
-
const rawField =
|
|
408
|
+
const rawField = RawQueryFragment.getKnownFragment(key);
|
|
418
409
|
const subCondition = Object.entries(value).map(([subKey, subValue]) => {
|
|
419
410
|
key = rawField?.clone().toString() ?? key;
|
|
420
411
|
return ({ [key]: { [subKey]: subValue } });
|
|
@@ -428,13 +419,13 @@ class QueryBuilderHelper {
|
|
|
428
419
|
value = this.platform.getRegExpValue(value);
|
|
429
420
|
}
|
|
430
421
|
// operators
|
|
431
|
-
const op = Object.keys(
|
|
432
|
-
/*
|
|
422
|
+
const op = Object.keys(QueryOperator).find(op => op in value);
|
|
423
|
+
/* v8 ignore next 3 */
|
|
433
424
|
if (!op) {
|
|
434
|
-
throw new Error(`Invalid query condition: ${
|
|
425
|
+
throw new Error(`Invalid query condition: ${inspect(cond, { depth: 5 })}`);
|
|
435
426
|
}
|
|
436
427
|
const replacement = this.getOperatorReplacement(op, value);
|
|
437
|
-
const fields =
|
|
428
|
+
const fields = Utils.splitPrimaryKeys(key);
|
|
438
429
|
if (fields.length > 1 && Array.isArray(value[op])) {
|
|
439
430
|
const singleTuple = !value[op].every((v) => Array.isArray(v));
|
|
440
431
|
if (!this.platform.allowsComparingTuples()) {
|
|
@@ -444,17 +435,17 @@ class QueryBuilderHelper {
|
|
|
444
435
|
return `(${mapped.map(field => `${this.platform.quoteIdentifier(field)} = ?`).join(' and ')})`;
|
|
445
436
|
});
|
|
446
437
|
parts.push(`(${conds.join(' or ')})`);
|
|
447
|
-
params.push(...
|
|
438
|
+
params.push(...Utils.flatten(value[op]));
|
|
448
439
|
return { sql: parts.join(' and '), params };
|
|
449
440
|
}
|
|
450
441
|
parts.push(...mapped.map(field => `${this.platform.quoteIdentifier(field)} = ?`));
|
|
451
|
-
params.push(...
|
|
442
|
+
params.push(...Utils.flatten(value[op]));
|
|
452
443
|
return { sql: parts.join(' and '), params };
|
|
453
444
|
}
|
|
454
445
|
if (singleTuple) {
|
|
455
|
-
const tmp = value[op].length === 1 &&
|
|
446
|
+
const tmp = value[op].length === 1 && Utils.isPlainObject(value[op][0]) ? fields.map(f => value[op][0][f]) : value[op];
|
|
456
447
|
const sql = `(${fields.map(() => '?').join(', ')})`;
|
|
457
|
-
value[op] =
|
|
448
|
+
value[op] = raw(sql, tmp);
|
|
458
449
|
}
|
|
459
450
|
}
|
|
460
451
|
if (this.subQueries[key]) {
|
|
@@ -465,22 +456,22 @@ class QueryBuilderHelper {
|
|
|
465
456
|
const [a, f] = this.splitField(key);
|
|
466
457
|
const prop = this.getProperty(f, a);
|
|
467
458
|
if (op === '$fulltext') {
|
|
468
|
-
/*
|
|
459
|
+
/* v8 ignore next 3 */
|
|
469
460
|
if (!prop) {
|
|
470
461
|
throw new Error(`Cannot use $fulltext operator on ${key}, property not found`);
|
|
471
462
|
}
|
|
472
|
-
const { sql, params: params2 } =
|
|
463
|
+
const { sql, params: params2 } = raw(this.platform.getFullTextWhereClause(prop), {
|
|
473
464
|
column: this.mapper(key, type, undefined, null),
|
|
474
465
|
query: value[op],
|
|
475
466
|
});
|
|
476
467
|
parts.push(sql);
|
|
477
468
|
params.push(...params2);
|
|
478
469
|
}
|
|
479
|
-
else if (
|
|
480
|
-
parts.push(`1 = 0`);
|
|
470
|
+
else if (['$in', '$nin'].includes(op) && Array.isArray(value[op]) && value[op].length === 0) {
|
|
471
|
+
parts.push(`1 = ${op === '$in' ? 0 : 1}`);
|
|
481
472
|
}
|
|
482
|
-
else if (value[op] instanceof
|
|
483
|
-
const query = value[op] instanceof
|
|
473
|
+
else if (value[op] instanceof RawQueryFragment || value[op] instanceof NativeQueryBuilder) {
|
|
474
|
+
const query = value[op] instanceof NativeQueryBuilder ? value[op].toRaw() : value[op];
|
|
484
475
|
const mappedKey = this.mapper(key, type, query, null);
|
|
485
476
|
let sql = query.sql;
|
|
486
477
|
if (['$in', '$nin'].includes(op)) {
|
|
@@ -506,7 +497,7 @@ class QueryBuilderHelper {
|
|
|
506
497
|
}
|
|
507
498
|
return `(${tmp.join(', ')})`;
|
|
508
499
|
}
|
|
509
|
-
if (prop?.customType instanceof
|
|
500
|
+
if (prop?.customType instanceof ArrayType) {
|
|
510
501
|
const item = prop.customType.convertToDatabaseValue(value, this.platform, { fromQuery: true, key, mode: 'query' });
|
|
511
502
|
params.push(item);
|
|
512
503
|
}
|
|
@@ -522,7 +513,7 @@ class QueryBuilderHelper {
|
|
|
522
513
|
return '?';
|
|
523
514
|
}
|
|
524
515
|
getOperatorReplacement(op, value) {
|
|
525
|
-
let replacement =
|
|
516
|
+
let replacement = QueryOperator[op];
|
|
526
517
|
if (op === '$exists') {
|
|
527
518
|
replacement = value[op] ? 'is not' : 'is';
|
|
528
519
|
value[op] = null;
|
|
@@ -548,26 +539,26 @@ class QueryBuilderHelper {
|
|
|
548
539
|
const ret = [];
|
|
549
540
|
for (const key of Object.keys(orderBy)) {
|
|
550
541
|
const direction = orderBy[key];
|
|
551
|
-
const order =
|
|
552
|
-
const raw =
|
|
542
|
+
const order = Utils.isNumber(direction) ? QueryOrderNumeric[direction] : direction;
|
|
543
|
+
const raw = RawQueryFragment.getKnownFragment(key);
|
|
553
544
|
if (raw) {
|
|
554
545
|
ret.push(...this.platform.getOrderByExpression(this.platform.formatQuery(raw.sql, raw.params), order));
|
|
555
546
|
continue;
|
|
556
547
|
}
|
|
557
|
-
for (const f of
|
|
548
|
+
for (const f of Utils.splitPrimaryKeys(key)) {
|
|
558
549
|
// eslint-disable-next-line prefer-const
|
|
559
550
|
let [alias, field] = this.splitField(f, true);
|
|
560
551
|
alias = populate[alias] || alias;
|
|
561
552
|
const prop = this.getProperty(field, alias);
|
|
562
|
-
const noPrefix = (prop && prop.persist === false && !prop.formula && !prop.embedded) ||
|
|
553
|
+
const noPrefix = (prop && prop.persist === false && !prop.formula && !prop.embedded) || RawQueryFragment.isKnownFragment(f);
|
|
563
554
|
const column = this.mapper(noPrefix ? field : `${alias}.${field}`, type, undefined, null);
|
|
564
|
-
/*
|
|
565
|
-
const rawColumn =
|
|
555
|
+
/* v8 ignore next */
|
|
556
|
+
const rawColumn = Utils.isString(column) ? column.split('.').map(e => this.platform.quoteIdentifier(e)).join('.') : column;
|
|
566
557
|
const customOrder = prop?.customOrder;
|
|
567
558
|
let colPart = customOrder
|
|
568
559
|
? this.platform.generateCustomOrder(rawColumn, customOrder)
|
|
569
560
|
: rawColumn;
|
|
570
|
-
if (
|
|
561
|
+
if (isRaw(colPart)) {
|
|
571
562
|
colPart = this.platform.formatQuery(colPart.sql, colPart.params);
|
|
572
563
|
}
|
|
573
564
|
if (Array.isArray(order)) {
|
|
@@ -590,23 +581,23 @@ class QueryBuilderHelper {
|
|
|
590
581
|
qb.returning(returning.map(field => this.mapper(field, type)));
|
|
591
582
|
return;
|
|
592
583
|
}
|
|
593
|
-
if (type ===
|
|
584
|
+
if (type === QueryType.INSERT) {
|
|
594
585
|
const returningProps = meta.hydrateProps
|
|
595
586
|
.filter(prop => prop.returning || (prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw)))
|
|
596
587
|
.filter(prop => !(prop.name in data));
|
|
597
588
|
if (returningProps.length > 0) {
|
|
598
|
-
qb.returning(
|
|
589
|
+
qb.returning(Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
599
590
|
}
|
|
600
591
|
return;
|
|
601
592
|
}
|
|
602
|
-
if (type ===
|
|
603
|
-
const returningProps = meta.hydrateProps.filter(prop => prop.fieldNames &&
|
|
593
|
+
if (type === QueryType.UPDATE) {
|
|
594
|
+
const returningProps = meta.hydrateProps.filter(prop => prop.fieldNames && isRaw(data[prop.fieldNames[0]]));
|
|
604
595
|
if (returningProps.length > 0) {
|
|
605
596
|
qb.returning(returningProps.flatMap(prop => {
|
|
606
597
|
if (prop.hasConvertToJSValueSQL) {
|
|
607
598
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
608
599
|
const sql = prop.customType.convertToJSValueSQL(aliased, this.platform) + ' as ' + this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
609
|
-
return [
|
|
600
|
+
return [raw(sql)];
|
|
610
601
|
}
|
|
611
602
|
return prop.fieldNames;
|
|
612
603
|
}));
|
|
@@ -633,8 +624,8 @@ class QueryBuilderHelper {
|
|
|
633
624
|
}
|
|
634
625
|
getLockSQL(qb, lockMode, lockTables = []) {
|
|
635
626
|
const meta = this.metadata.find(this.entityName);
|
|
636
|
-
if (lockMode ===
|
|
637
|
-
throw
|
|
627
|
+
if (lockMode === LockMode.OPTIMISTIC && meta && !meta.versionProperty) {
|
|
628
|
+
throw OptimisticLockError.lockFailed(this.entityName);
|
|
638
629
|
}
|
|
639
630
|
qb.lockMode(lockMode, lockTables);
|
|
640
631
|
}
|
|
@@ -648,14 +639,14 @@ class QueryBuilderHelper {
|
|
|
648
639
|
if (versionProperty.runtimeType === 'Date') {
|
|
649
640
|
sql = this.platform.getCurrentTimestampSQL(versionProperty.length);
|
|
650
641
|
}
|
|
651
|
-
qb.update({ [versionProperty.fieldNames[0]]:
|
|
642
|
+
qb.update({ [versionProperty.fieldNames[0]]: raw(sql) });
|
|
652
643
|
}
|
|
653
644
|
prefix(field, always = false, quote = false, idx) {
|
|
654
645
|
let ret;
|
|
655
646
|
if (!this.isPrefixed(field)) {
|
|
656
647
|
const alias = always ? (quote ? this.alias : this.platform.quoteIdentifier(this.alias)) + '.' : '';
|
|
657
648
|
const fieldName = this.fieldName(field, this.alias, always, idx);
|
|
658
|
-
if (fieldName instanceof
|
|
649
|
+
if (fieldName instanceof RawQueryFragment) {
|
|
659
650
|
return fieldName.sql;
|
|
660
651
|
}
|
|
661
652
|
ret = alias + fieldName;
|
|
@@ -664,7 +655,7 @@ class QueryBuilderHelper {
|
|
|
664
655
|
const [a, ...rest] = field.split('.');
|
|
665
656
|
const f = rest.join('.');
|
|
666
657
|
const fieldName = this.fieldName(f, a, always, idx);
|
|
667
|
-
if (fieldName instanceof
|
|
658
|
+
if (fieldName instanceof RawQueryFragment) {
|
|
668
659
|
return fieldName.sql;
|
|
669
660
|
}
|
|
670
661
|
ret = a + '.' + fieldName;
|
|
@@ -688,7 +679,7 @@ class QueryBuilderHelper {
|
|
|
688
679
|
// skip nesting parens if the value is simple = scalar or object without operators or with only single key, being the operator
|
|
689
680
|
const keys = Object.keys(sub);
|
|
690
681
|
const val = sub[keys[0]];
|
|
691
|
-
const simple = !
|
|
682
|
+
const simple = !Utils.isPlainObject(val) || Utils.getObjectKeysSize(val) === 1 || Object.keys(val).every(k => !Utils.isOperator(k));
|
|
692
683
|
if (keys.length === 1 && simple) {
|
|
693
684
|
this.append(() => this._appendQueryCondition(type, sub, operator), parts, params);
|
|
694
685
|
continue;
|
|
@@ -707,17 +698,17 @@ class QueryBuilderHelper {
|
|
|
707
698
|
}
|
|
708
699
|
if (prop.fieldNameRaw) {
|
|
709
700
|
if (!always) {
|
|
710
|
-
return
|
|
711
|
-
.replace(new RegExp(
|
|
701
|
+
return raw(prop.fieldNameRaw
|
|
702
|
+
.replace(new RegExp(ALIAS_REPLACEMENT_RE + '\\.?', 'g'), '')
|
|
712
703
|
.replace(this.platform.quoteIdentifier('') + '.', ''));
|
|
713
704
|
}
|
|
714
705
|
if (alias) {
|
|
715
|
-
return
|
|
706
|
+
return raw(prop.fieldNameRaw.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), alias));
|
|
716
707
|
}
|
|
717
|
-
/*
|
|
718
|
-
return
|
|
708
|
+
/* v8 ignore next */
|
|
709
|
+
return raw(prop.fieldNameRaw);
|
|
719
710
|
}
|
|
720
|
-
/*
|
|
711
|
+
/* v8 ignore next */
|
|
721
712
|
return prop.fieldNames?.[idx] ?? field;
|
|
722
713
|
}
|
|
723
714
|
getProperty(field, alias) {
|
|
@@ -726,7 +717,7 @@ class QueryBuilderHelper {
|
|
|
726
717
|
// check if `alias` is not matching an embedded property name instead of alias, e.g. `address.city`
|
|
727
718
|
if (alias && meta) {
|
|
728
719
|
const prop = meta.properties[alias];
|
|
729
|
-
if (prop?.kind ===
|
|
720
|
+
if (prop?.kind === ReferenceKind.EMBEDDED) {
|
|
730
721
|
// we want to select the full object property so hydration works as expected
|
|
731
722
|
if (prop.object) {
|
|
732
723
|
return prop;
|
|
@@ -745,16 +736,15 @@ class QueryBuilderHelper {
|
|
|
745
736
|
return undefined;
|
|
746
737
|
}
|
|
747
738
|
isTableNameAliasRequired(type) {
|
|
748
|
-
return [
|
|
739
|
+
return [QueryType.SELECT, QueryType.COUNT].includes(type);
|
|
749
740
|
}
|
|
750
741
|
processOnConflictCondition(cond, schema) {
|
|
751
742
|
const meta = this.metadata.get(this.entityName);
|
|
752
743
|
const tableName = meta.tableName;
|
|
753
744
|
for (const key of Object.keys(cond)) {
|
|
754
|
-
const mapped = this.mapper(key,
|
|
755
|
-
|
|
745
|
+
const mapped = this.mapper(key, QueryType.UPSERT);
|
|
746
|
+
Utils.renameKey(cond, key, tableName + '.' + mapped);
|
|
756
747
|
}
|
|
757
748
|
return cond;
|
|
758
749
|
}
|
|
759
750
|
}
|
|
760
|
-
exports.QueryBuilderHelper = QueryBuilderHelper;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CriteriaNode } from './CriteriaNode';
|
|
2
|
-
import type { IQueryBuilder, ICriteriaNodeProcessOptions } from '../typings';
|
|
1
|
+
import { CriteriaNode } from './CriteriaNode.js';
|
|
2
|
+
import type { IQueryBuilder, ICriteriaNodeProcessOptions } from '../typings.js';
|
|
3
3
|
/**
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
@@ -1,32 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const CriteriaNode_1 = require("./CriteriaNode");
|
|
6
|
-
const enums_1 = require("./enums");
|
|
7
|
-
const QueryBuilder_1 = require("./QueryBuilder");
|
|
1
|
+
import { ReferenceKind, Utils } from '@mikro-orm/core';
|
|
2
|
+
import { CriteriaNode } from './CriteriaNode.js';
|
|
3
|
+
import { JoinType } from './enums.js';
|
|
4
|
+
import { QueryBuilder } from './QueryBuilder.js';
|
|
8
5
|
/**
|
|
9
6
|
* @internal
|
|
10
7
|
*/
|
|
11
|
-
class ScalarCriteriaNode extends
|
|
8
|
+
export class ScalarCriteriaNode extends CriteriaNode {
|
|
12
9
|
process(qb, options) {
|
|
13
10
|
if (this.shouldJoin()) {
|
|
14
11
|
const path = this.getPath();
|
|
15
12
|
const parentPath = this.parent.getPath(); // the parent is always there, otherwise `shouldJoin` would return `false`
|
|
16
13
|
const nestedAlias = qb.getAliasForJoinPath(path) || qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
|
|
17
14
|
const field = this.aliased(this.prop.name, options?.alias);
|
|
18
|
-
const type = this.prop.kind ===
|
|
15
|
+
const type = this.prop.kind === ReferenceKind.MANY_TO_MANY ? JoinType.pivotJoin : JoinType.leftJoin;
|
|
19
16
|
qb.join(field, nestedAlias, undefined, type, path);
|
|
20
17
|
// select the owner as virtual property when joining from 1:1 inverse side, but only if the parent is root entity
|
|
21
|
-
if (this.prop.kind ===
|
|
18
|
+
if (this.prop.kind === ReferenceKind.ONE_TO_ONE && !parentPath.includes('.') && !qb._fields?.includes(field)) {
|
|
22
19
|
qb.addSelect(field);
|
|
23
20
|
}
|
|
24
21
|
}
|
|
25
|
-
if (this.payload instanceof
|
|
22
|
+
if (this.payload instanceof QueryBuilder) {
|
|
26
23
|
return this.payload.getNativeQuery().toRaw();
|
|
27
24
|
}
|
|
28
25
|
if (this.payload && typeof this.payload === 'object') {
|
|
29
|
-
const keys = Object.keys(this.payload).filter(key =>
|
|
26
|
+
const keys = Object.keys(this.payload).filter(key => Utils.isArrayOperator(key) && Array.isArray(this.payload[key]));
|
|
30
27
|
for (const key of keys) {
|
|
31
28
|
this.payload[key] = JSON.stringify(this.payload[key]);
|
|
32
29
|
}
|
|
@@ -41,11 +38,10 @@ class ScalarCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
41
38
|
return false;
|
|
42
39
|
}
|
|
43
40
|
switch (this.prop.kind) {
|
|
44
|
-
case
|
|
45
|
-
case
|
|
46
|
-
case
|
|
41
|
+
case ReferenceKind.ONE_TO_MANY: return true;
|
|
42
|
+
case ReferenceKind.MANY_TO_MANY: return true;
|
|
43
|
+
case ReferenceKind.ONE_TO_ONE: return !this.prop.owner;
|
|
47
44
|
default: return false; // SCALAR, MANY_TO_ONE
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
|
-
exports.ScalarCriteriaNode = ScalarCriteriaNode;
|
package/query/enums.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JoinType = exports.QueryType = void 0;
|
|
4
|
-
var QueryType;
|
|
1
|
+
export var QueryType;
|
|
5
2
|
(function (QueryType) {
|
|
6
3
|
QueryType["TRUNCATE"] = "TRUNCATE";
|
|
7
4
|
QueryType["SELECT"] = "SELECT";
|
|
@@ -10,8 +7,8 @@ var QueryType;
|
|
|
10
7
|
QueryType["UPDATE"] = "UPDATE";
|
|
11
8
|
QueryType["DELETE"] = "DELETE";
|
|
12
9
|
QueryType["UPSERT"] = "UPSERT";
|
|
13
|
-
})(QueryType || (
|
|
14
|
-
var JoinType;
|
|
10
|
+
})(QueryType || (QueryType = {}));
|
|
11
|
+
export var JoinType;
|
|
15
12
|
(function (JoinType) {
|
|
16
13
|
JoinType["leftJoin"] = "left join";
|
|
17
14
|
JoinType["innerJoin"] = "inner join";
|
|
@@ -20,4 +17,4 @@ var JoinType;
|
|
|
20
17
|
JoinType["pivotJoin"] = "pivot join";
|
|
21
18
|
JoinType["innerJoinLateral"] = "inner join lateral";
|
|
22
19
|
JoinType["leftJoinLateral"] = "left join lateral";
|
|
23
|
-
})(JoinType || (
|
|
20
|
+
})(JoinType || (JoinType = {}));
|
package/query/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export * from './enums';
|
|
2
|
-
export * from './QueryBuilderHelper';
|
|
3
|
-
export * from './QueryBuilder';
|
|
4
|
-
export * from './CriteriaNode';
|
|
5
|
-
export * from './ArrayCriteriaNode';
|
|
6
|
-
export * from './ObjectCriteriaNode';
|
|
7
|
-
export * from './ScalarCriteriaNode';
|
|
8
|
-
export * from './CriteriaNodeFactory';
|
|
9
|
-
export * from './NativeQueryBuilder';
|
|
1
|
+
export * from './enums.js';
|
|
2
|
+
export * from './QueryBuilderHelper.js';
|
|
3
|
+
export * from './QueryBuilder.js';
|
|
4
|
+
export * from './CriteriaNode.js';
|
|
5
|
+
export * from './ArrayCriteriaNode.js';
|
|
6
|
+
export * from './ObjectCriteriaNode.js';
|
|
7
|
+
export * from './ScalarCriteriaNode.js';
|
|
8
|
+
export * from './CriteriaNodeFactory.js';
|
|
9
|
+
export * from './NativeQueryBuilder.js';
|