Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL::type modifier support #621

Merged
merged 1 commit into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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