Skip to content

Commit fbb75d3

Browse files
authored
Add a "defaultValue" to the resolver builder. (#941)
1 parent e4d3b30 commit fbb75d3

3 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace Drupal\graphql\GraphQL\Resolver;
4+
5+
use Drupal\graphql\GraphQL\Execution\FieldContext;
6+
use Drupal\graphql\GraphQL\Execution\ResolveContext;
7+
use Drupal\graphql\GraphQL\Utility\DeferredUtility;
8+
use GraphQL\Deferred;
9+
use GraphQL\Type\Definition\ResolveInfo;
10+
11+
/**
12+
* Default value resolver.
13+
*
14+
* Allows to fall back if a value is NULL.
15+
*/
16+
class DefaultValue implements ResolverInterface {
17+
18+
/**
19+
* The initial value.
20+
*
21+
* @var \Drupal\graphql\GraphQL\Resolver\ResolverInterface
22+
*/
23+
protected $value;
24+
25+
/**
26+
* The fallback value in case the initial value resolves to NULL.
27+
*
28+
* @var \Drupal\graphql\GraphQL\Resolver\ResolverInterface
29+
*/
30+
protected $default;
31+
32+
33+
/**
34+
* DefaultValue constructor.
35+
*
36+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface $value
37+
* The initial value to check.
38+
* @param \Drupal\graphql\GraphQL\Resolver\ResolverInterface $default
39+
* The fallback value returned if the initial one resolves to NULL.
40+
*/
41+
public function __construct(ResolverInterface $value, ResolverInterface $default) {
42+
$this->value = $value;
43+
$this->default = $default;
44+
}
45+
46+
47+
/**
48+
* {@inheritDoc}
49+
*/
50+
public function resolve(
51+
$value,
52+
$args,
53+
ResolveContext $context,
54+
ResolveInfo $info,
55+
FieldContext $field
56+
) {
57+
$result = $this->value->resolve($value, $args, $context, $info, $field);
58+
if ($result === NULL) {
59+
return $this->default->resolve($value, $args, $context, $info, $field);
60+
}
61+
62+
if ($result instanceof Deferred) {
63+
return DeferredUtility::returnFinally($result, function ($current) use ($value, $args, $context, $info, $field) {
64+
if ($current === NULL) {
65+
return $this->default->resolve($value, $args, $context, $info, $field);
66+
}
67+
return $current;
68+
});
69+
}
70+
return $result;
71+
}
72+
}

src/GraphQL/ResolverBuilder.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Drupal\graphql\GraphQL\Resolver\Composite;
99
use Drupal\graphql\GraphQL\Resolver\Condition;
1010
use Drupal\graphql\GraphQL\Resolver\Context;
11+
use Drupal\graphql\GraphQL\Resolver\DefaultValue;
1112
use Drupal\graphql\GraphQL\Resolver\Map;
1213
use Drupal\graphql\GraphQL\Resolver\ParentValue;
1314
use Drupal\graphql\GraphQL\Resolver\Path;
@@ -134,4 +135,14 @@ public function fromContext($name, $default = NULL) {
134135
return new Context($name, $default);
135136
}
136137

138+
/**
139+
* @param $value
140+
* @param $default
141+
*
142+
* @return \Drupal\graphql\GraphQL\Resolver\DefaultValue
143+
*/
144+
public function defaultValue($value, $default) {
145+
return new DefaultValue($value, $default);
146+
}
147+
137148
}

tests/src/Kernel/ResolverBuilderTest.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,28 @@ public function testCompose() {
195195
$this->assertResults($query, [], ['tree' => ['name' => 'SOME TREE NAME']]);
196196
}
197197

198+
/**
199+
* @covers ::compose
200+
*/
201+
public function testComposeNullValue() {
202+
$this->mockResolver('Query', 'tree', $this->builder->fromValue(['name' => 'some tree', 'id' => 5]));
203+
$this->mockResolver('Tree', 'name', $this->builder->compose(
204+
$this->builder->fromValue(NULL),
205+
$this->builder->produce('uppercase')
206+
->map('string', $this->builder->fromParent())
207+
));
208+
209+
$query = <<<GQL
210+
query {
211+
tree {
212+
name
213+
}
214+
}
215+
GQL;
216+
217+
$this->assertResults($query, [], ['tree' => ['name' => NULL]]);
218+
}
219+
198220
/**
199221
* @covers ::context
200222
* @covers ::fromContext
@@ -287,5 +309,105 @@ public function testParentCond() {
287309

288310
$this->assertResults($query, [], ['tree' => ['name' => 'But this should.']]);
289311
}
312+
313+
/**
314+
* @covers ::defaultValue
315+
*/
316+
public function testSimpleDefaultValue() {
317+
$this->mockResolver('Query', 'tree', ['name' => 'some tree', 'id' => 5]);
318+
$this->mockResolver('Tree', 'name', $this->builder->defaultValue(
319+
$this->builder->fromValue(NULL),
320+
$this->builder->fromValue('bar')
321+
));
322+
323+
$this->mockResolver('Tree', 'uri', $this->builder->defaultValue(
324+
$this->builder->fromValue('baz'),
325+
$this->builder->fromValue('bar')
326+
));
327+
328+
$query = <<<GQL
329+
query {
330+
tree(id: 1) {
331+
name
332+
uri
333+
}
334+
}
335+
GQL;
336+
337+
$this->assertResults($query, [], [
338+
'tree' => [
339+
'name' => 'bar',
340+
'uri' => 'baz',
341+
]
342+
]);
343+
}
344+
345+
public function testCompositeDefaultValue() {
346+
347+
$this->mockResolver('Query', 'tree', ['name' => 'some tree', 'id' => 5]);
348+
$this->mockResolver('Tree', 'name', $this->builder->defaultValue(
349+
$this->builder->compose(
350+
$this->builder->fromValue('baz'),
351+
$this->builder->fromValue(NULL)
352+
),
353+
$this->builder->fromValue('bar')
354+
));
355+
356+
$this->mockResolver('Tree', 'uri', $this->builder->defaultValue(
357+
$this->builder->compose(
358+
$this->builder->fromValue(TRUE),
359+
$this->builder->fromValue('baz')
360+
),
361+
$this->builder->fromValue('bar')
362+
));
363+
364+
$query = <<<GQL
365+
query {
366+
tree(id: 1) {
367+
name
368+
uri
369+
}
370+
}
371+
GQL;
372+
373+
$this->assertResults($query, [], [
374+
'tree' => [
375+
'name' => 'bar',
376+
'uri' => 'baz',
377+
]
378+
]);
379+
}
380+
381+
/**
382+
* @covers ::defaultValue
383+
*/
384+
public function testDeferredDefaultValue() {
385+
$this->mockResolver('Query', 'tree', ['name' => 'some tree', 'id' => 5]);
386+
$this->mockResolver('Tree', 'name', $this->builder->defaultValue(
387+
$this->builder->callback(function () { return new Deferred(function () { return NULL; }); }),
388+
$this->builder->callback(function () { return new Deferred(function () { return 'bar'; }); })
389+
));
390+
391+
$this->mockResolver('Tree', 'uri', $this->builder->defaultValue(
392+
$this->builder->callback(function () { return new Deferred(function () { return 'baz'; }); }),
393+
$this->builder->callback(function () { return new Deferred(function () { return 'bar'; }); })
394+
));
395+
396+
$query = <<<GQL
397+
query {
398+
tree(id: 1) {
399+
name
400+
uri
401+
}
402+
}
403+
GQL;
404+
405+
$this->assertResults($query, [], [
406+
'tree' => [
407+
'name' => 'bar',
408+
'uri' => 'baz',
409+
]
410+
]);
411+
}
290412
}
291413

0 commit comments

Comments
 (0)