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

Support schema without Query type when using federation #1925

Merged
merged 6 commits into from
Aug 24, 2021
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

## v5.22.2

### Fixed

- Support schema without `Query` type when using federation https://github.com/nuwave/lighthouse/pull/1925

## v5.22.1

### Fixed
Expand Down
4 changes: 3 additions & 1 deletion src/Console/MutationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace Nuwave\Lighthouse\Console;

use Nuwave\Lighthouse\Schema\RootType;

class MutationCommand extends FieldGeneratorCommand
{
protected $name = 'lighthouse:mutation';

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

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

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

namespace Nuwave\Lighthouse\Console;

use Nuwave\Lighthouse\Schema\RootType;

class QueryCommand extends FieldGeneratorCommand
{
protected $name = 'lighthouse:query';

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

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

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

namespace Nuwave\Lighthouse\Console;

use Nuwave\Lighthouse\Schema\RootType;

class SubscriptionCommand extends LighthouseGeneratorCommand
{
protected $name = 'lighthouse:subscription';

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

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

protected function namespaceConfigKey(): string
{
Expand Down
9 changes: 8 additions & 1 deletion src/Federation/ASTManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Nuwave\Lighthouse\Events\ManipulateAST;
use Nuwave\Lighthouse\Exceptions\FederationException;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\RootType;

class ASTManipulator
{
Expand Down Expand Up @@ -73,8 +74,14 @@ protected function addEntityUnion(DocumentAST &$documentAST): void

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');
}

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

$queryType->fields [] = Parser::fieldDefinition(/** @lang GraphQL */ '
_entities(
Expand Down
36 changes: 21 additions & 15 deletions src/Federation/FederationPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Nuwave\Lighthouse\Federation\Directives\KeyDirective;
use Nuwave\Lighthouse\Federation\Directives\ProvidesDirective;
use Nuwave\Lighthouse\Federation\Directives\RequiresDirective;
use Nuwave\Lighthouse\Schema\RootType;

class FederationPrinter
{
Expand Down Expand Up @@ -53,21 +54,26 @@ public static function print(Schema $schema): string
unset($types[$type]);
}

$originalQueryType = Arr::pull($types, 'Query');
$config->setQuery(new ObjectType([
'name' => 'Query',
'fields' => array_filter(
$originalQueryType->getFields(),
static function (FieldDefinition $field): bool {
return ! in_array($field->name, static::FEDERATION_FIELDS);
}
),
'interfaces' => $originalQueryType->getInterfaces(),
]));

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

$config->setSubscription(Arr::pull($types, 'Subscription'));
/** @var \GraphQL\Type\Definition\ObjectType $originalQueryType */
$originalQueryType = Arr::pull($types, RootType::QUERY);
$queryFieldsWithoutFederation = array_filter(
$originalQueryType->getFields(),
static function (FieldDefinition $field): bool {
return ! in_array($field->name, static::FEDERATION_FIELDS);
}
);
$newQueryType = count($queryFieldsWithoutFederation) > 0
? new ObjectType([
'name' => RootType::QUERY,
'fields' => $queryFieldsWithoutFederation,
'interfaces' => $originalQueryType->getInterfaces(),
])
: null;
$config->setQuery($newQueryType);

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

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

$config->setTypes($types);

Expand Down
18 changes: 18 additions & 0 deletions tests/Integration/Federation/FederationSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ public function testServiceQueryShouldReturnValidSdl(): void
$this->assertStringContainsString($query, $sdl);
}

public function testServiceQueryShouldReturnValidSdlWithoutQuery(): void
{
$foo = /** @lang GraphQL */ <<<'GRAPHQL'
type Foo @key(fields: "id") {
id: ID! @external
foo: String!
}

GRAPHQL;

$this->schema = $foo;

$sdl = $this->_serviceSdl();

$this->assertStringContainsString($foo, $sdl);
$this->assertStringNotContainsString(/** @lang GraphQL */ 'type Query', $sdl);
}

public function testFederatedSchemaShouldContainCorrectEntityUnion(): void
{
$schema = $this->buildSchema(/** @lang GraphQL */ '
Expand Down
19 changes: 18 additions & 1 deletion tests/Unit/Federation/SchemaBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace Tests\Unit\Federation;

use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Schema;
use Nuwave\Lighthouse\Exceptions\FederationException;
use Nuwave\Lighthouse\Federation\FederationServiceProvider;
use Tests\TestCase;
Expand Down Expand Up @@ -37,6 +37,23 @@ public function testFederatedSchema(): void
$this->assertTrue($schema->hasType('_Any'));
$this->assertTrue($schema->hasType('_FieldSet'));

$this->assertSchemaHasQueryTypeWithFederationFields($schema);
}

public function testAddsQueryTypeIfNotDefined(): void
{
$schema = $this->buildSchema(/** @lang GraphQL */ '
type Foo @key(fields: "id") {
id: ID!
foo: String!
}
');

$this->assertSchemaHasQueryTypeWithFederationFields($schema);
}

protected function assertSchemaHasQueryTypeWithFederationFields(Schema $schema): void
{
$queryType = $schema->getQueryType();
$this->assertInstanceOf(ObjectType::class, $queryType);

Expand Down