@mikro-orm/sql 7.1.10-dev.6 → 7.1.10-dev.7
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 +2 -2
- package/query/QueryBuilder.d.ts +10 -5
- package/query/QueryBuilder.js +32 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.1.10-dev.
|
|
3
|
+
"version": "7.1.10-dev.7",
|
|
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.9"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.1.10-dev.
|
|
56
|
+
"@mikro-orm/core": "7.1.10-dev.7"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
package/query/QueryBuilder.d.ts
CHANGED
|
@@ -507,11 +507,16 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
507
507
|
*/
|
|
508
508
|
applyJoinedFilters(em: EntityManager, filterOptions: FilterOptions | undefined): Promise<void>;
|
|
509
509
|
/**
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
|
|
514
|
-
|
|
510
|
+
* The `on` clause of `condJoin` — its explicit join condition or a filter condition merged into
|
|
511
|
+
* it — can reference the alias of any join in its subtree, both auto-joins created while
|
|
512
|
+
* processing the condition and pre-existing joined paths, all of which render after `condJoin`
|
|
513
|
+
* and would be forward alias references (issues #7681, #8090, #8099). When that happens, fold the
|
|
514
|
+
* subtree into `condJoin`, so it renders as a single parenthesized join group and every alias
|
|
515
|
+
* shares the scope of the outer `on` clause.
|
|
516
|
+
*/
|
|
517
|
+
private nestReferencedJoins;
|
|
518
|
+
private getJoinSubtree;
|
|
519
|
+
private condReferencesAlias;
|
|
515
520
|
withSubQuery(subQuery: RawQueryFragment | NativeQueryBuilder, alias: string): this;
|
|
516
521
|
/**
|
|
517
522
|
* Adds a WHERE clause to the query using an object condition.
|
package/query/QueryBuilder.js
CHANGED
|
@@ -411,7 +411,6 @@ export class QueryBuilder {
|
|
|
411
411
|
filterOptions = QueryHelper.mergePropertyFilters(join.prop.filters, filterOptions);
|
|
412
412
|
let cond = await em.applyFilters(join.prop.targetMeta.class, join.cond, filterOptions, 'read');
|
|
413
413
|
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, join.prop.targetMeta.class, cond);
|
|
414
|
-
const joinCountBefore = Object.keys(this.#state.joins).length;
|
|
415
414
|
cond = criteriaNode.process(this, {
|
|
416
415
|
matchPopulateJoins: true,
|
|
417
416
|
filter: true,
|
|
@@ -419,7 +418,6 @@ export class QueryBuilder {
|
|
|
419
418
|
ignoreBranching: true,
|
|
420
419
|
parentPath: join.path,
|
|
421
420
|
});
|
|
422
|
-
this.nestNewJoins(join, joinCountBefore);
|
|
423
421
|
if (Utils.hasObjectKeys(cond) || RawQueryFragment.hasObjectFragments(cond)) {
|
|
424
422
|
// remove nested filters, we only care about scalars here, nesting would require another join branch
|
|
425
423
|
for (const key of Object.keys(cond)) {
|
|
@@ -435,6 +433,7 @@ export class QueryBuilder {
|
|
|
435
433
|
else {
|
|
436
434
|
join.cond = { ...cond };
|
|
437
435
|
}
|
|
436
|
+
this.nestReferencedJoins(join);
|
|
438
437
|
// For polymorphic LEFT JOIN filters, add a WHERE condition to enforce the filter
|
|
439
438
|
// only for rows matching this target's discriminator value. This ensures rows pointing
|
|
440
439
|
// to other polymorphic targets are not excluded.
|
|
@@ -459,26 +458,44 @@ export class QueryBuilder {
|
|
|
459
458
|
}
|
|
460
459
|
}
|
|
461
460
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
461
|
+
* The `on` clause of `condJoin` — its explicit join condition or a filter condition merged into
|
|
462
|
+
* it — can reference the alias of any join in its subtree, both auto-joins created while
|
|
463
|
+
* processing the condition and pre-existing joined paths, all of which render after `condJoin`
|
|
464
|
+
* and would be forward alias references (issues #7681, #8090, #8099). When that happens, fold the
|
|
465
|
+
* subtree into `condJoin`, so it renders as a single parenthesized join group and every alias
|
|
466
|
+
* shares the scope of the outer `on` clause.
|
|
465
467
|
*/
|
|
466
|
-
|
|
468
|
+
nestReferencedJoins(condJoin) {
|
|
467
469
|
// m:n pivot joins might not have the target join entry created
|
|
468
470
|
if (!condJoin) {
|
|
469
471
|
return;
|
|
470
472
|
}
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
473
|
+
const subtree = this.getJoinSubtree(condJoin);
|
|
474
|
+
if (!subtree.some(j => this.condReferencesAlias(condJoin.cond, j.alias))) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
for (const j of subtree) {
|
|
478
|
+
const parent = j.ownerAlias === condJoin.alias ? condJoin : subtree.find(p => p.alias === j.ownerAlias);
|
|
479
|
+
if (!parent.nested?.has(j)) {
|
|
480
|
+
const nested = (parent.nested ??= new Set());
|
|
481
|
+
j.type = j.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin;
|
|
482
|
+
nested.add(j);
|
|
476
483
|
}
|
|
477
|
-
const nested = (condJoin.nested ??= new Set());
|
|
478
|
-
j.type = j.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin;
|
|
479
|
-
nested.add(j);
|
|
480
484
|
}
|
|
481
485
|
}
|
|
486
|
+
getJoinSubtree(join) {
|
|
487
|
+
const children = Object.values(this.#state.joins).filter(j => j !== join && j.ownerAlias === join.alias);
|
|
488
|
+
return children.flatMap(j => [j, ...this.getJoinSubtree(j)]);
|
|
489
|
+
}
|
|
490
|
+
condReferencesAlias(cond, alias) {
|
|
491
|
+
if (Array.isArray(cond)) {
|
|
492
|
+
return cond.some(c => this.condReferencesAlias(c, alias));
|
|
493
|
+
}
|
|
494
|
+
if (Utils.isPlainObject(cond)) {
|
|
495
|
+
return Object.entries(cond).some(([key, value]) => key.startsWith(`${alias}.`) || this.condReferencesAlias(value, alias));
|
|
496
|
+
}
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
482
499
|
withSubQuery(subQuery, alias) {
|
|
483
500
|
this.ensureNotFinalized();
|
|
484
501
|
if (isRaw(subQuery)) {
|
|
@@ -1437,7 +1454,6 @@ export class QueryBuilder {
|
|
|
1437
1454
|
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
1438
1455
|
});
|
|
1439
1456
|
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.class, cond);
|
|
1440
|
-
const joinCountBefore = Object.keys(this.#state.joins).length;
|
|
1441
1457
|
cond = criteriaNode.process(this, { ignoreBranching: true, alias });
|
|
1442
1458
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1443
1459
|
path ??= `${Object.values(this.#state.joins).find(j => j.alias === fromAlias)?.path ?? Utils.className(entityName)}.${prop.name}`;
|
|
@@ -1467,7 +1483,7 @@ export class QueryBuilder {
|
|
|
1467
1483
|
this.#state.joins[aliasedName] = this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, cond, schema);
|
|
1468
1484
|
this.#state.joins[aliasedName].path ??= path;
|
|
1469
1485
|
}
|
|
1470
|
-
this.
|
|
1486
|
+
this.nestReferencedJoins(this.#state.joins[aliasedName]);
|
|
1471
1487
|
return { prop, key: aliasedName };
|
|
1472
1488
|
}
|
|
1473
1489
|
prepareFields(fields, type = 'where', schema) {
|