Skip to content

Allow changing root type names #2077

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

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
10 changes: 9 additions & 1 deletion src/Console/MutationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Nuwave\Lighthouse\Console;

use Illuminate\Filesystem\Filesystem;
use Nuwave\Lighthouse\Schema\RootType;

class MutationCommand extends FieldGeneratorCommand
Expand All @@ -10,7 +11,14 @@ class MutationCommand extends FieldGeneratorCommand

protected $description = 'Create a class for a single field on the root Mutation type.';

protected $type = RootType::MUTATION;
protected $type;

public function __construct(Filesystem $files)
{
$this->type = RootType::Mutation();

parent::__construct($files);
}

protected function namespaceConfigKey(): string
{
Expand Down
10 changes: 9 additions & 1 deletion src/Console/QueryCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Nuwave\Lighthouse\Console;

use Illuminate\Filesystem\Filesystem;
use Nuwave\Lighthouse\Schema\RootType;

class QueryCommand extends FieldGeneratorCommand
Expand All @@ -10,7 +11,14 @@ class QueryCommand extends FieldGeneratorCommand

protected $description = 'Create a class for a single field on the root Query type.';

protected $type = RootType::QUERY;
protected $type;

public function __construct(Filesystem $files)
{
$this->type = RootType::Query();

parent::__construct($files);
}

protected function namespaceConfigKey(): string
{
Expand Down
10 changes: 9 additions & 1 deletion src/Console/SubscriptionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Nuwave\Lighthouse\Console;

use Illuminate\Filesystem\Filesystem;
use Nuwave\Lighthouse\Schema\RootType;

class SubscriptionCommand extends LighthouseGeneratorCommand
Expand All @@ -10,7 +11,14 @@ class SubscriptionCommand extends LighthouseGeneratorCommand

protected $description = 'Create a class for a single field on the root Subscription type.';

protected $type = RootType::SUBSCRIPTION;
protected $type;

public function __construct(Filesystem $files)
{
$this->type = RootType::Subscription();

parent::__construct($files);
}

protected function namespaceConfigKey(): string
{
Expand Down
2 changes: 1 addition & 1 deletion src/Defer/DeferrableDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected function shouldDefer(TypeNode $fieldType, ResolveInfo $resolveInfo): b
$defers = (new ClientDirective(self::DEFER_DIRECTIVE_NAME))->forField($resolveInfo);

if ($this->anyFieldHasDefer($defers)) {
if (RootType::MUTATION === $resolveInfo->parentType->name) {
if (RootType::Mutation() === $resolveInfo->parentType->name) {
throw new Error(self::THE_DEFER_DIRECTIVE_CANNOT_BE_USED_ON_A_ROOT_MUTATION_FIELD);
}
if ($fieldType instanceof NonNullTypeNode) {
Expand Down
6 changes: 3 additions & 3 deletions src/Federation/ASTManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ protected function addRootFields(DocumentAST &$documentAST): void
{
// In federation it is fine for a schema to not have a user-defined root query type,
// since we add two federation related fields to it here.
if (! isset($documentAST->types[RootType::QUERY])) {
$documentAST->types[RootType::QUERY] = Parser::objectTypeDefinition(/** @lang GraphQL */ 'type Query');
if (! isset($documentAST->types[RootType::Query()])) {
$documentAST->types[RootType::Query()] = Parser::objectTypeDefinition(/** @lang GraphQL */ 'type Query');
}

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
$queryType = $documentAST->types[RootType::QUERY];
$queryType = $documentAST->types[RootType::Query()];

$queryType->fields[] = Parser::fieldDefinition(/** @lang GraphQL */ '
_entities(
Expand Down
8 changes: 4 additions & 4 deletions src/Federation/FederationPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static function print(Schema $schema): string
}

/** @var \GraphQL\Type\Definition\ObjectType $originalQueryType */
$originalQueryType = Arr::pull($types, RootType::QUERY);
$originalQueryType = Arr::pull($types, RootType::Query());
$queryFieldsWithoutFederation = array_filter(
$originalQueryType->getFields(),
static function (FieldDefinition $field): bool {
Expand All @@ -64,16 +64,16 @@ static function (FieldDefinition $field): bool {
);
$newQueryType = count($queryFieldsWithoutFederation) > 0
? new ObjectType([
'name' => RootType::QUERY,
'name' => RootType::Query(),
'fields' => $queryFieldsWithoutFederation,
'interfaces' => $originalQueryType->getInterfaces(),
])
: null;
$config->setQuery($newQueryType);

$config->setMutation(Arr::pull($types, RootType::MUTATION));
$config->setMutation(Arr::pull($types, RootType::Mutation()));

$config->setSubscription(Arr::pull($types, RootType::SUBSCRIPTION));
$config->setSubscription(Arr::pull($types, RootType::Subscription()));

$config->setTypes($types);

Expand Down
2 changes: 1 addition & 1 deletion src/GlobalId/GlobalIdServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ interface $node @interface(resolveType: "Nuwave\\\Lighthouse\\\GlobalId\\\NodeRe
);

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
$queryType = $documentAST->types[RootType::QUERY];
$queryType = $documentAST->types[RootType::Query()];
$queryType->fields[] = Parser::fieldDefinition(/** @lang GraphQL */ <<<'GRAPHQL'
node(id: ID! @globalId): Node @field(resolver: "Nuwave\\Lighthouse\\GlobalId\\NodeRegistry@resolve")
GRAPHQL
Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Factories/FieldFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ protected function complexity(FieldValue $fieldValue): ?callable

public static function defaultResolver(FieldValue $fieldValue): callable
{
if (RootType::SUBSCRIPTION === $fieldValue->getParentName()) {
if (RootType::Subscription() === $fieldValue->getParentName()) {
/** @var \Nuwave\Lighthouse\Support\Contracts\ProvidesSubscriptionResolver $providesSubscriptionResolver */
$providesSubscriptionResolver = app(ProvidesSubscriptionResolver::class);

Expand Down
50 changes: 33 additions & 17 deletions src/Schema/RootType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,54 @@

namespace Nuwave\Lighthouse\Schema;

use Illuminate\Support\Str;

class RootType
{
public const QUERY = 'Query';
public const MUTATION = 'Mutation';
public const SUBSCRIPTION = 'Subscription';

public const NATIVE_TYPES = [
'Query',
'Mutation',
'Subscription',
];

public static function Query(): string
{
return self::getType('Query');
}

public static function Mutation(): string
{
return self::getType('Mutation');
}

public static function Subscription(): string
{
return self::getType('Subscription');
}

private static function getType(string $nativeName): string
{
return config(sprintf('lighthouse.root_types.%s', Str::lower($nativeName)));
}

public static function isRootType(string $typeName): bool
{
return in_array(
$typeName,
[
static::QUERY,
static::MUTATION,
static::SUBSCRIPTION,
]
);
return in_array($typeName, static::NATIVE_TYPES);
}

/**
* @return array<int, string>
*/
public static function defaultNamespaces(string $typeName): array
{
switch ($typeName) {
case static::QUERY:
return (array) config('lighthouse.namespaces.queries');
case static::MUTATION:
return (array) config('lighthouse.namespaces.mutations');
case static::SUBSCRIPTION:
return (array) config('lighthouse.namespaces.subscriptions');
default:
return [];
if (!static::isRootType($typeName)) {
return [];
}

return (array) config(sprintf('lighthouse.namespaces.%s', Str::of($typeName)->plural()->lower()));
}
}
10 changes: 5 additions & 5 deletions src/Schema/SchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ protected function build(DocumentAST $documentAST): Schema

// Always set Query since it is required
/** @var \GraphQL\Type\Definition\ObjectType $query */
$query = $this->typeRegistry->get(RootType::QUERY);
$query = $this->typeRegistry->get(RootType::Query());
$config->setQuery($query);

// Mutation and Subscription are optional, so only add them
// if they are present in the schema
if (isset($documentAST->types[RootType::MUTATION])) {
if (isset($documentAST->types[RootType::Mutation()])) {
/** @var \GraphQL\Type\Definition\ObjectType $mutation */
$mutation = $this->typeRegistry->get(RootType::MUTATION);
$mutation = $this->typeRegistry->get(RootType::Mutation());
$config->setMutation($mutation);
}

if (isset($documentAST->types[RootType::SUBSCRIPTION])) {
if (isset($documentAST->types[RootType::Subscription()])) {
/** @var \GraphQL\Type\Definition\ObjectType $subscription */
$subscription = $this->typeRegistry->get(RootType::SUBSCRIPTION);
$subscription = $this->typeRegistry->get(RootType::Subscription());
$config->setSubscription($subscription);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Values/TypeValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function cacheKey(): ?string
$typeName = $this->getTypeDefinitionName();

// The Query type is exempt from requiring a cache key
if (RootType::QUERY === $typeName) {
if (RootType::Query() === $typeName) {
return null;
}

Expand Down
14 changes: 14 additions & 0 deletions src/lighthouse.php
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,20 @@
'max_execution_ms' => 0,
],

/*
|--------------------------------------------------------------------------
| Root types
|--------------------------------------------------------------------------
|
| Change root types to get around naming conflicts.
|
*/
'root_types' => [
'query' => 'Query',
'mutation' => 'Mutation',
'subscription' => 'Subscription',
],

/*
|--------------------------------------------------------------------------
| Apollo Federation
Expand Down
2 changes: 1 addition & 1 deletion tests/Integration/IntrospectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function testFindsTypesFromSchema(): void
$this->introspectType('Foo')
);
$this->assertNotNull(
$this->introspectType(RootType::QUERY)
$this->introspectType(RootType::Query())
);

$this->assertNull(
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Execution/Arguments/ArgumentSetFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ protected function rootQueryArgumentSet(array $args): ArgumentSet
$documentAST = $astBuilder->documentAST();

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
$queryType = $documentAST->types[RootType::QUERY];
$queryType = $documentAST->types[RootType::Query()];

/** @var array<\GraphQL\Language\AST\FieldDefinitionNode> $fields */
$fields = $queryType->fields;
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/GlobalId/GlobalIdDirectiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function testDecodesGlobalId(): void
}
')->assertJson([
'data' => [
'foo' => $this->globalId->encode(RootType::QUERY, Foo::THE_ANSWER),
'foo' => $this->globalId->encode(RootType::Query(), Foo::THE_ANSWER),
],
]);
}
Expand Down
8 changes: 4 additions & 4 deletions tests/Unit/Schema/AST/ASTBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function testMergeTypeExtensionFields(): void
$documentAST = $this->astBuilder->documentAST();

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
$queryType = $documentAST->types[RootType::QUERY];
$queryType = $documentAST->types[RootType::Query()];

$fields = $queryType->fields;
$this->assertNotNull($fields);
Expand All @@ -68,23 +68,23 @@ public function testAllowsExtendingUndefinedRootTypes(): void
$documentAST = $this->astBuilder->documentAST();

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
$queryType = $documentAST->types[RootType::QUERY];
$queryType = $documentAST->types[RootType::Query()];

$queryFields = $queryType->fields;
$this->assertNotNull($queryFields);
/** @var array<\GraphQL\Language\AST\FieldDefinitionNode> $queryFields */
$this->assertCount(1, $queryFields);

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $mutationType */
$mutationType = $documentAST->types[RootType::MUTATION];
$mutationType = $documentAST->types[RootType::Mutation()];

$mutationFields = $mutationType->fields;
$this->assertNotNull($mutationFields);
/** @var array<\GraphQL\Language\AST\FieldDefinitionNode> $mutationFields */
$this->assertCount(1, $mutationFields);

/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $subscriptionType */
$subscriptionType = $documentAST->types[RootType::SUBSCRIPTION];
$subscriptionType = $documentAST->types[RootType::Subscription()];

$subscriptionFields = $subscriptionType->fields;
$this->assertNotNull($subscriptionFields);
Expand Down
6 changes: 3 additions & 3 deletions tests/Unit/Schema/AST/DocumentASTTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function testParsesSimpleSchema(): void

$this->assertInstanceOf(
ObjectTypeDefinitionNode::class,
$documentAST->types[RootType::QUERY]
$documentAST->types[RootType::Query()]
);
}

Expand Down Expand Up @@ -79,7 +79,7 @@ public function testOverwritesDefinitionWithSameName(): void

$this->assertSame(
$overwrite,
$documentAST->types[RootType::QUERY]
$documentAST->types[RootType::Query()]
);
}

Expand All @@ -98,7 +98,7 @@ public function testBeSerialized(): void
serialize($documentAST)
);

$queryType = $reserialized->types[RootType::QUERY];
$queryType = $reserialized->types[RootType::Query()];
$this->assertInstanceOf(ObjectTypeDefinitionNode::class, $queryType);
$this->assertInstanceOf(FieldDefinitionNode::class, $queryType->fields[0]);

Expand Down
6 changes: 5 additions & 1 deletion tests/Unit/Schema/ResolverProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ public function testThrowsIfRootFieldHasNoResolver(): void
);
}

protected function constructFieldValue(string $fieldDefinition, string $parentTypeName = RootType::QUERY): FieldValue
protected function constructFieldValue(string $fieldDefinition, string $parentTypeName = null): FieldValue
{
if (is_null($parentTypeName)) {
$parentTypeName = RootType::Query();
}

$queryType = Parser::objectTypeDefinition(/** @lang GraphQL */ "
type {$parentTypeName} {
{$fieldDefinition}
Expand Down
Loading