Skip to content

Commit

Permalink
handle relay mutations
Browse files Browse the repository at this point in the history
  • Loading branch information
chrissm79 committed Jun 2, 2016
1 parent c3483e3 commit 81c7946
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 11 deletions.
10 changes: 3 additions & 7 deletions src/Support/Definition/GraphQLField.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ public function getRules()
$arguments = func_get_args();
$args = $this->args();

if ($this instanceof RelayMutation) {
$args = $this->inputFields();
}

return collect($args)
->transform(function ($arg, $name) use ($arguments) {
if (isset($arg['rules'])) {
Expand All @@ -103,11 +99,11 @@ public function getRules()
*/
protected function getResolver()
{
if (!method_exists($this, 'resolve')) {
if (!method_exists($this, 'resolve') && !method_exists($this, 'relayResolve')) {
return null;
}

$resolver = array($this, 'resolve');
$resolver = method_exists($this, 'resolve') ? array($this, 'resolve') : array($this, 'relayResolve');

return function () use ($resolver) {
$arguments = func_get_args();
Expand Down Expand Up @@ -165,7 +161,7 @@ public static function field()
public function __get($key)
{
$attributes = $this->getAttributes();

return isset($attributes[$key]) ? $attributes[$key]:null;
}

Expand Down
112 changes: 111 additions & 1 deletion src/Support/Definition/GraphQLMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,117 @@

namespace Nuwave\Lighthouse\Support\Definition;

use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Support\Interfaces\RelayMutation;

class GraphQLMutation extends GraphQLField
{

/**
* Mutation id sent from client.
*
* @var integer|null
*/
protected $clientMutationId = null;

/**
* Generate Relay compliant output type.
*
* @return InputObjectType
*/
public function type()
{
if (! $this instanceof RelayMutation) {
return parent::type();
}

return new ObjectType([
'name' => ucfirst($this->attributes['name']) . 'Payload',
'fields' => array_merge($this->outputFields(), [
'clientMutationId' => [
'type' => Type::nonNull(Type::string()),
'resolve' => function () {
return $this->clientMutationId;
}
]
])
]);
}

/**
* Get the attributes of the field.
*
* @return array
*/
public function getAttributes()
{
if (! $this instanceof RelayMutation) {
return parent::getAttributes();
}

$attributes = array_merge($this->attributes, [
'args' => $this->relayArgs()
], $this->attributes());

$attributes['type'] = $this->type();
$attributes['resolve'] = $this->getResolver();

return $attributes;
}

/**
* Get list of relay arguments.
*
* @return array
*/
protected function relayArgs()
{
$inputType = new InputObjectType([
'name' => ucfirst($this->attributes['name'].'Input'),
'fields' => array_merge($this->args(), [
'clientMutationId' => [
'type' => Type::nonNull(Type::string()),
]
])
]);

return [
'input' => [
'type' => Type::nonNull($inputType)
]
];
}

/**
* Resolve mutation.
*
* @param mixed $_
* @param array $args
* @param ResolveInfo $info
* @return array
*/
public function relayResolve($_, $args, ResolveInfo $info)
{
if (isset($args['input']['id'])) {
$args['input']['relay_id'] = $args['input']['id'];
$args['input']['id'] = $this->decodeRelayId($args['input']['id']);
}

$this->clientMutationId = $args['input']['clientMutationId'];

return $this->mutateAndGetPayload($args['input'], $info);
}

/**
* Get input for validation.
*
* @param array $arguments
* @return array
*/
protected function getInput(array $arguments)
{
return array_get($arguments, '1.input', []);
}
}
130 changes: 130 additions & 0 deletions src/Support/Definition/RelayMutation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

namespace Nuwave\Relay\Support\Definition;

use Validator;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\InputObjectType;
use Nuwave\Lighthouse\Support\Exceptions\ValidationError;

abstract class RelayMutation extends GraphQLMutation
{
/**
* Type being mutated is RelayType.
*
* @var boolean
*/
protected $mutatesRelayType = true;

/**
* Mutation id sent from client.
*
* @var integer|null
*/
protected $clientMutationId = null;

/**
* Generate Relay compliant output type.
*
* @return InputObjectType
*/
public function type()
{
return new ObjectType([
'name' => ucfirst($this->name()) . 'Payload',
'fields' => array_merge($this->outputFields(), [
'clientMutationId' => [
'type' => Type::nonNull(Type::string()),
'resolve' => function () {
return $this->clientMutationId;
}
]
])
]);
}

/**
* Generate Relay compliant arguments.
*
* @return array
*/
public function args()
{
$inputType = new InputObjectType([
'name' => ucfirst($this->name()) . 'Input',
'fields' => array_merge($this->inputFields(), [
'clientMutationId' => [
'type' => Type::nonNull(Type::string())
]
])
]);
return [
'input' => [
'type' => Type::nonNull($inputType)
]
];
}

/**
* Resolve mutation.
*
* @param mixed $_
* @param array $args
* @param ResolveInfo $info
* @return array
*/
public function resolve($_, $args, ResolveInfo $info)
{
if ($this->mutatesRelayType && isset($args['input']['id'])) {
$args['input']['relay_id'] = $args['input']['id'];
$args['input']['id'] = $this->decodeRelayId($args['input']['id']);
}

$this->clientMutationId = $args['input']['clientMutationId'];

return $this->mutateAndGetPayload($args['input'], $info);
}

/**
* Get input for validation.
*
* @param array $arguments
* @return array
*/
protected function getInput(array $arguments)
{
return array_get($arguments, '1.input', []);
}

/**
* Perform mutation.
*
* @param array $input
* @param ResolveInfo $info
* @return array
*/
abstract protected function mutateAndGetPayload(array $input, ResolveInfo $info);

/**
* List of available input fields.
*
* @return array
*/
abstract protected function inputFields();

/**
* List of output fields.
*
* @return array
*/
abstract protected function outputFields();

/**
* Get name of mutation.
*
* @return string
*/
abstract protected function name();
}
24 changes: 24 additions & 0 deletions src/Support/Interfaces/RelayMutation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Nuwave\Lighthouse\Support\Interfaces;

use GraphQL\Type\Definition\ResolveInfo;

interface RelayMutation
{
/**
* List of output fields.
*
* @return array
*/
public function outputFields();

/**
* Perform mutation.
*
* @param array $input
* @param \GraphQL\Type\Definition\ResolveInfo $info
* @return array
*/
public function mutateAndGetPayload(array $input, ResolveInfo $info);
}
46 changes: 46 additions & 0 deletions tests/Queries/MutationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

namespace Nuwave\Lighthouse\Tests\Queries;

use Nuwave\Lighthouse\Support\Traits\GlobalIdTrait;
use Nuwave\Lighthouse\Tests\TestCase;
use Nuwave\Lighthouse\Tests\Support\GraphQL\Types\UserType;
use Nuwave\Lighthouse\Tests\Support\GraphQL\Types\TaskType;
use Nuwave\Lighthouse\Tests\Support\GraphQL\Mutations\UpdateEmailMutation;
use Nuwave\Lighthouse\Tests\Support\GraphQL\Mutations\UpdateEmailRelayMutation;

class MutationTest extends TestCase
{
use GlobalIdTrait;

/**
* @test
*/
Expand All @@ -33,4 +37,46 @@ public function itCanResolveMutation()

$this->assertEquals(['data' => $expected], $this->executeQuery($query));
}

/**
* @test
* @group failing
*/
public function itCanResolveRelayMutation()
{
$id = $this->encodeGlobalId(UserType::class, 'foo');

$query = 'mutation UpdateUserEmailRelay($input: UpdateUserPasswordRelayInput!) {
updateEmail(input: $input) {
user {
email
}
clientMutationId
}
}';

$expected = [
'updateEmail' => [
'user' => [
'email' => '[email protected]'
],
'clientMutationId' => 'abcde',
]
];

$variables = [
'input' => [
'id' => $id,
'email' => '[email protected]',
'clientMutationId' => 'abcde'
]
];

$graphql = app('graphql');
$graphql->schema()->type('user', UserType::class);
$graphql->schema()->type('task', TaskType::class);
$graphql->schema()->mutation('updateEmail', UpdateEmailRelayMutation::class);

$this->assertEquals(['data' => $expected], $this->executeQuery($query, $variables));
}
}
1 change: 0 additions & 1 deletion tests/Queries/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ public function itCanResolveNodeInterface()

/**
* @test
* @group failing
*/
public function itCanResolveNodeWithoutRegularIdAttribute()
{
Expand Down
4 changes: 2 additions & 2 deletions tests/Support/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace Nuwave\Lighthouse\Tests\Support\Console;

use Orchestra\Testbench\Console\Kernel;
use Orchestra\Testbench\Console\Kernel as BaseKernel;

class Kernel extends Kernel
class Kernel extends BaseKernel
{
/**
* The Artisan commands provided by your application.
Expand Down
Loading

0 comments on commit 81c7946

Please sign in to comment.