@mikro-orm/sql 7.1.13-dev.5 → 7.1.13-dev.6

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.13-dev.5",
3
+ "version": "7.1.13-dev.6",
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.12"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.1.13-dev.5"
56
+ "@mikro-orm/core": "7.1.13-dev.6"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"
@@ -994,6 +994,13 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
994
994
  processPopulateHint(): void;
995
995
  private processPopulateWhere;
996
996
  private mergeOnConditions;
997
+ /**
998
+ * `$or` branches can be moved to a to-one join's `on` clause only when they all target that same
999
+ * join and stay flat — a partial `$or` in the `on` clause would drop rows matching a sibling
1000
+ * branch. A `$or` targeting only to-many joins keeps the partial distribution, as that is how
1001
+ * `PopulateHint.INFER` narrows collections.
1002
+ */
1003
+ private canDistributeOrBranches;
997
1004
  /**
998
1005
  * When adding an inner join on a left joined relation, we need to nest them,
999
1006
  * otherwise the inner join could discard rows of the root table.
@@ -2038,6 +2038,10 @@ export class QueryBuilder {
2038
2038
  for (const k of Object.keys(cond)) {
2039
2039
  if (Utils.isOperator(k)) {
2040
2040
  if (Array.isArray(cond[k])) {
2041
+ // a partial `$or` on a to-one join drops rows matching a sibling branch, but entity filters have no other sink, so they must pass
2042
+ if (k === '$or' && !filter && !this.canDistributeOrBranches(cond[k], joins)) {
2043
+ continue;
2044
+ }
2041
2045
  cond[k].forEach((c) => this.mergeOnConditions(joins, c, filter, k));
2042
2046
  }
2043
2047
  /* v8 ignore next */
@@ -2071,6 +2075,33 @@ export class QueryBuilder {
2071
2075
  }
2072
2076
  }
2073
2077
  }
2078
+ /**
2079
+ * `$or` branches can be moved to a to-one join's `on` clause only when they all target that same
2080
+ * join and stay flat — a partial `$or` in the `on` clause would drop rows matching a sibling
2081
+ * branch. A `$or` targeting only to-many joins keeps the partial distribution, as that is how
2082
+ * `PopulateHint.INFER` narrows collections.
2083
+ */
2084
+ canDistributeOrBranches(branches, joins) {
2085
+ const aliases = new Set();
2086
+ const collectAliases = (cond) => {
2087
+ for (const k of Object.keys(cond)) {
2088
+ if (Utils.isOperator(k)) {
2089
+ Utils.asArray(cond[k]).forEach((c) => collectAliases(c));
2090
+ }
2091
+ else {
2092
+ aliases.add(this.helper.splitField(k)[0]);
2093
+ }
2094
+ }
2095
+ };
2096
+ branches.forEach(collectAliases);
2097
+ const targeted = joins.filter(j => aliases.has(j.alias));
2098
+ // nested operators cannot be preserved inside a distributed disjunction, `mergeOnConditions` would flatten them into `and` conjuncts
2099
+ const flat = branches.every(branch => Object.keys(branch).every(k => !Utils.isOperator(k)));
2100
+ if (aliases.size === 1 && targeted.length === 1 && flat) {
2101
+ return true;
2102
+ }
2103
+ return !targeted.some(j => [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(j.prop.kind));
2104
+ }
2074
2105
  /**
2075
2106
  * When adding an inner join on a left joined relation, we need to nest them,
2076
2107
  * otherwise the inner join could discard rows of the root table.