Skip to content

Commit ef75504

Browse files
author
Andrii Sudiev
committed
revert to previous Prefetch behavior
1 parent ee84251 commit ef75504

File tree

10 files changed

+41
-137
lines changed

10 files changed

+41
-137
lines changed

src/Annotations/Prefetch.php

+2-8
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,8 @@
1010
#[Attribute(Attribute::TARGET_PARAMETER)]
1111
class Prefetch implements ParameterAnnotationInterface
1212
{
13-
/**
14-
* @param string|(callable&array{class-string, string}) $callable
15-
* @param bool $returnRequested return value mapped to requested method
16-
*/
17-
public function __construct(
18-
public readonly string|array $callable,
19-
public readonly bool $returnRequested = false,
20-
)
13+
/** @param string|(callable&array{class-string, string}) $callable */
14+
public function __construct(public readonly string|array $callable)
2115
{
2216
}
2317

src/Mappers/Parameters/PrefetchParameterMiddleware.php

-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock,
5252
fieldName: $method->getName(),
5353
resolver: $resolver,
5454
parameters: $parameters,
55-
returnRequested: $prefetch->returnRequested,
5655
);
5756
}
5857
}

src/Parameters/PrefetchDataParameter.php

+7-19
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use TheCodingMachine\GraphQLite\PrefetchBuffer;
1313
use TheCodingMachine\GraphQLite\QueryField;
1414

15-
use function array_key_exists;
1615
use function assert;
1716

1817
/**
@@ -28,7 +27,6 @@ public function __construct(
2827
private readonly string $fieldName,
2928
private readonly mixed $resolver,
3029
public readonly array $parameters,
31-
public readonly bool $returnRequested = false,
3230
)
3331
{
3432
}
@@ -59,7 +57,10 @@ public function resolve(object|null $source, array $args, mixed $context, Resolv
5957
$this->computePrefetch($args, $context, $info, $prefetchBuffer);
6058
}
6159

62-
return $prefetchBuffer->getResult($source);
60+
$result = $prefetchBuffer->getResult($source);
61+
// clear internal storage
62+
$prefetchBuffer->purgeResult($source);
63+
return $result;
6364
});
6465
}
6566

@@ -71,22 +72,9 @@ private function computePrefetch(array $args, mixed $context, ResolveInfo $info,
7172
$toPassPrefetchArgs = QueryField::paramsToArguments($this->fieldName, $this->parameters, null, $args, $context, $info, $this->resolver);
7273

7374
$resolvedValues = ($this->resolver)($sources, ...$toPassPrefetchArgs);
74-
if ($this->returnRequested) {
75-
foreach ($resolvedValues as $key => $resolvedValue) {
76-
if (! array_key_exists($key, $sources)) {
77-
throw new GraphQLRuntimeException(
78-
'Called by Prefetch function should accept ' .
79-
'Array<key> and return Array<value>, but the function did ' .
80-
'not return an Array of the same length as the Array of keys.',
81-
);
82-
}
83-
$prefetchBuffer->storeResult($sources[$key], $resolvedValue);
84-
}
85-
} else {
86-
foreach ($sources as $source) {
87-
// map results to each source to support old prefetch behavior
88-
$prefetchBuffer->storeResult($source, $resolvedValues);
89-
}
75+
foreach ($sources as $source) {
76+
// map results to each source to support old prefetch behavior
77+
$prefetchBuffer->storeResult($source, $resolvedValues);
9078
}
9179
}
9280

src/PrefetchBuffer.php

+6
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,10 @@ public function getResult(
8989
): mixed {
9090
return $this->results->offsetGet($source);
9191
}
92+
93+
public function purgeResult(
94+
object $source,
95+
): void {
96+
$this->results->offsetUnset($source);
97+
}
9298
}

src/QueryField.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,17 @@ public static function paramsToArguments(string $name, array $parameters, object
194194
*/
195195
public static function deferred(array $toPassArgs, Closure $callResolver): mixed
196196
{
197+
$deferredArgument = null;
197198
foreach ($toPassArgs as $position => $toPassArg) {
198199
if ($toPassArg instanceof SyncPromise) {
199-
return $toPassArg->then(static function ($resolvedValue) use ($toPassArgs, $position, $callResolver) {
200+
$deferredArgument = $toPassArg->then(static function ($resolvedValue) use ($toPassArgs, $position, $callResolver) {
200201
$toPassArgs[$position] = $resolvedValue;
201202
return self::deferred($toPassArgs, $callResolver);
202203
});
204+
break;
203205
}
204206
}
205-
return $callResolver(...$toPassArgs);
207+
208+
return $deferredArgument ?? $callResolver(...$toPassArgs);
206209
}
207210
}

tests/Fixtures/Integration/Models/Blog.php

+10-10
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,29 @@ public function getId(): int
2323
}
2424

2525
/**
26-
* @param Post[] $prefetchedPosts
26+
* @param Post[][] $prefetchedPosts
2727
*
2828
* @return Post[]
2929
*/
3030
#[Field]
3131
public function getPosts(
32-
#[Prefetch('prefetchPosts', true)]
32+
#[Prefetch('prefetchPosts')]
3333
array $prefetchedPosts,
3434
): array {
35-
return $prefetchedPosts;
35+
return $prefetchedPosts[$this->id];
3636
}
3737

3838
/**
39-
* @param Blog[] $prefetchedSubBlogs
39+
* @param Blog[][] $prefetchedSubBlogs
4040
*
4141
* @return Blog[]
4242
*/
4343
#[Field]
4444
public function getSubBlogs(
45-
#[Prefetch('prefetchSubBlogs', true)]
45+
#[Prefetch('prefetchSubBlogs')]
4646
array $prefetchedSubBlogs,
4747
): array {
48-
return $prefetchedSubBlogs;
48+
return $prefetchedSubBlogs[$this->id];
4949
}
5050

5151
/**
@@ -56,9 +56,9 @@ public function getSubBlogs(
5656
public static function prefetchPosts(iterable $blogs): array
5757
{
5858
$posts = [];
59-
foreach ($blogs as $key => $blog) {
59+
foreach ($blogs as $blog) {
6060
$blogId = $blog->getId();
61-
$posts[$key] = [
61+
$posts[$blog->getId()] = [
6262
new Post('post-' . $blogId . '.1'),
6363
new Post('post-' . $blogId . '.2'),
6464
];
@@ -75,10 +75,10 @@ public static function prefetchPosts(iterable $blogs): array
7575
public static function prefetchSubBlogs(iterable $blogs): array
7676
{
7777
$subBlogs = [];
78-
foreach ($blogs as $key => $blog) {
78+
foreach ($blogs as $blog) {
7979
$blogId = $blog->getId();
8080
$subBlogId = $blogId * 10;
81-
$subBlogs[$key] = [new Blog($subBlogId)];
81+
$subBlogs[$blog->id] = [new Blog($subBlogId)];
8282
}
8383

8484
return $subBlogs;

tests/Fixtures/Integration/Types/CompanyType.php

-25
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,4 @@ public static function prefetchContacts(array $companies): array
4444

4545
return $contacts;
4646
}
47-
48-
#[Field]
49-
public function getContactRequested(
50-
Company $company,
51-
#[Prefetch('prefetchContactsExact', true)]
52-
Contact $contact,
53-
): Contact|null {
54-
return $contact;
55-
}
56-
57-
/**
58-
* @param Company[] $companies
59-
*
60-
* @return Contact[]
61-
*/
62-
public static function prefetchContactsExact(array $companies): array
63-
{
64-
$contacts = [];
65-
66-
foreach ($companies as $key => $company) {
67-
$contacts[$key] = new Contact('Kate');
68-
}
69-
70-
return $contacts;
71-
}
7247
}

tests/Fixtures/Integration/Types/PostType.php

+9-6
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,17 @@ public function getTitle(Post $post): string
2929
}
3030

3131
/**
32-
* @param Comment[] $prefetchedComments
32+
* @param Comment[][] $prefetchedComments
3333
*
3434
* @return Comment[]
3535
*/
3636
#[Field]
3737
public function getComments(
3838
Post $post,
39-
#[Prefetch('prefetchComments', true)]
39+
#[Prefetch('prefetchComments')]
4040
array $prefetchedComments,
4141
): array {
42-
return $prefetchedComments;
42+
return $prefetchedComments[$post->title];
4343
}
4444

4545
/**
@@ -49,11 +49,14 @@ public function getComments(
4949
*
5050
* @throws Exception
5151
*/
52-
public static function prefetchComments(array $posts): iterable
52+
public static function prefetchComments(array $posts): Promise
5353
{
5454
$syncPromiseAdapter = new SyncPromiseAdapter();
55-
foreach ($posts as $key => $post) {
56-
yield $key => $syncPromiseAdapter->createFulfilled([new Comment('comment for ' . $post->title)]);
55+
$result = [];
56+
foreach ($posts as $post) {
57+
$result[$post->title] = [new Comment('comment for ' . $post->title)];
5758
}
59+
60+
return $syncPromiseAdapter->createFulfilled($result);
5861
}
5962
}

tests/Parameters/PrefetchDataParameterTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function testResolveWithoutExistingResult(): void
7171
self::assertFalse($buffer->hasResult($source));
7272
self::assertSame([$source], $buffer->getObjectsByArguments($args));
7373
self::assertSame($prefetchResult, $this->deferredValue($resolvedParameterPromise));
74-
self::assertTrue($buffer->hasResult($source));
74+
self::assertFalse($buffer->hasResult($source));
7575
}
7676

7777
private function deferredValue(Deferred $promise): mixed

website/docs/prefetch-method.mdx

+1-65
Original file line numberDiff line numberDiff line change
@@ -52,83 +52,19 @@ class PostType {
5252
{
5353
// This method will receive the $prefetchedUsers as first argument. This is the return value of the "prefetchUsers" method below.
5454
// Using this prefetched list, it should be easy to map it to the post
55-
return $prefetchedUsers[$this->getUserId()];
5655
}
5756

5857
/**
5958
* @param Post[] $posts
6059
* @return mixed
6160
*/
62-
public static function prefetchUsers(iterable $posts, #[Autowire] UserProvider $loader)
61+
public static function prefetchUsers(iterable $posts)
6362
{
6463
// This function is called only once per GraphQL request
6564
// with the list of posts. You can fetch the list of users
6665
// associated with this posts in a single request,
6766
// for instance using a "IN" query in SQL or a multi-fetch
6867
// in your cache back-end.
69-
$userIds = [];
70-
foreach($posts as $post){
71-
$userIds[] = $post->getUserId();
72-
}
73-
return $loader->loadMany($userIds)
74-
}
75-
}
76-
```
77-
78-
When a `#[Prefetch]` attribute is constructed with returnRequested: true $prefetchedUser argument will be the mapped
79-
value resolved for concrete PostType, so you dont need to extract value from prefetched values
80-
81-
```php
82-
#[Type]
83-
class PostType {
84-
/**
85-
* @param User $prefetchedUser
86-
* @return User
87-
*/
88-
#[Field]
89-
public function getUser(#[Prefetch("prefetchUsers", returnRequested: true)] $prefetchedUser): User
90-
{
91-
return $prefetchedUser;
92-
}
93-
94-
/**
95-
* @param Post[] $posts
96-
* @return iterable
97-
*/
98-
public static function prefetchUsers(iterable $posts): iterable
99-
{
100-
foreach($posts as $post){
101-
yield new User(...);
102-
}
103-
}
104-
}
105-
```
106-
107-
108-
`#[Prefetch('prefetchUsers', true)]` callable can also return Promise[], so you can use for example Overblog DataLoader
109-
110-
```php
111-
#[Type]
112-
class PostType {
113-
/**
114-
* @param User $prefetchedUser
115-
* @return User
116-
*/
117-
#[Field]
118-
public function getUser(#[Prefetch("prefetchUsers", returnRequested: true)] $prefetchedUser): User
119-
{
120-
return $prefetchedUser;
121-
}
122-
123-
/**
124-
* @param Post[] $posts
125-
* @return iterable
126-
*/
127-
public static function prefetchUsers(iterable $posts, #[Autowire] DataLoader $dataloader): iterable
128-
{
129-
foreach($posts as $post){
130-
yield $dataloader->load($post->getId());
131-
}
13268
}
13369
}
13470
```

0 commit comments

Comments
 (0)