Skip to content

Commit 0cc38f0

Browse files
authored
Support schema without Query type when using federation (#1925)
1 parent c9529ee commit 0cc38f0

File tree

8 files changed

+80
-20
lines changed

8 files changed

+80
-20
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ You can find and compare releases at the [GitHub release page](https://github.co
99

1010
## Unreleased
1111

12+
## v5.22.2
13+
14+
### Fixed
15+
16+
- Support schema without `Query` type when using federation https://github.com/nuwave/lighthouse/pull/1925
17+
1218
## v5.22.1
1319

1420
### Fixed

src/Console/MutationCommand.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
namespace Nuwave\Lighthouse\Console;
44

5+
use Nuwave\Lighthouse\Schema\RootType;
6+
57
class MutationCommand extends FieldGeneratorCommand
68
{
79
protected $name = 'lighthouse:mutation';
810

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

11-
protected $type = 'Mutation';
13+
protected $type = RootType::MUTATION;
1214

1315
protected function namespaceConfigKey(): string
1416
{

src/Console/QueryCommand.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
namespace Nuwave\Lighthouse\Console;
44

5+
use Nuwave\Lighthouse\Schema\RootType;
6+
57
class QueryCommand extends FieldGeneratorCommand
68
{
79
protected $name = 'lighthouse:query';
810

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

11-
protected $type = 'Query';
13+
protected $type = RootType::QUERY;
1214

1315
protected function namespaceConfigKey(): string
1416
{

src/Console/SubscriptionCommand.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
namespace Nuwave\Lighthouse\Console;
44

5+
use Nuwave\Lighthouse\Schema\RootType;
6+
57
class SubscriptionCommand extends LighthouseGeneratorCommand
68
{
79
protected $name = 'lighthouse:subscription';
810

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

11-
protected $type = 'Subscription';
13+
protected $type = RootType::SUBSCRIPTION;
1214

1315
protected function namespaceConfigKey(): string
1416
{

src/Federation/ASTManipulator.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Nuwave\Lighthouse\Events\ManipulateAST;
88
use Nuwave\Lighthouse\Exceptions\FederationException;
99
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
10+
use Nuwave\Lighthouse\Schema\RootType;
1011

1112
class ASTManipulator
1213
{
@@ -73,8 +74,14 @@ protected function addEntityUnion(DocumentAST &$documentAST): void
7374

7475
protected function addRootFields(DocumentAST &$documentAST): void
7576
{
77+
// In federation it is fine for a schema to not have a user-defined root query type,
78+
// since we add two federation related fields to it here.
79+
if (! isset($documentAST->types[RootType::QUERY])) {
80+
$documentAST->types[RootType::QUERY] = Parser::objectTypeDefinition(/** @lang GraphQL */ 'type Query');
81+
}
82+
7683
/** @var \GraphQL\Language\AST\ObjectTypeDefinitionNode $queryType */
77-
$queryType = $documentAST->types['Query'];
84+
$queryType = $documentAST->types[RootType::QUERY];
7885

7986
$queryType->fields [] = Parser::fieldDefinition(/** @lang GraphQL */ '
8087
_entities(

src/Federation/FederationPrinter.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Nuwave\Lighthouse\Federation\Directives\KeyDirective;
2222
use Nuwave\Lighthouse\Federation\Directives\ProvidesDirective;
2323
use Nuwave\Lighthouse\Federation\Directives\RequiresDirective;
24+
use Nuwave\Lighthouse\Schema\RootType;
2425

2526
class FederationPrinter
2627
{
@@ -53,21 +54,26 @@ public static function print(Schema $schema): string
5354
unset($types[$type]);
5455
}
5556

56-
$originalQueryType = Arr::pull($types, 'Query');
57-
$config->setQuery(new ObjectType([
58-
'name' => 'Query',
59-
'fields' => array_filter(
60-
$originalQueryType->getFields(),
61-
static function (FieldDefinition $field): bool {
62-
return ! in_array($field->name, static::FEDERATION_FIELDS);
63-
}
64-
),
65-
'interfaces' => $originalQueryType->getInterfaces(),
66-
]));
67-
68-
$config->setMutation(Arr::pull($types, 'Mutation'));
69-
70-
$config->setSubscription(Arr::pull($types, 'Subscription'));
57+
/** @var \GraphQL\Type\Definition\ObjectType $originalQueryType */
58+
$originalQueryType = Arr::pull($types, RootType::QUERY);
59+
$queryFieldsWithoutFederation = array_filter(
60+
$originalQueryType->getFields(),
61+
static function (FieldDefinition $field): bool {
62+
return ! in_array($field->name, static::FEDERATION_FIELDS);
63+
}
64+
);
65+
$newQueryType = count($queryFieldsWithoutFederation) > 0
66+
? new ObjectType([
67+
'name' => RootType::QUERY,
68+
'fields' => $queryFieldsWithoutFederation,
69+
'interfaces' => $originalQueryType->getInterfaces(),
70+
])
71+
: null;
72+
$config->setQuery($newQueryType);
73+
74+
$config->setMutation(Arr::pull($types, RootType::MUTATION));
75+
76+
$config->setSubscription(Arr::pull($types, RootType::SUBSCRIPTION));
7177

7278
$config->setTypes($types);
7379

tests/Integration/Federation/FederationSchemaTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ public function testServiceQueryShouldReturnValidSdl(): void
4141
$this->assertStringContainsString($query, $sdl);
4242
}
4343

44+
public function testServiceQueryShouldReturnValidSdlWithoutQuery(): void
45+
{
46+
$foo = /** @lang GraphQL */ <<<'GRAPHQL'
47+
type Foo @key(fields: "id") {
48+
id: ID! @external
49+
foo: String!
50+
}
51+
52+
GRAPHQL;
53+
54+
$this->schema = $foo;
55+
56+
$sdl = $this->_serviceSdl();
57+
58+
$this->assertStringContainsString($foo, $sdl);
59+
$this->assertStringNotContainsString(/** @lang GraphQL */ 'type Query', $sdl);
60+
}
61+
4462
public function testFederatedSchemaShouldContainCorrectEntityUnion(): void
4563
{
4664
$schema = $this->buildSchema(/** @lang GraphQL */ '

tests/Unit/Federation/SchemaBuilderTest.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace Tests\Unit\Federation;
44

5-
use GraphQL\Type\Definition\Directive;
65
use GraphQL\Type\Definition\ObjectType;
6+
use GraphQL\Type\Schema;
77
use Nuwave\Lighthouse\Exceptions\FederationException;
88
use Nuwave\Lighthouse\Federation\FederationServiceProvider;
99
use Tests\TestCase;
@@ -37,6 +37,23 @@ public function testFederatedSchema(): void
3737
$this->assertTrue($schema->hasType('_Any'));
3838
$this->assertTrue($schema->hasType('_FieldSet'));
3939

40+
$this->assertSchemaHasQueryTypeWithFederationFields($schema);
41+
}
42+
43+
public function testAddsQueryTypeIfNotDefined(): void
44+
{
45+
$schema = $this->buildSchema(/** @lang GraphQL */ '
46+
type Foo @key(fields: "id") {
47+
id: ID!
48+
foo: String!
49+
}
50+
');
51+
52+
$this->assertSchemaHasQueryTypeWithFederationFields($schema);
53+
}
54+
55+
protected function assertSchemaHasQueryTypeWithFederationFields(Schema $schema): void
56+
{
4057
$queryType = $schema->getQueryType();
4158
$this->assertInstanceOf(ObjectType::class, $queryType);
4259

0 commit comments

Comments
 (0)