* When adding an inner join on a left joined relation, we need to nest them, * otherwise the inner join could discard rows of the root table.
()
| 3908 | * otherwise the inner join could discard rows of the root table. |
| 3909 | */ |
| 3910 | private processNestedJoins() { |
| 3911 | if (this.#state.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) { |
| 3912 | return; |
| 3913 | } |
| 3914 | |
| 3915 | const joins = Object.values(this.#state.joins); |
| 3916 | const lookupParentGroup = (j: JoinOptions): Set<JoinOptions> | undefined => { |
| 3917 | return j.nested ?? (j.parent ? lookupParentGroup(j.parent) : undefined); |
| 3918 | }; |
| 3919 | |
| 3920 | for (const join of joins) { |
| 3921 | if (join.type === JoinType.innerJoin) { |
| 3922 | join.parent = joins.find(j => j.alias === join.ownerAlias); |
| 3923 | |
| 3924 | // https://stackoverflow.com/a/56815807/3665878 |
| 3925 | if (join.parent?.type === JoinType.leftJoin || join.parent?.type === JoinType.nestedLeftJoin) { |
| 3926 | const nested = (join.parent.nested ??= new Set()); |
| 3927 | join.type = join.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin; |
| 3928 | nested.add(join); |
| 3929 | } else if (join.parent?.type === JoinType.nestedInnerJoin) { |
| 3930 | const group = lookupParentGroup(join.parent); |
| 3931 | const nested = group ?? (join.parent.nested ??= new Set()); |
| 3932 | join.type = join.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin; |
| 3933 | nested.add(join); |
| 3934 | } |
| 3935 | } |
| 3936 | } |
| 3937 | } |
| 3938 | |
| 3939 | private hasToManyJoins(): boolean { |
| 3940 | return Object.values(this.#state.joins).some(join => { |