Skip to content

Commit 79185ec

Browse files
authored
Turn direct inner joins on the same class into promise wrapped lo… (#10)
Turn direct inner joins on the same class into promise wrapped look ups
2 parents 5ceba9a + 6561f90 commit 79185ec

File tree

7 files changed

+120
-3
lines changed

7 files changed

+120
-3
lines changed

etc/db/migrations/20190327192030_InitialMigration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public function change(): void
1515

1616
$this->table('blog_posts', ['id' => false, 'primary_key' => ['id']])
1717
->addColumn('id', 'uuid')
18+
->addColumn('previous_blog_post_id', 'uuid', ['null' => true])
19+
->addColumn('next_blog_post_id', 'uuid', ['null' => true])
1820
->addColumn('author_id', 'uuid')
1921
->addColumn('publisher_id', 'uuid')
2022
->addColumn('title', 'string')

etc/db/seeds/BlogPostsSeed.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public function run(): void
88
$data = [
99
[
1010
'id' => '53ab5832-9a90-4e6e-988b-06b8b5fed763',
11+
'previous_blog_post_id' => null,
12+
'next_blog_post_id' => '090fa83b-5c5a-4042-9f05-58d9ab649a1a',
1113
'author_id' => 'fb175cbc-04cc-41c7-8e35-6b817ac016ca',
1214
'publisher_id' => 'fb175cbc-04cc-41c7-8e35-6b817ac016ca',
1315
'title' => 'Cats!',
@@ -18,6 +20,8 @@ public function run(): void
1820
],
1921
[
2022
'id' => '090fa83b-5c5a-4042-9f05-58d9ab649a1a',
23+
'previous_blog_post_id' => '53ab5832-9a90-4e6e-988b-06b8b5fed763',
24+
'next_blog_post_id' => null,
2125
'author_id' => '15f25357-4b3d-4d4d-b6a5-2ceb93864b77',
2226
'publisher_id' => '15f25357-4b3d-4d4d-b6a5-2ceb93864b77',
2327
'title' => 'Moar Cats!',

src/Repository.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Plasma\SQL\QueryBuilder;
66
use Ramsey\Uuid\Uuid;
7+
use React\Promise\Promise;
78
use React\Promise\PromiseInterface;
89
use Rx\Observable;
910
use Rx\Scheduler\ImmediateScheduler;
@@ -155,6 +156,10 @@ private function buildJoins(QueryBuilder $query, InspectedEntityInterface $entit
155156
continue;
156157
}
157158

159+
if ($join->getType() === 'inner' && $entity->getClass() === $join->getEntity()->getClass()) {
160+
continue;
161+
}
162+
158163
$tableKey = \spl_object_hash($join->getEntity()) . '___' . $join->getProperty();
159164
if (!isset($this->tableAliases[$tableKey])) {
160165
$this->tableAliases[$tableKey] = 't' . $i++;
@@ -225,12 +230,40 @@ private function buildTree(array $row, InspectedEntityInterface $entity, string
225230
$tree = $row[$this->tableAliases[$tableKey]];
226231

227232
foreach ($entity->getJoins() as $join) {
228-
if ($join->getType() === 'inner') {
233+
if ($join->getType() === 'inner' && $entity->getClass() !== $join->getEntity()->getClass()) {
229234
$tree[$join->getProperty()] = $this->buildTree($row, $join->getEntity(), $join->getProperty());
230235

231236
continue;
232237
}
233238

239+
if ($join->getType() === 'inner' && $entity->getClass() === $join->getEntity()->getClass()) {
240+
$tree[$join->getProperty()] = new Promise(function (callable $resolve, callable $reject) use ($row, $join, $tableKey): void {
241+
if ($row[$this->tableAliases[$tableKey]][$join->getLocalKey()] === null) {
242+
$resolve(null);
243+
244+
return;
245+
}
246+
247+
$where = [];
248+
249+
$where[] = [
250+
$join->getForeignKey(),
251+
'=',
252+
$row[$this->tableAliases[$tableKey]][$join->getLocalKey()],
253+
];
254+
255+
$this->client
256+
->getRepository($join->getEntity()
257+
->getClass())
258+
->fetch($where)
259+
->take(1)
260+
->toPromise()
261+
->then($resolve, $reject);
262+
});
263+
264+
continue;
265+
}
266+
234267
$tree[$join->getProperty()] = Observable::defer(
235268
function () use ($row, $join, $tableKey) {
236269
$where = [];

tests/EntityInspectorTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ public function inspectWithJoins(): void
5454
self::assertSame('blog_posts', $inspectedEntity->getTable());
5555

5656
$fields = $inspectedEntity->getFields();
57-
self::assertCount(8, $fields);
57+
self::assertCount(10, $fields);
5858

5959
foreach ([
6060
'id' => 'string',
61+
'previous_blog_post_id' => 'string',
62+
'next_blog_post_id' => 'string',
6163
'author_id' => 'string',
6264
'title' => 'string',
6365
'contents' => 'string',
@@ -70,7 +72,7 @@ public function inspectWithJoins(): void
7072
}
7173

7274
$joins = $inspectedEntity->getJoins();
73-
self::assertCount(3, $joins);
75+
self::assertCount(5, $joins);
7476

7577
self::assertArrayHasKey('author', $joins);
7678
self::assertSame(UserStub::class, $joins['author']->getEntity()->getClass());

tests/FunctionalTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,44 @@ function (CommentStub $comment) {
227227
);
228228
}
229229

230+
/**
231+
* @test
232+
*/
233+
public function secondBlogPostPreviousBlogPostAuthorId(): void
234+
{
235+
self::assertSame(
236+
'fb175cbc-04cc-41c7-8e35-6b817ac016ca',
237+
$this->await(
238+
$this->client->getRepository(BlogPostStub::class)->fetch()->filter(function (BlogPostStub $blogPost): bool {
239+
return $blogPost->getId() === '090fa83b-5c5a-4042-9f05-58d9ab649a1a';
240+
})->toPromise()->then(function (BlogPostStub $blogPost) {
241+
return $blogPost->getPreviousBlogPost();
242+
})->then(function (BlogPostStub $blogPost) {
243+
return $blogPost->getAuthor()->getId();
244+
}),
245+
$this->loop
246+
)
247+
);
248+
}
249+
250+
/**
251+
* @test
252+
*/
253+
public function secondBlogPostNextBlogPostResolvesToNull(): void
254+
{
255+
self::assertSame(
256+
null,
257+
$this->await(
258+
$this->client->getRepository(BlogPostStub::class)->fetch()->filter(function (BlogPostStub $blogPost): bool {
259+
return $blogPost->getId() === '090fa83b-5c5a-4042-9f05-58d9ab649a1a';
260+
})->toPromise()->then(function (BlogPostStub $blogPost) {
261+
return $blogPost->getNextBlogPost();
262+
}),
263+
$this->loop
264+
)
265+
);
266+
}
267+
230268
/**
231269
* @test
232270
*/

tests/HydratorTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use function ApiClients\Tools\Rx\observableFromArray;
66
use Doctrine\Common\Annotations\AnnotationReader;
7+
use function React\Promise\resolve;
78
use WyriHaximus\React\SimpleORM\EntityInspector;
89
use WyriHaximus\React\SimpleORM\Hydrator;
910
use WyriHaximus\React\Tests\SimpleORM\Stub\BlogPostStub;
@@ -47,6 +48,8 @@ public function testHydrateWithJoins(): void
4748
(new EntityInspector(new AnnotationReader()))->getEntity(BlogPostStub::class),
4849
[
4950
'id' => $id,
51+
'previous_blog_post' => resolve(null),
52+
'next_blog_post' => resolve(null),
5053
'title' => $title,
5154
'author' => [
5255
'id' => $authorId,

tests/Stub/BlogPostStub.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace WyriHaximus\React\Tests\SimpleORM\Stub;
44

5+
use React\Promise\PromiseInterface;
56
use Rx\Observable;
67
use WyriHaximus\React\SimpleORM\Annotation\InnerJoin;
78
use WyriHaximus\React\SimpleORM\Annotation\LeftJoin;
@@ -29,12 +30,36 @@
2930
foreign_key="id",
3031
property="publisher"
3132
* )
33+
* @InnerJoin(
34+
entity=BlogPostStub::class,
35+
local_key="previous_blog_post_id",
36+
foreign_key="id",
37+
property="previous_blog_post"
38+
* )
39+
* @InnerJoin(
40+
entity=BlogPostStub::class,
41+
local_key="next_blog_post_id",
42+
foreign_key="id",
43+
property="next_blog_post"
44+
* )
3245
*/
3346
class BlogPostStub implements EntityInterface
3447
{
3548
/** @var string */
3649
protected $id;
3750

51+
/** @var string|null */
52+
protected $previous_blog_post_id;
53+
54+
/** @var PromiseInterface */
55+
protected $previous_blog_post;
56+
57+
/** @var string|null */
58+
protected $next_blog_post_id;
59+
60+
/** @var PromiseInterface */
61+
protected $next_blog_post;
62+
3863
/** @var string */
3964
protected $author_id;
4065

@@ -70,6 +95,16 @@ public function getId(): string
7095
return $this->id;
7196
}
7297

98+
public function getPreviousBlogPost(): PromiseInterface
99+
{
100+
return $this->previous_blog_post;
101+
}
102+
103+
public function getNextBlogPost(): PromiseInterface
104+
{
105+
return $this->next_blog_post;
106+
}
107+
73108
public function getAuthor(): UserStub
74109
{
75110
return $this->author;

0 commit comments

Comments
 (0)