Skip to content

Commit 4005f76

Browse files
authored
Merge pull request #13 from WyriHaximus/lazy-joins
Allow inner joins to be defined as lazy
2 parents 6f992b6 + b33a062 commit 4005f76

File tree

9 files changed

+89
-10
lines changed

9 files changed

+89
-10
lines changed

infection.json.dist

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@
2222
},
2323
"IncrementInteger": {
2424
"ignore": [
25-
"WyriHaximus\\React\\SimpleORM\\Repository::count"
25+
"WyriHaximus\\React\\SimpleORM\\Repository::count",
26+
"WyriHaximus\\React\\SimpleORM\\Repository::buildTree"
2627
]
2728
},
2829
"OneZeroInteger": {
2930
"ignore": [
3031
"WyriHaximus\\React\\SimpleORM\\Repository::count"
3132
]
33+
},
34+
"Foreach_": {
35+
"ignore": [
36+
"WyriHaximus\\React\\SimpleORM\\Repository::buildTree"
37+
]
3238
}
3339
}
34-
}
40+
}

src/Annotation/InnerJoin.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ final class InnerJoin implements JoinInterface
2020
/** @var string */
2121
private $property;
2222

23+
/** @var bool */
24+
private $lazy = self::IS_NOT_LAZY;
25+
2326
public function __construct(array $table)
2427
{
2528
/** @psalm-suppress RawObjectIteration */
@@ -40,6 +43,11 @@ public function getType(): string
4043
return 'inner';
4144
}
4245

46+
public function getLazy(): bool
47+
{
48+
return $this->lazy;
49+
}
50+
4351
/**
4452
* @return Clause[]
4553
*/

src/Annotation/JoinInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44

55
interface JoinInterface
66
{
7+
public const IS_LAZY = true;
8+
public const IS_NOT_LAZY = false;
9+
710
public function getEntity(): string;
811

912
public function getType(): string;
1013

1114
public function getProperty(): string;
1215

16+
public function getLazy(): bool;
17+
1318
/**
1419
* @return Clause[]
1520
*/

src/Annotation/LeftJoin.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ final class LeftJoin implements JoinInterface
2020
/** @var string */
2121
private $property;
2222

23+
/** @var bool */
24+
private $lazy = self::IS_NOT_LAZY;
25+
2326
public function __construct(array $table)
2427
{
2528
/** @psalm-suppress RawObjectIteration */
@@ -40,6 +43,11 @@ public function getType(): string
4043
return 'left';
4144
}
4245

46+
public function getLazy(): bool
47+
{
48+
return $this->lazy;
49+
}
50+
4351
/**
4452
* @return Clause[]
4553
*/

src/Entity/Join.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ final class Join
1616
/** @var string */
1717
private $property;
1818

19+
/** @var bool */
20+
private $lazy;
21+
1922
/** @var Clause[] */
2023
private $clause;
2124

22-
public function __construct(InspectedEntityInterface $entity, string $type, string $property, Clause ...$clause)
25+
public function __construct(InspectedEntityInterface $entity, string $type, string $property, bool $lazy, Clause ...$clause)
2326
{
2427
$this->entity = $entity;
2528
$this->type = $type;
2629
$this->property = $property;
30+
$this->lazy = $lazy;
2731
$this->clause = $clause;
2832
}
2933

@@ -42,6 +46,11 @@ public function getProperty(): string
4246
return $this->property;
4347
}
4448

49+
public function getLazy(): bool
50+
{
51+
return $this->lazy;
52+
}
53+
4554
/**
4655
* @return Clause[]
4756
*/

src/EntityInspector.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ private function getJoins(ReflectionClass $class): iterable
8080
new LazyInspectedEntity($this, $annotation->getEntity()),
8181
$annotation->getType(),
8282
$annotation->getProperty(),
83+
$annotation->getLazy(),
8384
...$annotation->getClause()
8485
);
8586
}

src/Repository.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use React\Promise\PromiseInterface;
99
use Rx\Observable;
1010
use Rx\Scheduler\ImmediateScheduler;
11+
use WyriHaximus\React\SimpleORM\Annotation\JoinInterface;
1112

1213
final class Repository implements RepositoryInterface
1314
{
@@ -156,6 +157,10 @@ private function buildJoins(QueryBuilder $query, InspectedEntityInterface $entit
156157
continue;
157158
}
158159

160+
if ($join->getLazy() === JoinInterface::IS_LAZY) {
161+
continue;
162+
}
163+
159164
if ($join->getType() === 'inner' && $entity->getClass() === $join->getEntity()->getClass()) {
160165
continue;
161166
}
@@ -238,13 +243,13 @@ private function buildTree(array $row, InspectedEntityInterface $entity, string
238243
$tree = $row[$this->tableAliases[$tableKey]];
239244

240245
foreach ($entity->getJoins() as $join) {
241-
if ($join->getType() === 'inner' && $entity->getClass() !== $join->getEntity()->getClass()) {
246+
if ($join->getType() === 'inner' && $entity->getClass() !== $join->getEntity()->getClass() && $join->getLazy() === false) {
242247
$tree[$join->getProperty()] = $this->buildTree($row, $join->getEntity(), $join->getProperty());
243248

244249
continue;
245250
}
246251

247-
if ($join->getType() === 'inner' && $entity->getClass() === $join->getEntity()->getClass()) {
252+
if ($join->getType() === 'inner' && ($join->getLazy() === JoinInterface::IS_LAZY || $entity->getClass() === $join->getEntity()->getClass())) {
248253
$tree[$join->getProperty()] = new Promise(function (callable $resolve, callable $reject) use ($row, $join, $tableKey): void {
249254
foreach ($join->getClause() as $clause) {
250255
if ($row[$this->tableAliases[$tableKey]][$clause->getLocalKey()] === null) {

tests/FunctionalTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,38 @@ function (CommentStub $comment) {
164164
);
165165
}
166166

167+
/**
168+
* @test
169+
*/
170+
public function firstBlogPostNextBlogPostResolvesToBlogPost(): void
171+
{
172+
self::assertInstanceOf(
173+
BlogPostStub::class,
174+
$this->await(
175+
$this->client->getRepository(BlogPostStub::class)->fetch()->take(1)->toPromise()->then(function (BlogPostStub $blogPost) {
176+
return $blogPost->getNextBlogPost();
177+
}),
178+
$this->loop
179+
)
180+
);
181+
}
182+
183+
/**
184+
* @test
185+
*/
186+
public function firstBlogPostPreviousBlogPostResolvesToNull(): void
187+
{
188+
self::assertSame(
189+
null,
190+
$this->await(
191+
$this->client->getRepository(BlogPostStub::class)->fetch()->take(1)->toPromise()->then(function (BlogPostStub $blogPost) {
192+
return $blogPost->getPreviousBlogPost();
193+
}),
194+
$this->loop
195+
)
196+
);
197+
}
198+
167199
/**
168200
* @test
169201
*/

tests/Stub/BlogPostStub.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
foreign_key="blog_post_id",
2222
)
2323
},
24-
property="comments"
24+
property="comments",
25+
lazy=LeftJoin::IS_LAZY
2526
* )
2627
* @InnerJoin(
2728
entity=UserStub::class,
@@ -31,7 +32,8 @@
3132
foreign_key="id",
3233
)
3334
},
34-
property="author"
35+
property="author",
36+
lazy=InnerJoin::IS_NOT_LAZY
3537
* )
3638
* @InnerJoin(
3739
entity=UserStub::class,
@@ -41,7 +43,8 @@
4143
foreign_key="id",
4244
)
4345
},
44-
property="publisher"
46+
property="publisher",
47+
lazy=InnerJoin::IS_NOT_LAZY
4548
* )
4649
* @InnerJoin(
4750
entity=BlogPostStub::class,
@@ -51,7 +54,8 @@
5154
foreign_key="id",
5255
)
5356
},
54-
property="previous_blog_post"
57+
property="previous_blog_post",
58+
lazy=InnerJoin::IS_LAZY
5559
* )
5660
* @InnerJoin(
5761
entity=BlogPostStub::class,
@@ -61,7 +65,8 @@
6165
foreign_key="id",
6266
)
6367
},
64-
property="next_blog_post"
68+
property="next_blog_post",
69+
lazy=InnerJoin::IS_NOT_LAZY
6570
* )
6671
*/
6772
class BlogPostStub implements EntityInterface

0 commit comments

Comments
 (0)