Skip to content

Commit a42cf9d

Browse files
authored
Fix: TypeError with fromRaw() when using alias from 'from' method (#226)
* Added failing test * Fixed fromRaw * Fixed tests
1 parent ccda351 commit a42cf9d

File tree

2 files changed

+163
-1
lines changed

2 files changed

+163
-1
lines changed

src/Mixins/JoinRelationship.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function joinRelationship(): Closure
110110
// Check if the main table has an alias (e.g., "posts as p") and set it as the main table or alias if it does.
111111
$fromClause = $this->getQuery()->from;
112112
$mainTableOrAlias = $this->getModel()->getTable();
113-
if ($fromClause && preg_match('/^.+\s+as\s+["\'\`]?(.+?)["\'\`]?$/i', $fromClause, $matches)) {
113+
if ($fromClause && is_string($fromClause) && preg_match('/^.+\s+as\s+["\'\`]?(.+?)["\'\`]?$/i', $fromClause, $matches)) {
114114
// Register the alias for the main model so joins use it
115115
$mainTableOrAlias = $matches[1];
116116
StaticCache::setTableAliasForModel($this->getModel(), $mainTableOrAlias);
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php
2+
3+
namespace Kirschbaum\PowerJoins\Tests;
4+
5+
use Illuminate\Support\Facades\DB;
6+
use Kirschbaum\PowerJoins\Tests\Models\Comment;
7+
use Kirschbaum\PowerJoins\Tests\Models\Post;
8+
use Kirschbaum\PowerJoins\Tests\Models\User;
9+
10+
class FromRawWithJoinRelationshipTest extends TestCase
11+
{
12+
/**
13+
* Get the boolean true value for the current database driver.
14+
*/
15+
protected function getBooleanTrueValue(): string
16+
{
17+
$driver = DB::getDriverName();
18+
19+
return match ($driver) {
20+
'pgsql' => 'true',
21+
'sqlite' => '1',
22+
default => '1', // MySQL and others use 1
23+
};
24+
}
25+
26+
/** @test */
27+
public function test_left_join_relationship_with_from_raw_cte()
28+
{
29+
// Skip CTE test for SQLite as it has limited CTE support in subqueries
30+
if (DB::getDriverName() === 'sqlite') {
31+
$this->markTestSkipped('SQLite has limited CTE support in subqueries');
32+
}
33+
34+
$user = factory(User::class)->create(['name' => 'John Doe']);
35+
factory(Post::class)->create([
36+
'user_id' => $user->id,
37+
'title' => 'Test Post',
38+
'published' => true,
39+
]);
40+
41+
$boolTrue = $this->getBooleanTrueValue();
42+
43+
// Using fromRaw with a CTE (Common Table Expression)
44+
$query = Post::fromRaw("(
45+
WITH active_posts AS (
46+
SELECT * FROM posts WHERE published = {$boolTrue}
47+
)
48+
SELECT * FROM active_posts
49+
) as posts")
50+
->leftJoinRelationship('user');
51+
52+
// Should not throw TypeError
53+
$result = $query->get();
54+
55+
$this->assertCount(1, $result);
56+
$this->assertEquals('Test Post', $result->first()->title);
57+
}
58+
59+
/** @test */
60+
public function test_join_relationship_with_from_raw_subquery()
61+
{
62+
$user = factory(User::class)->create(['name' => 'Jane Doe']);
63+
factory(Post::class)->create([
64+
'user_id' => $user->id,
65+
'title' => 'Another Test',
66+
'published' => true,
67+
]);
68+
69+
$boolTrue = $this->getBooleanTrueValue();
70+
71+
// Using fromRaw with a subquery
72+
$query = Post::fromRaw("(
73+
SELECT * FROM posts WHERE published = {$boolTrue}
74+
) as posts")
75+
->joinRelationship('user');
76+
77+
// Should not throw TypeError
78+
$result = $query->get();
79+
80+
$this->assertCount(1, $result);
81+
$this->assertEquals('Another Test', $result->first()->title);
82+
}
83+
84+
/** @test */
85+
public function test_order_by_left_power_joins_with_from_raw()
86+
{
87+
$user = factory(User::class)->create(['name' => 'Alice']);
88+
factory(Post::class)->create([
89+
'user_id' => $user->id,
90+
'title' => 'First Post',
91+
'published' => true,
92+
]);
93+
94+
$boolTrue = $this->getBooleanTrueValue();
95+
96+
// Using fromRaw with orderByLeftPowerJoins
97+
$query = Post::fromRaw("(
98+
SELECT * FROM posts WHERE published = {$boolTrue}
99+
) as posts")
100+
->orderByLeftPowerJoins('user.name', 'asc');
101+
102+
// Should not throw TypeError
103+
$result = $query->get();
104+
105+
$this->assertCount(1, $result);
106+
$this->assertEquals('First Post', $result->first()->title);
107+
}
108+
109+
/** @test */
110+
public function test_right_join_relationship_with_from_raw()
111+
{
112+
$user = factory(User::class)->create(['name' => 'Bob']);
113+
factory(Post::class)->create([
114+
'user_id' => $user->id,
115+
'title' => 'Right Join Test',
116+
'published' => true,
117+
]);
118+
119+
$boolTrue = $this->getBooleanTrueValue();
120+
121+
// Using fromRaw with rightJoinRelationship
122+
$query = Post::fromRaw("(
123+
SELECT * FROM posts WHERE published = {$boolTrue}
124+
) as posts")
125+
->rightJoinRelationship('user');
126+
127+
// Should not throw TypeError
128+
$result = $query->get();
129+
130+
$this->assertGreaterThanOrEqual(1, $result->count());
131+
}
132+
133+
/** @test */
134+
public function test_nested_join_relationship_with_from_raw()
135+
{
136+
$user = factory(User::class)->create(['name' => 'Charlie']);
137+
$post = factory(Post::class)->create([
138+
'user_id' => $user->id,
139+
'title' => 'Nested Test',
140+
'published' => true,
141+
]);
142+
factory(Comment::class)->create([
143+
'post_id' => $post->id,
144+
'user_id' => $user->id,
145+
'body' => 'Test comment',
146+
]);
147+
148+
$boolTrue = $this->getBooleanTrueValue();
149+
150+
// Using fromRaw with nested relationship
151+
$query = Post::fromRaw("(
152+
SELECT * FROM posts WHERE published = {$boolTrue}
153+
) as posts")
154+
->leftJoinRelationship('comments.user');
155+
156+
// Should not throw TypeError
157+
$result = $query->get();
158+
159+
$this->assertCount(1, $result);
160+
$this->assertEquals('Nested Test', $result->first()->title);
161+
}
162+
}

0 commit comments

Comments
 (0)