Skip to content

Commit f82c04f

Browse files
authored
Fix ambiguity around when schema definition may be omitted (#1303)
1 parent d3bf232 commit f82c04f

File tree

5 files changed

+76
-36
lines changed

5 files changed

+76
-36
lines changed

src/Language/Printer.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ public static function doPrint(Node $ast): string
7777
return $instance->printAST($ast);
7878
}
7979

80-
protected function __construct()
81-
{
82-
}
80+
protected function __construct() {}
8381

8482
/**
8583
* Recursively traverse an AST depth-first and produce a pretty string.

src/Utils/SchemaPrinter.php

+30-33
Original file line numberDiff line numberDiff line change
@@ -137,61 +137,58 @@ protected static function printFilteredSchema(Schema $schema, callable $directiv
137137
return \implode("\n\n", \array_filter($elements)) . "\n";
138138
}
139139

140-
protected static function printSchemaDefinition(Schema $schema): string
140+
protected static function printSchemaDefinition(Schema $schema): ?string
141141
{
142-
if (static::isSchemaOfCommonNames($schema)) {
143-
return '';
144-
}
145-
146-
$operationTypes = [];
147-
148142
$queryType = $schema->getQueryType();
149-
if ($queryType !== null) {
150-
$operationTypes[] = " query: {$queryType->name}";
151-
}
152-
153143
$mutationType = $schema->getMutationType();
154-
if ($mutationType !== null) {
155-
$operationTypes[] = " mutation: {$mutationType->name}";
156-
}
157-
158144
$subscriptionType = $schema->getSubscriptionType();
159-
if ($subscriptionType !== null) {
160-
$operationTypes[] = " subscription: {$subscriptionType->name}";
145+
146+
// Special case: When a schema has no root operation types, no valid schema
147+
// definition can be printed.
148+
if ($queryType === null && $mutationType === null && $subscriptionType === null) {
149+
return null;
161150
}
162151

163-
$typesString = \implode("\n", $operationTypes);
152+
// TODO add condition for schema.description
153+
// Only print a schema definition if there is a description or if it should
154+
// not be omitted because of having default type names.
155+
if (! self::hasDefaultRootOperationTypes($schema)) {
156+
return "schema {\n"
157+
. ($queryType !== null ? " query: {$queryType->name}\n" : '')
158+
. ($mutationType !== null ? " mutation: {$mutationType->name}\n" : '')
159+
. ($subscriptionType !== null ? " subscription: {$subscriptionType->name}\n" : '')
160+
. '}';
161+
}
164162

165-
return "schema {\n{$typesString}\n}";
163+
return null;
166164
}
167165

168166
/**
169167
* GraphQL schema define root types for each type of operation. These types are
170168
* the same as any other type and can be named in any manner, however there is
171169
* a common naming convention:.
172170
*
171+
* ```graphql
173172
* schema {
174173
* query: Query
175174
* mutation: Mutation
175+
* subscription: Subscription
176176
* }
177+
* ```
177178
*
178179
* When using this naming convention, the schema description can be omitted.
180+
* When using this naming convention, the schema description can be omitted so
181+
* long as these names are only used for operation types.
182+
*
183+
* Note however that if any of these default names are used elsewhere in the
184+
* schema but not as a root operation type, the schema definition must still
185+
* be printed to avoid ambiguity.
179186
*/
180-
protected static function isSchemaOfCommonNames(Schema $schema): bool
187+
protected static function hasDefaultRootOperationTypes(Schema $schema): bool
181188
{
182-
$queryType = $schema->getQueryType();
183-
if ($queryType !== null && $queryType->name !== 'Query') {
184-
return false;
185-
}
186-
187-
$mutationType = $schema->getMutationType();
188-
if ($mutationType !== null && $mutationType->name !== 'Mutation') {
189-
return false;
190-
}
191-
192-
$subscriptionType = $schema->getSubscriptionType();
193-
194-
return $subscriptionType === null || $subscriptionType->name === 'Subscription';
189+
return $schema->getQueryType() === $schema->getType('Query')
190+
&& $schema->getMutationType() === $schema->getType('Mutation')
191+
&& $schema->getSubscriptionType() === $schema->getType('Subscription');
195192
}
196193

197194
/**

tests/Language/SchemaPrinterTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
88
use GraphQL\Language\Parser;
99
use GraphQL\Language\Printer;
10+
use GraphQL\Utils\BuildSchema;
11+
use GraphQL\Utils\SchemaPrinter;
1012
use PHPUnit\Framework\TestCase;
1113

1214
use function Safe\file_get_contents;
@@ -177,4 +179,14 @@ enum UndefinedEnum
177179
$printed
178180
);
179181
}
182+
183+
/**
184+
* it('prints viral schema correctly', () => {.
185+
*/
186+
public function testPrintsViralSchemaCorrectly(): void
187+
{
188+
$schemaSDL = \Safe\file_get_contents(__DIR__ . '/../viralSchema.graphql');
189+
$schema = BuildSchema::build($schemaSDL);
190+
self::assertSame($schemaSDL, SchemaPrinter::doPrint($schema));
191+
}
180192
}

tests/Utils/BuildSchemaTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,22 @@ public function testThrowsOnUnknownTypes(): void
13861386
BuildSchema::build($sdl, null, ['assumeValidSDL' => true])->assertValid();
13871387
}
13881388

1389+
/**
1390+
* it('correctly processes viral schema', () => {.
1391+
*/
1392+
public function testCorrectlyProcessesViralSchema(): void
1393+
{
1394+
$schema = BuildSchema::build(\Safe\file_get_contents(__DIR__ . '/../viralSchema.graphql'));
1395+
1396+
$queryType = $schema->getQueryType();
1397+
self::assertNotNull($queryType);
1398+
self::assertSame('Query', $queryType->name);
1399+
self::assertNotNull($schema->getType('Virus'));
1400+
self::assertNotNull($schema->getType('Mutation'));
1401+
// Though the viral schema has a 'Mutation' type, it is not used for the 'mutation' operation.
1402+
self::assertNull($schema->getMutationType());
1403+
}
1404+
13891405
/**
13901406
* @see https://github.com/webonyx/graphql-php/issues/997
13911407
*/

tests/viralSchema.graphql

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
schema {
2+
query: Query
3+
}
4+
5+
type Query {
6+
viruses: [Virus!]
7+
}
8+
9+
type Virus {
10+
name: String!
11+
knownMutations: [Mutation!]!
12+
}
13+
14+
type Mutation {
15+
name: String!
16+
geneSequence: String!
17+
}

0 commit comments

Comments
 (0)