Skip to content

Commit

Permalink
GraphQL::type modifier and standard type support
Browse files Browse the repository at this point in the history
  • Loading branch information
stevelacey committed Apr 6, 2020
1 parent ffe0cb9 commit a28a2f3
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ CHANGELOG
- Support Laravel 7 [\#597 / exodusanto](https://github.com/rebing/graphql-laravel/pull/597)
- Add support for custom authorization message [\#578 / Sh1d0w](https://github.com/rebing/graphql-laravel/pull/578)
- Add support for macros on the GraphQL service/facade [\#592 / stevelacey](https://github.com/rebing/graphql-laravel/pull/592)
- Add support for modifiers to `GraphQL::type` [\#621 / stevelacey](https://github.com/rebing/graphql-laravel/pull/621)
### Fixed
- 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)
- Fix selecting not the correct columns for interface fields [\#607 / illambo](https://github.com/rebing/graphql-laravel/pull/607)
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ To work this around:
- [Interfaces](#interfaces)
- [Sharing interface fields](#sharing-interface-fields)
- [Input Object](#input-object)
- [Type modifiers](#type-modifiers)
- [Field and input alias](#field-and-input-alias)
- [JSON columns](#json-columns)
- [Field deprecation](#field-deprecation)
Expand Down Expand Up @@ -1656,6 +1657,24 @@ class TestMutation extends GraphQLType {
}
```

### Type modifiers

Type modifiers can be applied by wrapping your chosen type in `Type::nonNull` or `Type::listOf` calls
or alternatively you can use the shorthand syntax available via `GraphQL::type` to build up more complex
types.

```php
GraphQL::type('MyInput!');
GraphQL::type('[MyInput]');
GraphQL::type('[MyInput]!');
GraphQL::type('[MyInput!]!');

GraphQL::type('String!');
GraphQL::type('[String]');
GraphQL::type('[String]!');
GraphQL::type('[String!]!');
```

### Field and input alias

It is possible to alias query and mutation arguments as well as input object fields.
Expand Down
31 changes: 31 additions & 0 deletions src/GraphQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,37 @@ public function addType($class, string $name = null): void

public function type(string $name, bool $fresh = false): Type
{
$modifiers = [];

while (true) {
if (preg_match('/^(.+)!$/', $name, $matches)) {
$name = $matches[1];
array_unshift($modifiers, 'nonNull');
} elseif (preg_match('/^\[(.+)\]$/', $name, $matches)) {
$name = $matches[1];
array_unshift($modifiers, 'listOf');
} else {
break;
}
}

$type = $this->getType($name, $fresh);

foreach ($modifiers as $modifier) {
$type = Type::$modifier($type);
}

return $type;
}

public function getType(string $name, bool $fresh = false): Type
{
$standardTypes = Type::getStandardTypes();

if (in_array($name, $standardTypes)) {
return $standardTypes[$name];
}

if (! isset($this->types[$name])) {
$error = "Type $name not found.";

Expand Down
188 changes: 188 additions & 0 deletions tests/Unit/GraphQLTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace Rebing\GraphQL\Tests\Unit;

use GraphQL\Error\Error;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
Expand Down Expand Up @@ -123,6 +125,192 @@ public function testWrongType(): void
GraphQL::type('ExampleWrong');
}

/**
* Test nonNull type.
*/
public function testNonNullType(): void
{
/** @var NonNull */
$type = GraphQL::type('Example!');
$this->assertInstanceOf(NonNull::class, $type);

/** @var NonNull */
$typeOther = GraphQL::type('Example!');
$this->assertTrue($type->getWrappedType() === $typeOther->getWrappedType());

/** @var NonNull */
$typeOther = GraphQL::type('Example!', true);
$this->assertFalse($type->getWrappedType() === $typeOther->getWrappedType());
}

/**
* Test listOf type.
*/
public function testListOfType(): void
{
/** @var ListOfType */
$type = GraphQL::type('[Example]');
$this->assertInstanceOf(ListOfType::class, $type);

/** @var ListOfType */
$typeOther = GraphQL::type('[Example]');
$this->assertTrue($type->getWrappedType() === $typeOther->getWrappedType());

/** @var ListOfType */
$typeOther = GraphQL::type('[Example]', true);
$this->assertFalse($type->getWrappedType() === $typeOther->getWrappedType());
}

/**
* Test listOf nonNull type.
*/
public function testListOfNonNullType(): void
{
/** @var ListOfType */
$type = GraphQL::type('[Example!]');
$this->assertInstanceOf(ListOfType::class, $type);
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());

/** @var ListOfType */
$typeOther = GraphQL::type('[Example!]');
$this->assertTrue($type->getWrappedType(true) === $typeOther->getWrappedType(true));

/** @var ListOfType */
$typeOther = GraphQL::type('[Example!]', true);
$this->assertFalse($type->getWrappedType(true) === $typeOther->getWrappedType(true));
}

/**
* Test nonNull listOf nonNull type.
*/
public function testNonNullListOfNonNullType(): void
{
/** @var NonNull */
$type = GraphQL::type('[Example!]!');
/** @var ListOfType */
$wrappedType = $type->getWrappedType();

$this->assertInstanceOf(NonNull::class, $type);
$this->assertInstanceOf(ListOfType::class, $wrappedType);
$this->assertInstanceOf(NonNull::class, $wrappedType->getWrappedType());

/** @var NonNull */
$typeOther = GraphQL::type('[Example!]!');
$this->assertTrue($type->getWrappedType(true) === $typeOther->getWrappedType(true));

/** @var NonNull */
$typeOther = GraphQL::type('[Example!]!', true);
$this->assertFalse($type->getWrappedType(true) === $typeOther->getWrappedType(true));
}

/**
* Test malformed listOf with no leading bracket.
*/
public function testMalformedListOfWithNoLeadingBracket(): void
{
$this->expectException(TypeNotFound::class);
$this->expectExceptionMessage('Type Example] not found.');
GraphQL::type('Example]');
}

/**
* Test malformed listOf with no trailing bracket.
*/
public function testMalformedListOfWithNoTrailingBracket(): void
{
$this->expectException(TypeNotFound::class);
$this->expectExceptionMessage('Type [Example not found.');
GraphQL::type('[Example');
}

/**
* Test malformed nonNull listOf with no trailing bracket.
*/
public function testMalformedNonNullListOfWithNoTrailingBracket(): void
{
$this->expectException(TypeNotFound::class);
$this->expectExceptionMessage('Type [Example not found.');
GraphQL::type('[Example!');
}

/**
* Test empty listOfType.
*/
public function testEmptyListOfType(): void
{
$this->expectException(TypeNotFound::class);
$this->expectExceptionMessage('Type [] not found.');
GraphQL::type('[]');
}

/**
* Test empty nonNull.
*/
public function testEmptyNonNull(): void
{
$this->expectException(TypeNotFound::class);
$this->expectExceptionMessage('Type ! not found.');
GraphQL::type('!');
}

/**
* Test standard types.
*/
public function testStandardTypes(): void
{
$standardTypes = Type::getStandardTypes();

foreach ($standardTypes as $standardType) {
$type = GraphQL::type($standardType->name);
$this->assertTrue($standardType === $type);

$typeOther = GraphQL::type($type->name);
$this->assertTrue($type === $typeOther);

$typeOther = GraphQL::type($type->name, true);
$this->assertTrue($type === $typeOther);
}
}

/**
* Test standard type modifiers.
*/
public function testStandardTypeModifiers(): void
{
$standardTypes = Type::getStandardTypes();

foreach ($standardTypes as $standardType) {
/** @var NonNull */
$type = GraphQL::type("$standardType->name!");

$this->assertInstanceOf(NonNull::class, $type);
$this->assertTrue($type->getWrappedType() === $standardType);

/** @var ListOfType */
$type = GraphQL::type("[$standardType->name]");

$this->assertInstanceOf(ListOfType::class, $type);
$this->assertTrue($type->getWrappedType() === $standardType);

/** @var ListOfType */
$type = GraphQL::type("[$standardType->name!]");

$this->assertInstanceOf(ListOfType::class, $type);
$this->assertInstanceOf(NonNull::class, $type->getWrappedType());
$this->assertTrue($type->getWrappedType(true) === $standardType);

/** @var NonNull */
$type = GraphQL::type("[$standardType->name!]!");
/** @var ListOfType */
$wrappedType = $type->getWrappedType();

$this->assertInstanceOf(NonNull::class, $type);
$this->assertInstanceOf(ListOfType::class, $wrappedType);
$this->assertInstanceOf(NonNull::class, $wrappedType->getWrappedType());
$this->assertTrue($type->getWrappedType(true) === $standardType);
}
}

/**
* Test objectType.
*/
Expand Down

0 comments on commit a28a2f3

Please sign in to comment.