Skip to content

Commit 10fca17

Browse files
stevelaceymfn
authored andcommitted
GraphQL::type modifier and standard type support
1 parent ffe0cb9 commit 10fca17

File tree

4 files changed

+239
-0
lines changed

4 files changed

+239
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
- Support Laravel 7 [\#597 / exodusanto](https://github.com/rebing/graphql-laravel/pull/597)
1111
- Add support for custom authorization message [\#578 / Sh1d0w](https://github.com/rebing/graphql-laravel/pull/578)
1212
- Add support for macros on the GraphQL service/facade [\#592 / stevelacey](https://github.com/rebing/graphql-laravel/pull/592)
13+
- Add support for modifiers to `GraphQL::type` [\#621 / stevelacey](https://github.com/rebing/graphql-laravel/pull/621)
1314
### Fixed
1415
- Fix the infinite loop as well as sending the correct matching input data to the rule-callback [\#579 / crissi](https://github.com/rebing/graphql-laravel/pull/579)
1516
- Fix selecting not the correct columns for interface fields [\#607 / illambo](https://github.com/rebing/graphql-laravel/pull/607)

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ To work this around:
129129
- [Interfaces](#interfaces)
130130
- [Sharing interface fields](#sharing-interface-fields)
131131
- [Input Object](#input-object)
132+
- [Type modifiers](#type-modifiers)
132133
- [Field and input alias](#field-and-input-alias)
133134
- [JSON columns](#json-columns)
134135
- [Field deprecation](#field-deprecation)
@@ -1656,6 +1657,24 @@ class TestMutation extends GraphQLType {
16561657
}
16571658
```
16581659

1660+
### Type modifiers
1661+
1662+
Type modifiers can be applied by wrapping your chosen type in `Type::nonNull` or `Type::listOf` calls
1663+
or alternatively you can use the shorthand syntax available via `GraphQL::type` to build up more complex
1664+
types.
1665+
1666+
```php
1667+
GraphQL::type('MyInput!');
1668+
GraphQL::type('[MyInput]');
1669+
GraphQL::type('[MyInput]!');
1670+
GraphQL::type('[MyInput!]!');
1671+
1672+
GraphQL::type('String!');
1673+
GraphQL::type('[String]');
1674+
GraphQL::type('[String]!');
1675+
GraphQL::type('[String!]!');
1676+
```
1677+
16591678
### Field and input alias
16601679

16611680
It is possible to alias query and mutation arguments as well as input object fields.

src/GraphQL.php

+31
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,37 @@ public function addType($class, string $name = null): void
175175

176176
public function type(string $name, bool $fresh = false): Type
177177
{
178+
$modifiers = [];
179+
180+
while (true) {
181+
if (preg_match('/^(.+)!$/', $name, $matches)) {
182+
$name = $matches[1];
183+
array_unshift($modifiers, 'nonNull');
184+
} elseif (preg_match('/^\[(.+)]$/', $name, $matches)) {
185+
$name = $matches[1];
186+
array_unshift($modifiers, 'listOf');
187+
} else {
188+
break;
189+
}
190+
}
191+
192+
$type = $this->getType($name, $fresh);
193+
194+
foreach ($modifiers as $modifier) {
195+
$type = Type::$modifier($type);
196+
}
197+
198+
return $type;
199+
}
200+
201+
public function getType(string $name, bool $fresh = false): Type
202+
{
203+
$standardTypes = Type::getStandardTypes();
204+
205+
if (in_array($name, $standardTypes)) {
206+
return $standardTypes[$name];
207+
}
208+
178209
if (! isset($this->types[$name])) {
179210
$error = "Type $name not found.";
180211

tests/Unit/GraphQLTest.php

+188
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace Rebing\GraphQL\Tests\Unit;
66

77
use GraphQL\Error\Error;
8+
use GraphQL\Type\Definition\ListOfType;
9+
use GraphQL\Type\Definition\NonNull;
810
use GraphQL\Type\Definition\ObjectType;
911
use GraphQL\Type\Definition\Type;
1012
use GraphQL\Type\Schema;
@@ -123,6 +125,192 @@ public function testWrongType(): void
123125
GraphQL::type('ExampleWrong');
124126
}
125127

128+
/**
129+
* Test nonNull type.
130+
*/
131+
public function testNonNullType(): void
132+
{
133+
/** @var NonNull */
134+
$type = GraphQL::type('Example!');
135+
$this->assertInstanceOf(NonNull::class, $type);
136+
137+
/** @var NonNull */
138+
$typeOther = GraphQL::type('Example!');
139+
$this->assertTrue($type->getWrappedType() === $typeOther->getWrappedType());
140+
141+
/** @var NonNull */
142+
$typeOther = GraphQL::type('Example!', true);
143+
$this->assertFalse($type->getWrappedType() === $typeOther->getWrappedType());
144+
}
145+
146+
/**
147+
* Test listOf type.
148+
*/
149+
public function testListOfType(): void
150+
{
151+
/** @var ListOfType */
152+
$type = GraphQL::type('[Example]');
153+
$this->assertInstanceOf(ListOfType::class, $type);
154+
155+
/** @var ListOfType */
156+
$typeOther = GraphQL::type('[Example]');
157+
$this->assertTrue($type->getWrappedType() === $typeOther->getWrappedType());
158+
159+
/** @var ListOfType */
160+
$typeOther = GraphQL::type('[Example]', true);
161+
$this->assertFalse($type->getWrappedType() === $typeOther->getWrappedType());
162+
}
163+
164+
/**
165+
* Test listOf nonNull type.
166+
*/
167+
public function testListOfNonNullType(): void
168+
{
169+
/** @var ListOfType */
170+
$type = GraphQL::type('[Example!]');
171+
$this->assertInstanceOf(ListOfType::class, $type);
172+
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());
173+
174+
/** @var ListOfType */
175+
$typeOther = GraphQL::type('[Example!]');
176+
$this->assertTrue($type->getWrappedType(true) === $typeOther->getWrappedType(true));
177+
178+
/** @var ListOfType */
179+
$typeOther = GraphQL::type('[Example!]', true);
180+
$this->assertFalse($type->getWrappedType(true) === $typeOther->getWrappedType(true));
181+
}
182+
183+
/**
184+
* Test nonNull listOf nonNull type.
185+
*/
186+
public function testNonNullListOfNonNullType(): void
187+
{
188+
/** @var NonNull */
189+
$type = GraphQL::type('[Example!]!');
190+
/** @var ListOfType */
191+
$wrappedType = $type->getWrappedType();
192+
193+
$this->assertInstanceOf(NonNull::class, $type);
194+
$this->assertInstanceOf(ListOfType::class, $wrappedType);
195+
$this->assertInstanceOf(NonNull::class, $wrappedType->getWrappedType());
196+
197+
/** @var NonNull */
198+
$typeOther = GraphQL::type('[Example!]!');
199+
$this->assertTrue($type->getWrappedType(true) === $typeOther->getWrappedType(true));
200+
201+
/** @var NonNull */
202+
$typeOther = GraphQL::type('[Example!]!', true);
203+
$this->assertFalse($type->getWrappedType(true) === $typeOther->getWrappedType(true));
204+
}
205+
206+
/**
207+
* Test malformed listOf with no leading bracket.
208+
*/
209+
public function testMalformedListOfWithNoLeadingBracket(): void
210+
{
211+
$this->expectException(TypeNotFound::class);
212+
$this->expectExceptionMessage('Type Example] not found.');
213+
GraphQL::type('Example]');
214+
}
215+
216+
/**
217+
* Test malformed listOf with no trailing bracket.
218+
*/
219+
public function testMalformedListOfWithNoTrailingBracket(): void
220+
{
221+
$this->expectException(TypeNotFound::class);
222+
$this->expectExceptionMessage('Type [Example not found.');
223+
GraphQL::type('[Example');
224+
}
225+
226+
/**
227+
* Test malformed nonNull listOf with no trailing bracket.
228+
*/
229+
public function testMalformedNonNullListOfWithNoTrailingBracket(): void
230+
{
231+
$this->expectException(TypeNotFound::class);
232+
$this->expectExceptionMessage('Type [Example not found.');
233+
GraphQL::type('[Example!');
234+
}
235+
236+
/**
237+
* Test empty listOfType.
238+
*/
239+
public function testEmptyListOfType(): void
240+
{
241+
$this->expectException(TypeNotFound::class);
242+
$this->expectExceptionMessage('Type [] not found.');
243+
GraphQL::type('[]');
244+
}
245+
246+
/**
247+
* Test empty nonNull.
248+
*/
249+
public function testEmptyNonNull(): void
250+
{
251+
$this->expectException(TypeNotFound::class);
252+
$this->expectExceptionMessage('Type ! not found.');
253+
GraphQL::type('!');
254+
}
255+
256+
/**
257+
* Test standard types.
258+
*/
259+
public function testStandardTypes(): void
260+
{
261+
$standardTypes = Type::getStandardTypes();
262+
263+
foreach ($standardTypes as $standardType) {
264+
$type = GraphQL::type($standardType->name);
265+
$this->assertTrue($standardType === $type);
266+
267+
$typeOther = GraphQL::type($type->name);
268+
$this->assertTrue($type === $typeOther);
269+
270+
$typeOther = GraphQL::type($type->name, true);
271+
$this->assertTrue($type === $typeOther);
272+
}
273+
}
274+
275+
/**
276+
* Test standard type modifiers.
277+
*/
278+
public function testStandardTypeModifiers(): void
279+
{
280+
$standardTypes = Type::getStandardTypes();
281+
282+
foreach ($standardTypes as $standardType) {
283+
/** @var NonNull */
284+
$type = GraphQL::type("$standardType->name!");
285+
286+
$this->assertInstanceOf(NonNull::class, $type);
287+
$this->assertTrue($type->getWrappedType() === $standardType);
288+
289+
/** @var ListOfType */
290+
$type = GraphQL::type("[$standardType->name]");
291+
292+
$this->assertInstanceOf(ListOfType::class, $type);
293+
$this->assertTrue($type->getWrappedType() === $standardType);
294+
295+
/** @var ListOfType */
296+
$type = GraphQL::type("[$standardType->name!]");
297+
298+
$this->assertInstanceOf(ListOfType::class, $type);
299+
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());
300+
$this->assertTrue($type->getWrappedType(true) === $standardType);
301+
302+
/** @var NonNull */
303+
$type = GraphQL::type("[$standardType->name!]!");
304+
/** @var ListOfType */
305+
$wrappedType = $type->getWrappedType();
306+
307+
$this->assertInstanceOf(NonNull::class, $type);
308+
$this->assertInstanceOf(ListOfType::class, $wrappedType);
309+
$this->assertInstanceOf(NonNull::class, $wrappedType->getWrappedType());
310+
$this->assertTrue($type->getWrappedType(true) === $standardType);
311+
}
312+
}
313+
126314
/**
127315
* Test objectType.
128316
*/

0 commit comments

Comments
 (0)