From 9a97b557f00fef341f0cb606d0ff4efdfbe1ee7f Mon Sep 17 00:00:00 2001 From: Deploy Date: Sat, 28 Dec 2024 16:07:44 +0100 Subject: [PATCH] feat: Added lateralJoin support --- src/Query/Concerns/BuildsJoins.php | 24 +++++++++++++++ src/Query/Concerns/CompilesColumns.php | 2 +- src/Query/Concerns/CompilesJoins.php | 1 + tests/Query/JoinTest.php | 41 ++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/Query/Concerns/BuildsJoins.php b/src/Query/Concerns/BuildsJoins.php index 989a4cd..d8cbe67 100644 --- a/src/Query/Concerns/BuildsJoins.php +++ b/src/Query/Concerns/BuildsJoins.php @@ -182,4 +182,28 @@ protected function newJoinClause(IlluminateQueryBuilder $parentQuery, $type, $ta return new JoinClause($parentQuery, $type, $table); } + /** + * Add a lateral join clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param string $type + * @return $this + */ + public function joinLateral($query, string $as, string $type = 'inner') + { + assert($query instanceof Builder); + + $query->importTableAliases($this); + $query->importTableAliases([$as => $as]); + $this->importTableAliases($query); + + [$query] = $this->createSub($query); + + $expression = $query . ' as ' . $this->grammar->wrapTable($as); + + $this->joins[] = $this->newJoinLateralClause($this, $type, new Expression($expression)); + + return $this; + } } diff --git a/src/Query/Concerns/CompilesColumns.php b/src/Query/Concerns/CompilesColumns.php index ca93959..9f81188 100644 --- a/src/Query/Concerns/CompilesColumns.php +++ b/src/Query/Concerns/CompilesColumns.php @@ -172,7 +172,6 @@ protected function normalizeColumnReferences(IlluminateQueryBuilder $query, stri $references = explode('.', $column); - $tableAlias = $query->getTableAlias($references[0]); if (isset($tableAlias)) { @@ -184,6 +183,7 @@ protected function normalizeColumnReferences(IlluminateQueryBuilder $query, stri array_unshift($references, $tableAlias); } + // geen tableAlias, table is parent...waarom geen tableAlias? if ($tableAlias === null && array_key_exists($table, $query->tableAliases)) { array_unshift($references, $query->tableAliases[$table]); } diff --git a/src/Query/Concerns/CompilesJoins.php b/src/Query/Concerns/CompilesJoins.php index 56b4ae7..264dda5 100644 --- a/src/Query/Concerns/CompilesJoins.php +++ b/src/Query/Concerns/CompilesJoins.php @@ -29,6 +29,7 @@ public function extractTableAndAlias(Builder $query, $join): array return [$table, $alias]; } + } $table = (string) $this->wrapTable($join->table); diff --git a/tests/Query/JoinTest.php b/tests/Query/JoinTest.php index f9abb7b..cc6f96d 100644 --- a/tests/Query/JoinTest.php +++ b/tests/Query/JoinTest.php @@ -110,3 +110,44 @@ 'coordinate', ]); }); + +test('joinLateral', function () { + $controlledLocations = DB::table('locations') + ->whereColumn('locations.led_by', '==', 'characters.id') + ->limit(3); + + $leadingLadies = DB::table('characters') + ->joinLateral( + $controlledLocations, + 'controlled_territory', + ) + ->orderBy('name') + ->get(); + + expect($leadingLadies)->toHaveCount(6); +}); + + +test('joinLateral with selected fields', function () { + $controlledLocations = DB::table('locations') + ->select('id as location_id', 'name as location_name') + ->whereColumn('locations.led_by', '==', 'characters.id') + ->orderBy('name') + ->limit(3); + + $leadingLadies = DB::table('characters') + ->select('id', 'name', 'controlled_territory.location_name as territory_name') + ->joinLateral( + $controlledLocations, + 'controlled_territory', + ) + ->orderBy('name') + ->get(); + + expect($leadingLadies)->toHaveCount(6); + + expect(($leadingLadies[1])->name)->toBe('Cersei'); + expect(($leadingLadies[2])->name)->toBe('Daenerys'); + expect(($leadingLadies[2])->territory_name)->toBe('Astapor'); + expect(($leadingLadies[5])->name)->toBe('Sansa'); +});