@mikro-orm/knex 6.0.0-dev.2 → 6.0.0-dev.200
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/{dist/AbstractSqlConnection.d.ts → AbstractSqlConnection.d.ts} +8 -4
- package/{dist/AbstractSqlConnection.js → AbstractSqlConnection.js} +35 -18
- package/AbstractSqlDriver.d.ts +73 -0
- package/AbstractSqlDriver.js +1085 -0
- package/AbstractSqlPlatform.d.ts +22 -0
- package/{dist/AbstractSqlPlatform.js → AbstractSqlPlatform.js} +46 -19
- package/{dist/MonkeyPatchable.d.ts → MonkeyPatchable.d.ts} +1 -0
- package/{dist/MonkeyPatchable.js → MonkeyPatchable.js} +3 -0
- package/PivotCollectionPersister.d.ts +17 -0
- package/PivotCollectionPersister.js +128 -0
- package/{dist/README.md → README.md} +66 -109
- package/{dist/SqlEntityManager.d.ts → SqlEntityManager.d.ts} +6 -10
- package/{dist/SqlEntityManager.js → SqlEntityManager.js} +5 -10
- package/SqlEntityRepository.d.ts +24 -0
- package/{dist/SqlEntityRepository.js → SqlEntityRepository.js} +11 -8
- package/{dist/index.d.ts → index.d.ts} +1 -0
- package/{dist/index.js → index.js} +6 -1
- package/index.mjs +211 -0
- package/package.json +20 -49
- package/query/ArrayCriteriaNode.d.ts +10 -0
- package/{dist/query → query}/ArrayCriteriaNode.js +7 -2
- package/{dist/query → query}/CriteriaNode.d.ts +11 -9
- package/{dist/query → query}/CriteriaNode.js +31 -15
- package/query/CriteriaNodeFactory.d.ts +12 -0
- package/{dist/query → query}/CriteriaNodeFactory.js +32 -15
- package/query/ObjectCriteriaNode.d.ts +15 -0
- package/{dist/query → query}/ObjectCriteriaNode.js +68 -21
- package/query/QueryBuilder.d.ts +284 -0
- package/query/QueryBuilder.js +1218 -0
- package/{dist/query → query}/QueryBuilderHelper.d.ts +26 -23
- package/query/QueryBuilderHelper.js +661 -0
- package/query/ScalarCriteriaNode.d.ts +10 -0
- package/{dist/query → query}/ScalarCriteriaNode.js +12 -8
- package/query/enums.d.ts +15 -0
- package/query/enums.js +20 -0
- package/{dist/query → query}/index.js +5 -1
- package/{dist/schema → schema}/DatabaseSchema.d.ts +6 -3
- package/{dist/schema → schema}/DatabaseSchema.js +35 -25
- package/{dist/schema → schema}/DatabaseTable.d.ts +21 -13
- package/schema/DatabaseTable.js +645 -0
- package/{dist/schema → schema}/SchemaComparator.d.ts +9 -7
- package/{dist/schema → schema}/SchemaComparator.js +99 -25
- package/{dist/schema → schema}/SchemaHelper.d.ts +20 -13
- package/{dist/schema → schema}/SchemaHelper.js +70 -18
- package/{dist/schema/SchemaGenerator.d.ts → schema/SqlSchemaGenerator.d.ts} +11 -14
- package/{dist/schema/SchemaGenerator.js → schema/SqlSchemaGenerator.js} +149 -63
- package/{dist/schema → schema}/index.d.ts +1 -1
- package/{dist/schema → schema}/index.js +6 -2
- package/{dist/typings.d.ts → typings.d.ts} +45 -22
- package/CHANGELOG.md +0 -661
- package/dist/AbstractSqlDriver.d.ts +0 -55
- package/dist/AbstractSqlDriver.js +0 -644
- package/dist/AbstractSqlPlatform.d.ts +0 -21
- package/dist/LICENSE +0 -21
- package/dist/SqlEntityRepository.d.ts +0 -23
- package/dist/index.mjs +0 -26
- package/dist/package.json +0 -99
- package/dist/query/ArrayCriteriaNode.d.ts +0 -9
- package/dist/query/CriteriaNodeFactory.d.ts +0 -12
- package/dist/query/ObjectCriteriaNode.d.ts +0 -14
- package/dist/query/QueryBuilder.d.ts +0 -211
- package/dist/query/QueryBuilder.js +0 -688
- package/dist/query/QueryBuilderHelper.js +0 -523
- package/dist/query/ScalarCriteriaNode.d.ts +0 -9
- package/dist/query/enums.d.ts +0 -8
- package/dist/query/enums.js +0 -12
- package/dist/schema/DatabaseTable.js +0 -319
- /package/{dist/query → query}/index.d.ts +0 -0
- /package/{dist/typings.js → typings.js} +0 -0
|
@@ -1,523 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QueryBuilderHelper = void 0;
|
|
4
|
-
const util_1 = require("util");
|
|
5
|
-
const core_1 = require("@mikro-orm/core");
|
|
6
|
-
const enums_1 = require("./enums");
|
|
7
|
-
/**
|
|
8
|
-
* @internal
|
|
9
|
-
*/
|
|
10
|
-
class QueryBuilderHelper {
|
|
11
|
-
constructor(entityName, alias, aliasMap, subQueries, metadata, knex, platform) {
|
|
12
|
-
this.entityName = entityName;
|
|
13
|
-
this.alias = alias;
|
|
14
|
-
this.aliasMap = aliasMap;
|
|
15
|
-
this.subQueries = subQueries;
|
|
16
|
-
this.metadata = metadata;
|
|
17
|
-
this.knex = knex;
|
|
18
|
-
this.platform = platform;
|
|
19
|
-
}
|
|
20
|
-
mapper(field, type = enums_1.QueryType.SELECT, value, alias) {
|
|
21
|
-
const isTableNameAliasRequired = this.isTableNameAliasRequired(type);
|
|
22
|
-
const fields = core_1.Utils.splitPrimaryKeys(field);
|
|
23
|
-
if (fields.length > 1) {
|
|
24
|
-
const parts = [];
|
|
25
|
-
for (const p of fields) {
|
|
26
|
-
const [a, f] = this.splitField(p);
|
|
27
|
-
const prop = this.getProperty(f, a);
|
|
28
|
-
if (prop) {
|
|
29
|
-
parts.push(...prop.fieldNames.map(f => this.mapper(f, type, value, alias)));
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
parts.push(this.mapper(`${a}.${f}`, type, value, alias));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return this.knex.raw('(' + parts.map(part => this.knex.ref(part)).join(', ') + ')');
|
|
36
|
-
}
|
|
37
|
-
let ret = field;
|
|
38
|
-
const customExpression = QueryBuilderHelper.isCustomExpression(field, !!alias);
|
|
39
|
-
const [a, f] = this.splitField(field);
|
|
40
|
-
const prop = this.getProperty(f, a);
|
|
41
|
-
const noPrefix = prop && prop.persist === false;
|
|
42
|
-
if (prop?.fieldNameRaw) {
|
|
43
|
-
return this.knex.raw(this.prefix(field, isTableNameAliasRequired));
|
|
44
|
-
}
|
|
45
|
-
if (prop?.formula) {
|
|
46
|
-
const alias2 = this.knex.ref(a).toString();
|
|
47
|
-
const aliased = this.knex.ref(prop.fieldNames[0]).toString();
|
|
48
|
-
const as = alias === null ? '' : ` as ${aliased}`;
|
|
49
|
-
return this.knex.raw(`${prop.formula(alias2)}${as}`);
|
|
50
|
-
}
|
|
51
|
-
if (prop?.customType?.convertToJSValueSQL) {
|
|
52
|
-
const prefixed = this.prefix(field, isTableNameAliasRequired, true);
|
|
53
|
-
const valueSQL = prop.customType.convertToJSValueSQL(prefixed, this.platform);
|
|
54
|
-
if (alias === null) {
|
|
55
|
-
return this.knex.raw(valueSQL);
|
|
56
|
-
}
|
|
57
|
-
return this.knex.raw(`${valueSQL} as ${this.platform.quoteIdentifier(alias ?? prop.fieldNames[0])}`);
|
|
58
|
-
}
|
|
59
|
-
// do not wrap custom expressions
|
|
60
|
-
if (!customExpression) {
|
|
61
|
-
ret = this.prefix(field);
|
|
62
|
-
}
|
|
63
|
-
if (alias) {
|
|
64
|
-
ret += ' as ' + alias;
|
|
65
|
-
}
|
|
66
|
-
if (customExpression) {
|
|
67
|
-
return this.knex.raw(ret, value);
|
|
68
|
-
}
|
|
69
|
-
if (!isTableNameAliasRequired || this.isPrefixed(ret) || noPrefix) {
|
|
70
|
-
return ret;
|
|
71
|
-
}
|
|
72
|
-
return this.alias + '.' + ret;
|
|
73
|
-
}
|
|
74
|
-
processData(data, convertCustomTypes, multi = false) {
|
|
75
|
-
if (Array.isArray(data)) {
|
|
76
|
-
return data.map(d => this.processData(d, convertCustomTypes, true));
|
|
77
|
-
}
|
|
78
|
-
data = Object.assign({}, data); // copy first
|
|
79
|
-
const meta = this.metadata.find(this.entityName);
|
|
80
|
-
Object.keys(data).forEach(k => {
|
|
81
|
-
if (!meta?.properties[k]) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const prop = meta.properties[k];
|
|
85
|
-
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
86
|
-
const copy = data[k];
|
|
87
|
-
delete data[k];
|
|
88
|
-
prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (prop.customType && convertCustomTypes && !this.platform.isRaw(data[k])) {
|
|
92
|
-
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, true);
|
|
93
|
-
}
|
|
94
|
-
if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(data[k])) {
|
|
95
|
-
const quoted = this.platform.quoteValue(data[k]);
|
|
96
|
-
data[k] = this.knex.raw(prop.customType.convertToDatabaseValueSQL(quoted, this.platform));
|
|
97
|
-
}
|
|
98
|
-
if (!prop.customType && (Array.isArray(data[k]) || core_1.Utils.isPlainObject(data[k]))) {
|
|
99
|
-
data[k] = JSON.stringify(data[k]);
|
|
100
|
-
}
|
|
101
|
-
if (prop.fieldNames) {
|
|
102
|
-
core_1.Utils.renameKey(data, k, prop.fieldNames[0]);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
if (!core_1.Utils.hasObjectKeys(data) && meta && multi) {
|
|
106
|
-
data[meta.primaryKeys[0]] = this.platform.usesDefaultKeyword() ? this.knex.raw('default') : undefined;
|
|
107
|
-
}
|
|
108
|
-
return data;
|
|
109
|
-
}
|
|
110
|
-
joinOneToReference(prop, ownerAlias, alias, type, cond = {}) {
|
|
111
|
-
const meta = this.metadata.find(prop.type);
|
|
112
|
-
const prop2 = meta.properties[prop.mappedBy || prop.inversedBy];
|
|
113
|
-
const table = this.getTableName(prop.type);
|
|
114
|
-
const joinColumns = prop.owner ? prop.referencedColumnNames : prop2.joinColumns;
|
|
115
|
-
const inverseJoinColumns = prop.referencedColumnNames;
|
|
116
|
-
const primaryKeys = prop.owner ? prop.joinColumns : prop2.referencedColumnNames;
|
|
117
|
-
return {
|
|
118
|
-
prop, type, cond, ownerAlias, alias, table,
|
|
119
|
-
joinColumns, inverseJoinColumns, primaryKeys,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
joinManyToOneReference(prop, ownerAlias, alias, type, cond = {}) {
|
|
123
|
-
return {
|
|
124
|
-
prop, type, cond, ownerAlias, alias,
|
|
125
|
-
table: this.getTableName(prop.type),
|
|
126
|
-
joinColumns: prop.referencedColumnNames,
|
|
127
|
-
primaryKeys: prop.fieldNames,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
joinManyToManyReference(prop, ownerAlias, alias, pivotAlias, type, cond, path) {
|
|
131
|
-
const ret = {
|
|
132
|
-
[`${ownerAlias}.${prop.name}#${pivotAlias}`]: {
|
|
133
|
-
prop, type, cond, ownerAlias,
|
|
134
|
-
alias: pivotAlias,
|
|
135
|
-
inverseAlias: alias,
|
|
136
|
-
joinColumns: prop.joinColumns,
|
|
137
|
-
inverseJoinColumns: prop.inverseJoinColumns,
|
|
138
|
-
primaryKeys: prop.referencedColumnNames,
|
|
139
|
-
table: prop.pivotTable,
|
|
140
|
-
path: path.endsWith('[pivot]') ? path : `${path}[pivot]`,
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
if (type === 'pivotJoin') {
|
|
144
|
-
return ret;
|
|
145
|
-
}
|
|
146
|
-
const prop2 = this.metadata.find(prop.pivotTable).properties[prop.type + (prop.owner ? '_inverse' : '_owner')];
|
|
147
|
-
ret[`${pivotAlias}.${prop2.name}#${alias}`] = this.joinManyToOneReference(prop2, pivotAlias, alias, type);
|
|
148
|
-
ret[`${pivotAlias}.${prop2.name}#${alias}`].path = path;
|
|
149
|
-
return ret;
|
|
150
|
-
}
|
|
151
|
-
joinPivotTable(field, prop, ownerAlias, alias, type, cond = {}) {
|
|
152
|
-
const pivotMeta = this.metadata.find(field);
|
|
153
|
-
const prop2 = pivotMeta.properties[prop.mappedBy || prop.inversedBy];
|
|
154
|
-
return {
|
|
155
|
-
prop, type, cond, ownerAlias, alias,
|
|
156
|
-
table: pivotMeta.collection,
|
|
157
|
-
schema: pivotMeta.schema,
|
|
158
|
-
joinColumns: prop.joinColumns,
|
|
159
|
-
inverseJoinColumns: prop2.joinColumns,
|
|
160
|
-
primaryKeys: prop.referencedColumnNames,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
processJoins(qb, joins, schema) {
|
|
164
|
-
Object.values(joins).forEach(join => {
|
|
165
|
-
let table = `${join.table} as ${join.alias}`;
|
|
166
|
-
const method = join.type === 'pivotJoin' ? 'leftJoin' : join.type;
|
|
167
|
-
schema = join.schema && join.schema !== '*' ? join.schema : schema;
|
|
168
|
-
if (schema) {
|
|
169
|
-
table = `${schema}.${table}`;
|
|
170
|
-
}
|
|
171
|
-
return qb[method](this.knex.ref(table), inner => {
|
|
172
|
-
join.primaryKeys.forEach((primaryKey, idx) => {
|
|
173
|
-
const left = `${join.ownerAlias}.${primaryKey}`;
|
|
174
|
-
const right = `${join.alias}.${join.joinColumns[idx]}`;
|
|
175
|
-
inner.on(left, right);
|
|
176
|
-
});
|
|
177
|
-
this.appendJoinClause(inner, join.cond);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
mapJoinColumns(type, join) {
|
|
182
|
-
if (join.prop && join.prop.reference === core_1.ReferenceType.ONE_TO_ONE && !join.prop.owner) {
|
|
183
|
-
return join.prop.fieldNames.map((fieldName, idx) => {
|
|
184
|
-
return this.mapper(`${join.alias}.${join.inverseJoinColumns[idx]}`, type, undefined, fieldName);
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
return [
|
|
188
|
-
...join.joinColumns.map(col => this.mapper(`${join.alias}.${col}`, type, undefined, `fk__${col}`)),
|
|
189
|
-
...join.inverseJoinColumns.map(col => this.mapper(`${join.alias}.${col}`, type, undefined, `fk__${col}`)),
|
|
190
|
-
];
|
|
191
|
-
}
|
|
192
|
-
isOneToOneInverse(field) {
|
|
193
|
-
const meta = this.metadata.find(this.entityName);
|
|
194
|
-
const prop = meta.properties[field];
|
|
195
|
-
return prop && prop.reference === core_1.ReferenceType.ONE_TO_ONE && !prop.owner;
|
|
196
|
-
}
|
|
197
|
-
getTableName(entityName) {
|
|
198
|
-
const meta = this.metadata.find(entityName);
|
|
199
|
-
return meta ? meta.collection : entityName;
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Checks whether the RE can be rewritten to simple LIKE query
|
|
203
|
-
*/
|
|
204
|
-
isSimpleRegExp(re) {
|
|
205
|
-
if (!(re instanceof RegExp)) {
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
// when including the opening bracket/paren we consider it complex
|
|
209
|
-
return !re.source.match(/[{[(]/);
|
|
210
|
-
}
|
|
211
|
-
getRegExpParam(re) {
|
|
212
|
-
const value = re.source
|
|
213
|
-
.replace(/\.\*/g, '%') // .* -> %
|
|
214
|
-
.replace(/\./g, '_') // . -> _
|
|
215
|
-
.replace(/\\_/g, '.') // \. -> .
|
|
216
|
-
.replace(/^\^/g, '') // remove ^ from start
|
|
217
|
-
.replace(/\$$/g, ''); // remove $ from end
|
|
218
|
-
if (re.source.startsWith('^') && re.source.endsWith('$')) {
|
|
219
|
-
return value;
|
|
220
|
-
}
|
|
221
|
-
if (re.source.startsWith('^')) {
|
|
222
|
-
return value + '%';
|
|
223
|
-
}
|
|
224
|
-
if (re.source.endsWith('$')) {
|
|
225
|
-
return '%' + value;
|
|
226
|
-
}
|
|
227
|
-
return `%${value}%`;
|
|
228
|
-
}
|
|
229
|
-
appendOnConflictClause(type, onConflict, qb) {
|
|
230
|
-
onConflict.forEach(item => {
|
|
231
|
-
const sub = qb.onConflict(item.fields);
|
|
232
|
-
core_1.Utils.runIfNotEmpty(() => sub.ignore(), item.ignore);
|
|
233
|
-
core_1.Utils.runIfNotEmpty(() => {
|
|
234
|
-
let mergeParam = item.merge;
|
|
235
|
-
if (core_1.Utils.isObject(item.merge)) {
|
|
236
|
-
mergeParam = {};
|
|
237
|
-
Object.keys(item.merge).forEach(key => {
|
|
238
|
-
const k = this.mapper(key, type);
|
|
239
|
-
mergeParam[k] = item.merge[key];
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
if (Array.isArray(item.merge)) {
|
|
243
|
-
mergeParam = item.merge.map(key => this.mapper(key, type));
|
|
244
|
-
}
|
|
245
|
-
const sub2 = sub.merge(mergeParam);
|
|
246
|
-
core_1.Utils.runIfNotEmpty(() => this.appendQueryCondition(type, item.where, sub2), item.where);
|
|
247
|
-
}, 'merge' in item);
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
appendQueryCondition(type, cond, qb, operator, method = 'where') {
|
|
251
|
-
const m = operator === '$or' ? 'orWhere' : 'andWhere';
|
|
252
|
-
Object.keys(cond).forEach(k => {
|
|
253
|
-
if (k === '$and' || k === '$or') {
|
|
254
|
-
if (operator) {
|
|
255
|
-
return qb[m](inner => this.appendGroupCondition(type, inner, k, method, cond[k]));
|
|
256
|
-
}
|
|
257
|
-
return this.appendGroupCondition(type, qb, k, method, cond[k]);
|
|
258
|
-
}
|
|
259
|
-
if (k === '$not') {
|
|
260
|
-
const m = operator === '$or' ? 'orWhereNot' : 'whereNot';
|
|
261
|
-
return qb[m](inner => this.appendQueryCondition(type, cond[k], inner));
|
|
262
|
-
}
|
|
263
|
-
this.appendQuerySubCondition(qb, type, method, cond, k, operator);
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
appendQuerySubCondition(qb, type, method, cond, key, operator) {
|
|
267
|
-
const m = operator === '$or' ? 'orWhere' : method;
|
|
268
|
-
if (this.isSimpleRegExp(cond[key])) {
|
|
269
|
-
return void qb[m](this.mapper(key, type), 'like', this.getRegExpParam(cond[key]));
|
|
270
|
-
}
|
|
271
|
-
if (core_1.Utils.isPlainObject(cond[key]) || cond[key] instanceof RegExp) {
|
|
272
|
-
return this.processObjectSubCondition(cond, key, qb, method, m, type);
|
|
273
|
-
}
|
|
274
|
-
if (QueryBuilderHelper.isCustomExpression(key)) {
|
|
275
|
-
return this.processCustomExpression(qb, m, key, cond, type);
|
|
276
|
-
}
|
|
277
|
-
const op = cond[key] === null ? 'is' : '=';
|
|
278
|
-
if (this.subQueries[key]) {
|
|
279
|
-
return void qb[m](this.knex.raw(`(${this.subQueries[key]})`), op, cond[key]);
|
|
280
|
-
}
|
|
281
|
-
qb[m](this.mapper(key, type, cond[key], null), op, cond[key]);
|
|
282
|
-
}
|
|
283
|
-
processCustomExpression(clause, m, key, cond, type = enums_1.QueryType.SELECT) {
|
|
284
|
-
// unwind parameters when ? found in field name
|
|
285
|
-
const count = key.concat('?').match(/\?/g).length - 1;
|
|
286
|
-
const value = core_1.Utils.asArray(cond[key]);
|
|
287
|
-
const params1 = value.slice(0, count).map((c) => core_1.Utils.isObject(c) ? JSON.stringify(c) : c);
|
|
288
|
-
const params2 = value.slice(count);
|
|
289
|
-
const k = this.mapper(key, type, params1);
|
|
290
|
-
if (params2.length > 0) {
|
|
291
|
-
const val = params2.length === 1 && params2[0] === null ? null : this.knex.raw('?', params2);
|
|
292
|
-
return void clause[m](k, val);
|
|
293
|
-
}
|
|
294
|
-
clause[m](k);
|
|
295
|
-
}
|
|
296
|
-
processObjectSubCondition(cond, key, qb, method, m, type) {
|
|
297
|
-
// grouped condition for one field
|
|
298
|
-
let value = cond[key];
|
|
299
|
-
if (core_1.Utils.getObjectKeysSize(value) > 1) {
|
|
300
|
-
const subCondition = Object.entries(value).map(([subKey, subValue]) => ({ [key]: { [subKey]: subValue } }));
|
|
301
|
-
return subCondition.forEach(sub => this.appendQueryCondition(type, sub, qb, '$and', method));
|
|
302
|
-
}
|
|
303
|
-
if (value instanceof RegExp) {
|
|
304
|
-
value = { $re: value.source };
|
|
305
|
-
}
|
|
306
|
-
// operators
|
|
307
|
-
const op = Object.keys(core_1.QueryOperator).find(op => op in value);
|
|
308
|
-
if (!op) {
|
|
309
|
-
throw new Error(`Invalid query condition: ${(0, util_1.inspect)(cond)}`);
|
|
310
|
-
}
|
|
311
|
-
const replacement = this.getOperatorReplacement(op, value);
|
|
312
|
-
const fields = core_1.Utils.splitPrimaryKeys(key);
|
|
313
|
-
if (fields.length > 1 && Array.isArray(value[op]) && !value[op].every((v) => Array.isArray(v))) {
|
|
314
|
-
const values = this.platform.requiresValuesKeyword() ? 'values ' : '';
|
|
315
|
-
value[op] = this.knex.raw(`${values}(${fields.map(() => '?').join(', ')})`, value[op]);
|
|
316
|
-
}
|
|
317
|
-
if (this.subQueries[key]) {
|
|
318
|
-
return void qb[m](this.knex.raw(`(${this.subQueries[key]})`), replacement, value[op]);
|
|
319
|
-
}
|
|
320
|
-
qb[m](this.mapper(key, type, undefined, null), replacement, value[op]);
|
|
321
|
-
}
|
|
322
|
-
getOperatorReplacement(op, value) {
|
|
323
|
-
let replacement = core_1.QueryOperator[op];
|
|
324
|
-
if (value[op] === null && ['$eq', '$ne'].includes(op)) {
|
|
325
|
-
replacement = op === '$eq' ? 'is' : 'is not';
|
|
326
|
-
}
|
|
327
|
-
if (op === '$re') {
|
|
328
|
-
replacement = this.platform.getRegExpOperator();
|
|
329
|
-
}
|
|
330
|
-
return replacement;
|
|
331
|
-
}
|
|
332
|
-
appendJoinClause(clause, cond, operator) {
|
|
333
|
-
Object.keys(cond).forEach(k => {
|
|
334
|
-
if (k === '$and' || k === '$or') {
|
|
335
|
-
const method = operator === '$or' ? 'orOn' : 'andOn';
|
|
336
|
-
const m = k === '$or' ? 'orOn' : 'andOn';
|
|
337
|
-
return clause[method](outer => cond[k].forEach((sub) => {
|
|
338
|
-
if (core_1.Utils.getObjectKeysSize(sub) === 1) {
|
|
339
|
-
return this.appendJoinClause(outer, sub, k);
|
|
340
|
-
}
|
|
341
|
-
outer[m](inner => this.appendJoinClause(inner, sub, '$and'));
|
|
342
|
-
}));
|
|
343
|
-
}
|
|
344
|
-
this.appendJoinSubClause(clause, cond, k, operator);
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
appendJoinSubClause(clause, cond, key, operator) {
|
|
348
|
-
const m = operator === '$or' ? 'orOn' : 'andOn';
|
|
349
|
-
if (cond[key] instanceof RegExp) {
|
|
350
|
-
return void clause[m](this.mapper(key), 'like', this.knex.raw('?', this.getRegExpParam(cond[key])));
|
|
351
|
-
}
|
|
352
|
-
if (core_1.Utils.isPlainObject(cond[key])) {
|
|
353
|
-
return this.processObjectSubClause(cond, key, clause, m);
|
|
354
|
-
}
|
|
355
|
-
if (QueryBuilderHelper.isCustomExpression(key)) {
|
|
356
|
-
return this.processCustomExpression(clause, m, key, cond);
|
|
357
|
-
}
|
|
358
|
-
const op = cond[key] === null ? 'is' : '=';
|
|
359
|
-
clause[m](this.knex.raw(`${this.knex.ref(this.mapper(key, enums_1.QueryType.SELECT, cond[key]))} ${op} ?`, cond[key]));
|
|
360
|
-
}
|
|
361
|
-
processObjectSubClause(cond, key, clause, m) {
|
|
362
|
-
// grouped condition for one field
|
|
363
|
-
if (core_1.Utils.getObjectKeysSize(cond[key]) > 1) {
|
|
364
|
-
const subCondition = Object.entries(cond[key]).map(([subKey, subValue]) => ({ [key]: { [subKey]: subValue } }));
|
|
365
|
-
return void clause[m](inner => subCondition.map(sub => this.appendJoinClause(inner, sub, '$and')));
|
|
366
|
-
}
|
|
367
|
-
// operators
|
|
368
|
-
for (const [op, replacement] of Object.entries(core_1.QueryOperator)) {
|
|
369
|
-
if (!(op in cond[key])) {
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
clause[m](this.mapper(key), replacement, this.knex.raw('?', cond[key][op]));
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
getQueryOrder(type, orderBy, populate) {
|
|
377
|
-
if (Array.isArray(orderBy)) {
|
|
378
|
-
return orderBy
|
|
379
|
-
.map(o => this.getQueryOrder(type, o, populate))
|
|
380
|
-
.filter(o => o)
|
|
381
|
-
.join(', ');
|
|
382
|
-
}
|
|
383
|
-
return this.getQueryOrderFromObject(type, orderBy, populate);
|
|
384
|
-
}
|
|
385
|
-
getQueryOrderFromObject(type, orderBy, populate) {
|
|
386
|
-
const ret = [];
|
|
387
|
-
Object.keys(orderBy).forEach(k => {
|
|
388
|
-
const direction = orderBy[k];
|
|
389
|
-
const order = core_1.Utils.isNumber(direction) ? core_1.QueryOrderNumeric[direction] : direction;
|
|
390
|
-
if (QueryBuilderHelper.isCustomExpression(k)) {
|
|
391
|
-
ret.push(`${k} ${order.toLowerCase()}`);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
// eslint-disable-next-line prefer-const
|
|
395
|
-
let [alias, field] = this.splitField(k);
|
|
396
|
-
alias = populate[alias] || alias;
|
|
397
|
-
core_1.Utils.splitPrimaryKeys(field).forEach(f => {
|
|
398
|
-
const prop = this.getProperty(f, alias);
|
|
399
|
-
const noPrefix = (prop && prop.persist === false) || QueryBuilderHelper.isCustomExpression(f);
|
|
400
|
-
const column = this.mapper(noPrefix ? f : `${alias}.${f}`, type);
|
|
401
|
-
/* istanbul ignore next */
|
|
402
|
-
const rawColumn = core_1.Utils.isString(column) ? column.split('.').map(e => this.knex.ref(e)).join('.') : column;
|
|
403
|
-
const customOrder = prop?.customOrder;
|
|
404
|
-
const colPart = customOrder
|
|
405
|
-
? this.platform.generateCustomOrder(rawColumn, customOrder)
|
|
406
|
-
: rawColumn;
|
|
407
|
-
ret.push(`${colPart} ${order.toLowerCase()}`);
|
|
408
|
-
});
|
|
409
|
-
});
|
|
410
|
-
return ret.join(', ');
|
|
411
|
-
}
|
|
412
|
-
finalize(type, qb, meta) {
|
|
413
|
-
const useReturningStatement = type === enums_1.QueryType.INSERT && this.platform.usesReturningStatement() && meta && !meta.compositePK;
|
|
414
|
-
if (useReturningStatement) {
|
|
415
|
-
const returningProps = meta.props.filter(prop => prop.primary || prop.defaultRaw);
|
|
416
|
-
qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
splitField(field) {
|
|
420
|
-
const parts = field.split('.');
|
|
421
|
-
const fromField = parts.pop();
|
|
422
|
-
const fromAlias = parts.length > 0 ? parts.join('.') : this.alias;
|
|
423
|
-
return [fromAlias, fromField];
|
|
424
|
-
}
|
|
425
|
-
getLockSQL(qb, lockMode, lockTables = []) {
|
|
426
|
-
const meta = this.metadata.find(this.entityName);
|
|
427
|
-
if (lockMode === core_1.LockMode.OPTIMISTIC && meta && !meta.versionProperty) {
|
|
428
|
-
throw core_1.OptimisticLockError.lockFailed(this.entityName);
|
|
429
|
-
}
|
|
430
|
-
switch (lockMode) {
|
|
431
|
-
case core_1.LockMode.PESSIMISTIC_READ: return void qb.forShare(...lockTables);
|
|
432
|
-
case core_1.LockMode.PESSIMISTIC_WRITE: return void qb.forUpdate(...lockTables);
|
|
433
|
-
case core_1.LockMode.PESSIMISTIC_PARTIAL_WRITE: return void qb.forUpdate(...lockTables).skipLocked();
|
|
434
|
-
case core_1.LockMode.PESSIMISTIC_WRITE_OR_FAIL: return void qb.forUpdate(...lockTables).noWait();
|
|
435
|
-
case core_1.LockMode.PESSIMISTIC_PARTIAL_READ: return void qb.forShare(...lockTables).skipLocked();
|
|
436
|
-
case core_1.LockMode.PESSIMISTIC_READ_OR_FAIL: return void qb.forShare(...lockTables).noWait();
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
updateVersionProperty(qb, data) {
|
|
440
|
-
const meta = this.metadata.find(this.entityName);
|
|
441
|
-
if (!meta || !meta.versionProperty || meta.versionProperty in data) {
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
const versionProperty = meta.properties[meta.versionProperty];
|
|
445
|
-
let sql = this.platform.quoteIdentifier(versionProperty.fieldNames[0]) + ' + 1';
|
|
446
|
-
if (versionProperty.type.toLowerCase() === 'date') {
|
|
447
|
-
sql = this.platform.getCurrentTimestampSQL(versionProperty.length);
|
|
448
|
-
}
|
|
449
|
-
qb.update(versionProperty.fieldNames[0], this.knex.raw(sql));
|
|
450
|
-
}
|
|
451
|
-
static isCustomExpression(field, hasAlias = false) {
|
|
452
|
-
// if we do not have alias, we don't consider spaces as custom expressions
|
|
453
|
-
const re = hasAlias ? /[ ?<>=()'"`:]|^\d/ : /[?<>=()'"`:]|^\d/;
|
|
454
|
-
return !!field.match(re);
|
|
455
|
-
}
|
|
456
|
-
prefix(field, always = false, quote = false) {
|
|
457
|
-
let ret;
|
|
458
|
-
if (!this.isPrefixed(field)) {
|
|
459
|
-
const alias = always ? (quote ? this.alias : this.platform.quoteIdentifier(this.alias)) + '.' : '';
|
|
460
|
-
const fieldName = this.fieldName(field, this.alias, always);
|
|
461
|
-
if (QueryBuilderHelper.isCustomExpression(fieldName)) {
|
|
462
|
-
return fieldName;
|
|
463
|
-
}
|
|
464
|
-
ret = alias + fieldName;
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
const [a, f] = field.split('.');
|
|
468
|
-
ret = a + '.' + this.fieldName(f, a);
|
|
469
|
-
}
|
|
470
|
-
if (quote) {
|
|
471
|
-
return this.platform.quoteIdentifier(ret);
|
|
472
|
-
}
|
|
473
|
-
return ret;
|
|
474
|
-
}
|
|
475
|
-
appendGroupCondition(type, qb, operator, method, subCondition) {
|
|
476
|
-
// single sub-condition can be ignored to reduce nesting of parens
|
|
477
|
-
if (subCondition.length === 1 || operator === '$and') {
|
|
478
|
-
return subCondition.forEach(sub => this.appendQueryCondition(type, sub, qb, undefined, method));
|
|
479
|
-
}
|
|
480
|
-
qb[method](outer => subCondition.forEach(sub => {
|
|
481
|
-
// skip nesting parens if the value is simple = scalar or object without operators or with only single key, being the operator
|
|
482
|
-
const keys = Object.keys(sub);
|
|
483
|
-
const val = sub[keys[0]];
|
|
484
|
-
const simple = !core_1.Utils.isPlainObject(val) || core_1.Utils.getObjectKeysSize(val) === 1 || Object.keys(val).every(k => !core_1.Utils.isOperator(k));
|
|
485
|
-
if (keys.length === 1 && simple) {
|
|
486
|
-
return this.appendQueryCondition(type, sub, outer, operator);
|
|
487
|
-
}
|
|
488
|
-
outer.orWhere(inner => this.appendQueryCondition(type, sub, inner));
|
|
489
|
-
}));
|
|
490
|
-
}
|
|
491
|
-
isPrefixed(field) {
|
|
492
|
-
return !!field.match(/[\w`"[\]]+\./);
|
|
493
|
-
}
|
|
494
|
-
fieldName(field, alias, always) {
|
|
495
|
-
const prop = this.getProperty(field, alias);
|
|
496
|
-
if (!prop) {
|
|
497
|
-
return field;
|
|
498
|
-
}
|
|
499
|
-
if (prop.fieldNameRaw) {
|
|
500
|
-
if (!always) {
|
|
501
|
-
return prop.fieldNameRaw
|
|
502
|
-
.replace(/\[::alias::]\.?/g, '')
|
|
503
|
-
.replace(this.platform.quoteIdentifier('') + '.', '');
|
|
504
|
-
}
|
|
505
|
-
if (alias) {
|
|
506
|
-
return prop.fieldNameRaw.replace(/\[::alias::]/g, alias);
|
|
507
|
-
}
|
|
508
|
-
/* istanbul ignore next */
|
|
509
|
-
return prop.fieldNameRaw;
|
|
510
|
-
}
|
|
511
|
-
/* istanbul ignore next */
|
|
512
|
-
return prop.fieldNames[0] ?? field;
|
|
513
|
-
}
|
|
514
|
-
getProperty(field, alias) {
|
|
515
|
-
const entityName = this.aliasMap[alias] || this.entityName;
|
|
516
|
-
const meta = this.metadata.find(entityName);
|
|
517
|
-
return meta ? meta.properties[field] : undefined;
|
|
518
|
-
}
|
|
519
|
-
isTableNameAliasRequired(type) {
|
|
520
|
-
return [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(type);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
exports.QueryBuilderHelper = QueryBuilderHelper;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { CriteriaNode } from './CriteriaNode';
|
|
2
|
-
import type { IQueryBuilder } from '../typings';
|
|
3
|
-
/**
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export declare class ScalarCriteriaNode extends CriteriaNode {
|
|
7
|
-
process<T>(qb: IQueryBuilder<T>, alias?: string): any;
|
|
8
|
-
shouldJoin(): boolean;
|
|
9
|
-
}
|
package/dist/query/enums.d.ts
DELETED
package/dist/query/enums.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QueryType = void 0;
|
|
4
|
-
var QueryType;
|
|
5
|
-
(function (QueryType) {
|
|
6
|
-
QueryType["TRUNCATE"] = "TRUNCATE";
|
|
7
|
-
QueryType["SELECT"] = "SELECT";
|
|
8
|
-
QueryType["COUNT"] = "COUNT";
|
|
9
|
-
QueryType["INSERT"] = "INSERT";
|
|
10
|
-
QueryType["UPDATE"] = "UPDATE";
|
|
11
|
-
QueryType["DELETE"] = "DELETE";
|
|
12
|
-
})(QueryType = exports.QueryType || (exports.QueryType = {}));
|