@mikro-orm/sql 7.1.16-dev.7 → 7.1.16-dev.8
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.1.16-dev.
|
|
3
|
+
"version": "7.1.16-dev.8",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@mikro-orm/core": "^7.1.15"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.1.16-dev.
|
|
56
|
+
"@mikro-orm/core": "7.1.16-dev.8"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
|
@@ -13,6 +13,7 @@ export declare class ObjectCriteriaNode<T extends object> extends CriteriaNode<T
|
|
|
13
13
|
private inlineArrayChildPayload;
|
|
14
14
|
private inlineChildPayload;
|
|
15
15
|
private inlineCondition;
|
|
16
|
+
private isCollectionOperator;
|
|
16
17
|
private shouldAutoJoin;
|
|
17
18
|
private autoJoin;
|
|
18
19
|
private isPrefixed;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ALIAS_REPLACEMENT, GroupOperator, QueryFlag, raw, RawQueryFragment, ReferenceKind, Utils, } from '@mikro-orm/core';
|
|
2
2
|
import { CriteriaNode } from './CriteriaNode.js';
|
|
3
3
|
import { JoinType, QueryType } from './enums.js';
|
|
4
|
-
const COLLECTION_OPERATORS = ['$some', '$none', '$every', '$size'];
|
|
4
|
+
const COLLECTION_OPERATORS = ['$some', '$none', '$every', '$size', '$all'];
|
|
5
5
|
/**
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
@@ -17,7 +17,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
17
17
|
alias = nestedAlias;
|
|
18
18
|
}
|
|
19
19
|
if (this.shouldAutoJoin(qb, nestedAlias)) {
|
|
20
|
-
if (keys.some(k =>
|
|
20
|
+
if (keys.some(k => this.isCollectionOperator(k))) {
|
|
21
21
|
if (![ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(this.prop.kind)) {
|
|
22
22
|
// ignore collection operators when used on a non-relational property - this can happen when they get into
|
|
23
23
|
// populateWhere via `infer` on m:n properties with select-in strategy
|
|
@@ -34,11 +34,24 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
34
34
|
const primaryKeys = parentMeta.primaryKeys.map(pk => {
|
|
35
35
|
return [QueryType.SELECT, QueryType.COUNT].includes(qb.type) ? `${knownKey ? alias : ownerAlias}.${pk}` : pk;
|
|
36
36
|
});
|
|
37
|
+
const conditions = [];
|
|
38
|
+
let matchNothing = false;
|
|
37
39
|
for (const key of keys) {
|
|
38
40
|
if (typeof key !== 'string' || !COLLECTION_OPERATORS.includes(key)) {
|
|
39
41
|
throw new Error('Mixing collection operators with other filters is not allowed.');
|
|
40
42
|
}
|
|
41
43
|
const payload = this.payload[key].unwrap();
|
|
44
|
+
// `$all` requires every listed item to be present, which is an intersection of `$some` conditions
|
|
45
|
+
if (key === '$all') {
|
|
46
|
+
// an empty `$all` matches nothing, same as in mongo
|
|
47
|
+
matchNothing ||= payload.length === 0;
|
|
48
|
+
conditions.push(...payload.map(item => ['$some', item]));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
conditions.push([key, payload]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const [key, payload] of conditions) {
|
|
42
55
|
// entities with a fixed schema must resolve the `from` table's own schema in the subquery,
|
|
43
56
|
// otherwise a nested operator inherits the root entity's schema (GH #7894); for wildcard or
|
|
44
57
|
// schema-less entities the schema is resolved dynamically and needs to be carried over
|
|
@@ -70,6 +83,9 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
70
83
|
[Utils.getPrimaryKeyHash(primaryKeys)]: { [op]: sub.getNativeQuery().toRaw() },
|
|
71
84
|
});
|
|
72
85
|
}
|
|
86
|
+
if (matchNothing) {
|
|
87
|
+
$and.push({ [Utils.getPrimaryKeyHash(primaryKeys)]: { $in: [] } });
|
|
88
|
+
}
|
|
73
89
|
if ($and.length === 1) {
|
|
74
90
|
return $and[0];
|
|
75
91
|
}
|
|
@@ -154,7 +170,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
154
170
|
alias = nestedAlias;
|
|
155
171
|
}
|
|
156
172
|
if (this.shouldAutoJoin(qb, nestedAlias)) {
|
|
157
|
-
return !keys.some(k =>
|
|
173
|
+
return !keys.some(k => this.isCollectionOperator(k));
|
|
158
174
|
}
|
|
159
175
|
return keys.some(field => {
|
|
160
176
|
const childNode = this.payload[field];
|
|
@@ -238,6 +254,14 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
238
254
|
delete o[key];
|
|
239
255
|
o.$and = $and;
|
|
240
256
|
}
|
|
257
|
+
isCollectionOperator(key) {
|
|
258
|
+
if (typeof key !== 'string' || !COLLECTION_OPERATORS.includes(key)) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
// `$all` is primarily a mongo array operator, in SQL it is supported only on collections
|
|
262
|
+
return (key !== '$all' ||
|
|
263
|
+
(!!this.prop && [ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(this.prop.kind)));
|
|
264
|
+
}
|
|
241
265
|
shouldAutoJoin(qb, nestedAlias) {
|
|
242
266
|
if (!this.prop || !this.parent) {
|
|
243
267
|
return false;
|
|
@@ -246,7 +270,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
246
270
|
if (keys.every(k => typeof k === 'string' && k.includes('.') && k.startsWith(`${qb.alias}.`))) {
|
|
247
271
|
return false;
|
|
248
272
|
}
|
|
249
|
-
if (keys.some(k =>
|
|
273
|
+
if (keys.some(k => this.isCollectionOperator(k))) {
|
|
250
274
|
return true;
|
|
251
275
|
}
|
|
252
276
|
const meta = this.metadata.find(this.entityName);
|
|
@@ -643,6 +643,10 @@ export class QueryBuilderHelper {
|
|
|
643
643
|
return '?';
|
|
644
644
|
}
|
|
645
645
|
getOperatorReplacement(op, value) {
|
|
646
|
+
// collection properties expand `$all` into `$some` sub-queries in `ObjectCriteriaNode`, nothing else has a SQL equivalent
|
|
647
|
+
if (op === '$all') {
|
|
648
|
+
throw new Error('The `$all` operator is supported only on collection properties in SQL drivers, use `$contains` for array columns instead.');
|
|
649
|
+
}
|
|
646
650
|
let replacement = QueryOperator[op];
|
|
647
651
|
if (op === '$exists') {
|
|
648
652
|
replacement = value[op] ? 'is not' : 'is';
|