new Deps
This commit is contained in:
+50
-65
@@ -4,31 +4,32 @@ namespace Nuwave\Lighthouse\Defer;
|
||||
|
||||
use Closure;
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Language\AST\TypeNode;
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use GraphQL\Language\AST\NonNullTypeNode;
|
||||
use Nuwave\Lighthouse\Schema\AST\ASTHelper;
|
||||
use Nuwave\Lighthouse\Schema\Values\FieldValue;
|
||||
use GraphQL\Language\AST\TypeNode;
|
||||
use GraphQL\Type\Definition\Directive;
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Nuwave\Lighthouse\ClientDirectives\ClientDirective;
|
||||
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
use Nuwave\Lighthouse\Schema\RootType;
|
||||
use Nuwave\Lighthouse\Schema\Values\FieldValue;
|
||||
use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware;
|
||||
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
class DeferrableDirective extends BaseDirective implements DefinedDirective, FieldMiddleware
|
||||
class DeferrableDirective extends BaseDirective implements FieldMiddleware
|
||||
{
|
||||
const NAME = 'deferrable';
|
||||
const THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_ROOT_MUTATION_FIELD = 'The @defer directive cannot be used on a root mutation field.';
|
||||
const THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_NON_NULLABLE_FIELD = 'The @defer directive cannot be used on a Non-Nullable field.';
|
||||
public const THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_ROOT_MUTATION_FIELD = 'The @defer directive cannot be used on a root mutation field.';
|
||||
public const THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_NON_NULLABLE_FIELD = 'The @defer directive cannot be used on a Non-Nullable field.';
|
||||
public const DEFER_DIRECTIVE_NAME = 'defer';
|
||||
|
||||
public static function definition(): string
|
||||
{
|
||||
return /* @lang GraphQL */ <<<'SDL'
|
||||
return /** @lang GraphQL */ <<<'GRAPHQL'
|
||||
"""
|
||||
Do not use this directive directly, it is automatically added to the schema
|
||||
when using the defer extension.
|
||||
"""
|
||||
directive @deferrable on FIELD_DEFINITION
|
||||
SDL;
|
||||
GRAPHQL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,32 +37,11 @@ SDL;
|
||||
*/
|
||||
protected $defer;
|
||||
|
||||
/**
|
||||
* @param \Nuwave\Lighthouse\Defer\Defer $defer
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Defer $defer)
|
||||
{
|
||||
$this->defer = $defer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the directive.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the field directive.
|
||||
*
|
||||
* @param \Nuwave\Lighthouse\Schema\Values\FieldValue $fieldValue
|
||||
* @param \Closure $next
|
||||
* @return \Nuwave\Lighthouse\Schema\Values\FieldValue
|
||||
*/
|
||||
public function handleField(FieldValue $fieldValue, Closure $next): FieldValue
|
||||
{
|
||||
$previousResolver = $fieldValue->getResolver();
|
||||
@@ -78,9 +58,7 @@ SDL;
|
||||
return $this->defer->defer($wrappedResolver, $path);
|
||||
}
|
||||
|
||||
return $this->defer->isStreaming()
|
||||
? $this->defer->findOrResolve($wrappedResolver, $path)
|
||||
: $previousResolver($root, $args, $context, $resolveInfo);
|
||||
return $this->defer->findOrResolve($wrappedResolver, $path);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -90,49 +68,56 @@ SDL;
|
||||
/**
|
||||
* Determine if field should be deferred.
|
||||
*
|
||||
* @param \GraphQL\Language\AST\TypeNode $fieldType
|
||||
* @param \GraphQL\Type\Definition\ResolveInfo $resolveInfo
|
||||
* @return bool
|
||||
*
|
||||
* @throws \GraphQL\Error\Error
|
||||
*/
|
||||
protected function shouldDefer(TypeNode $fieldType, ResolveInfo $resolveInfo): bool
|
||||
{
|
||||
foreach ($resolveInfo->fieldNodes as $fieldNode) {
|
||||
$deferDirective = ASTHelper::directiveDefinition($fieldNode, 'defer');
|
||||
if (! $deferDirective) {
|
||||
return false;
|
||||
}
|
||||
$defers = (new ClientDirective(self::DEFER_DIRECTIVE_NAME))->forField($resolveInfo);
|
||||
|
||||
if ($resolveInfo->parentType->name === 'Mutation') {
|
||||
if ($this->anyFieldHasDefer($defers)) {
|
||||
if ($resolveInfo->parentType->name === RootType::MUTATION) {
|
||||
throw new Error(self::THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_ROOT_MUTATION_FIELD);
|
||||
}
|
||||
|
||||
if (! ASTHelper::directiveArgValue($deferDirective, 'if', true)) {
|
||||
return false;
|
||||
if ($fieldType instanceof NonNullTypeNode) {
|
||||
throw new Error(self::THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_NON_NULLABLE_FIELD);
|
||||
}
|
||||
}
|
||||
|
||||
$skipDirective = ASTHelper::directiveDefinition($fieldNode, 'skip');
|
||||
if (
|
||||
$skipDirective
|
||||
&& ASTHelper::directiveArgValue($skipDirective, 'if') === true
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$includeDirective = ASTHelper::directiveDefinition($fieldNode, 'include');
|
||||
if (
|
||||
$includeDirective
|
||||
&& ASTHelper::directiveArgValue($includeDirective, 'if') === false
|
||||
) {
|
||||
// Following the semantics of Apollo:
|
||||
// All declarations of a field have to contain @defer for the field to be deferred
|
||||
foreach ($defers as $defer) {
|
||||
if ($defer === null || $defer === [Directive::IF_ARGUMENT_NAME => false]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fieldType instanceof NonNullTypeNode) {
|
||||
throw new Error(self::THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_NON_NULLABLE_FIELD);
|
||||
$skips = (new ClientDirective(Directive::SKIP_NAME))->forField($resolveInfo);
|
||||
foreach ($skips as $skip) {
|
||||
if ($skip === [Directive::IF_ARGUMENT_NAME => true]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
$includes = (new ClientDirective(Directive::INCLUDE_NAME))->forField($resolveInfo);
|
||||
|
||||
return ! in_array(
|
||||
[Directive::IF_ARGUMENT_NAME => false],
|
||||
$includes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array<string, mixed>|null> $defers
|
||||
*/
|
||||
protected function anyFieldHasDefer(array $defers): bool
|
||||
{
|
||||
foreach ($defers as $defer) {
|
||||
if ($defer !== null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user