Skip to content

Commit

Permalink
added connection auto resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
chrissm79 committed Jun 9, 2016
1 parent 03c60f5 commit 6132c23
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 1 deletion.
78 changes: 78 additions & 0 deletions src/Schema/Generators/ConnectionResolveGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Nuwave\Lighthouse\Schema\Generators;

use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Nuwave\Lighthouse\Support\Traits\GlobalIdTrait;

class ConnectionResolveGenerator
{
use GlobalIdTrait;

/**
* Attempt to auto-resolve connection.
*
* @param mixed $root
* @param array $args
* @param ResolveInfo $info
* @param string $name
* @return LengthAwarePaginator
*/
public function resolve($root, array $args, ResolveInfo $info, $name)
{
$items = $this->getItems($root, $info, $name);

if (is_array($items)) {
$items = collect($items);
} else if (! $items instanceof Collection) {
return $items;
}

return $items->paginate($args);
}

/**
* @param $collection
* @param ResolveInfo $info
* @param $name
* @return Collection|array
*/
protected function getItems($collection, ResolveInfo $info, $name)
{
if ($collection instanceof Model) {
if (in_array($name, array_keys($collection->getRelations()))) {
return $collection->{$name};
}

return method_exists($collection, $name)
? $collection->{$name}()->select($this->getSelectFields($info))->get()
: $collection->getAttribute($name);
} elseif (is_object($collection) && method_exists($collection, 'get')) {
return $collection->get($name);
} elseif (is_array($collection) && isset($collection[$name])) {
return collect($collection[$name]);
}

return [];
}

/**
* Select only certain fields on queries instead of all fields.
*
* @param ResolveInfo $info
* @return array
*/
protected function getSelectFields(ResolveInfo $info)
{
$camel = config('relay.camel_case');
$fields = array_get($info->getFieldSelection(2), 'edges.node');

return collect($fields)->reject(function ($value) {
is_array($value);
})->keys()->transform(function ($value) use ($camel) {
return $camel ? snake_case($value) : $value;
})->toArray();
}
}
53 changes: 52 additions & 1 deletion src/Support/Definition/Fields/ConnectionField.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@

use Closure;
use Illuminate\Support\Fluent;
use Nuwave\Lighthouse\Schema\Generators\ConnectionResolveGenerator as Resolver;

class ConnectionField extends Fluent
{
/**
* Connection auto resolver.
*
* @var Resolver
*/
protected $resolver;

/**
* Set resolve function on field.
*
Expand Down Expand Up @@ -52,13 +60,56 @@ public function args(array $args, $append = true)
return $this;
}

/**
* Auto resolve the connection.
*
* @param string $name
* @return Closure
*/
protected function autoResolve($name)
{
if (! $name) {
$connection = $this->get('type')->name;

throw new \Exception("A name must be provided for [$connection] when auto resolving.");
}

return function ($root, array $args, $info) use ($name) {
return $this->getResolver()->resolve($root, $args, $info, $name);
};
}

/**
* Set local instance of resolver.
*
* @param Resolver $resolver
*/
public function setResolver(Resolver $resolver)
{
$this->resolver = $resolver;
}

/**
* Get instance of resolver.
*
* @return Resolver
*/
protected function getResolver()
{
return $this->resolver ?: app(Resolver::class);
}

/**
* Convert to GraphQL field.
*
* @return array
*/
public function field()
public function field($name = null)
{
if (! $this->get('resolve')) {
$this->__set('resolve', $this->autoResolve($name));
}

return $this->toArray();
}
}
114 changes: 114 additions & 0 deletions tests/Queries/AutoResolveTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Nuwave\Tests\Queries;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Nuwave\Lighthouse\Tests\DBTestCase;
use Nuwave\Lighthouse\Tests\Support\GraphQL\Types\TaskType;
use Nuwave\Lighthouse\Tests\Support\Models\User;
use Nuwave\Lighthouse\Tests\Support\Models\Task;
use Nuwave\Lighthouse\Support\Definition\GraphQLType;
use Nuwave\Lighthouse\Support\Interfaces\RelayType;
use Nuwave\Lighthouse\Support\Traits\GlobalIdTrait;

class AutoResolveTest extends DBTestCase
{
use GlobalIdTrait;

/**
* User model.
*
* @var User
*/
protected $user;

/**
* User assigned tasks.
*
* @var \Illuminate\Support\Collection
*/
protected $tasks;

/**
* Set up test environment.
*/
public function setUp()
{
parent::setUp();

$this->user = factory(User::class)->create();

$this->tasks = factory(Task::class, 6)->create([
'user_id' => $this->user->id
]);

$graphql = app('graphql');
$graphql->schema()->type('user', UserStubType::class);
$graphql->schema()->type('task', TaskType::class);
}

/**
* @test
*/
public function itCanAutoResolveConnection()
{
$data = $this->executeQuery($this->getQuery());
$edges = array_get($data, 'data.node.tasks.edges', []);

$this->assertCount(2, $edges);
}

/**
* Get query.
*
* @return string
*/
protected function getQuery()
{
$id = $this->encodeGlobalId(UserStubType::class, $this->user->id);

return '{
node(id:"'.$id.'") {
... on User {
name
tasks(first:2) {
edges {
node {
title
}
}
}
}
}
}';
}
}

class UserStubType extends GraphQLType implements RelayType
{
protected $attributes = [
'name' => 'User',
'description' => 'A user.'
];

public function resolveById($id)
{
return User::find($id);
}

public function fields()
{
return [
'name' => [
'type' => Type::string(),
'description' => 'Name of the user.'
],
'email' => [
'type' => Type::string(),
'description' => 'Email of the user.'
],
'tasks' => GraphQL::connection('task')->field('tasks')
];
}
}

0 comments on commit 6132c23

Please sign in to comment.