Skip to content

Commit f93fdac

Browse files
authored
Merge pull request #3471 from graphql-java/schema-extension-not-printed
Add extend schema (AST print) to SchemaPrinter
2 parents 53f22c5 + 32c87b5 commit f93fdac

2 files changed

Lines changed: 238 additions & 17 deletions

File tree

src/main/java/graphql/schema/idl/SchemaPrinter.java

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import graphql.language.ObjectTypeDefinition;
2020
import graphql.language.ScalarTypeDefinition;
2121
import graphql.language.SchemaDefinition;
22+
import graphql.language.SchemaExtensionDefinition;
2223
import graphql.language.TypeDefinition;
2324
import graphql.language.UnionTypeDefinition;
2425
import graphql.schema.DefaultGraphqlTypeComparatorRegistry;
@@ -283,7 +284,7 @@ public Options includeDirectiveDefinitions(boolean flag) {
283284
/**
284285
* This is a Predicate that decides whether a directive definition is printed.
285286
*
286-
* @param includeDirectiveDefinition the predicate to decide of a directive defintion is printed
287+
* @param includeDirectiveDefinition the predicate to decide of a directive definition is printed
287288
*
288289
* @return new instance of options
289290
*/
@@ -482,7 +483,7 @@ public SchemaPrinter(Options options) {
482483

483484
/**
484485
* This can print an in memory GraphQL IDL document back to a logical schema definition.
485-
* If you want to turn a Introspection query result into a Document (and then into a printed
486+
* If you want to turn an Introspection query result into a Document (and then into a printed
486487
* schema) then use {@link graphql.introspection.IntrospectionResultToSchema#createSchemaDefinition(java.util.Map)}
487488
* first to get the {@link graphql.language.Document} and then print that.
488489
*
@@ -773,6 +774,17 @@ private boolean shouldPrintAsAst(TypeDefinition<?> definition) {
773774
return options.isUseAstDefinitions() && definition != null;
774775
}
775776

777+
/**
778+
* This will return true if the options say to use the AST and we have an AST element
779+
*
780+
* @param definition the AST schema definition
781+
*
782+
* @return true if we should print using AST nodes
783+
*/
784+
private boolean shouldPrintAsAst(SchemaDefinition definition) {
785+
return options.isUseAstDefinitions() && definition != null;
786+
}
787+
776788
/**
777789
* This will print out a runtime graphql schema element using its contained AST type definition. This
778790
* must be guarded by a called to {@link #shouldPrintAsAst(TypeDefinition)}
@@ -792,6 +804,25 @@ private void printAsAst(PrintWriter out, TypeDefinition<?> definition, List<? ex
792804
out.print('\n');
793805
}
794806

807+
/**
808+
* This will print out a runtime graphql schema block using its AST definition. This
809+
* must be guarded by a called to {@link #shouldPrintAsAst(SchemaDefinition)}
810+
*
811+
* @param out the output writer
812+
* @param definition the AST schema definition
813+
* @param extensions a list of schema definition extensions
814+
*/
815+
private void printAsAst(PrintWriter out, SchemaDefinition definition, List<SchemaExtensionDefinition> extensions) {
816+
out.printf("%s\n", AstPrinter.printAst(definition));
817+
if (extensions != null) {
818+
for (SchemaExtensionDefinition extension : extensions) {
819+
out.printf("\n%s\n", AstPrinter.printAst(extension));
820+
}
821+
}
822+
out.print('\n');
823+
}
824+
825+
795826
private static String printAst(InputValueWithState value, GraphQLInputType type) {
796827
return AstPrinter.printAst(ValuesResolver.valueToLiteral(value, type, GraphQLContext.getDefault(), Locale.getDefault()));
797828
}
@@ -803,7 +834,7 @@ private SchemaElementPrinter<GraphQLSchema> schemaPrinter() {
803834
GraphQLObjectType subscriptionType = schema.getSubscriptionType();
804835

805836
// when serializing a GraphQL schema using the type system language, a
806-
// schema definition should be omitted if only uses the default root type names.
837+
// schema definition should be omitted only if it uses the default root type names.
807838
boolean needsSchemaPrinted = options.isIncludeSchemaDefinition();
808839

809840
if (!needsSchemaPrinted) {
@@ -819,21 +850,25 @@ private SchemaElementPrinter<GraphQLSchema> schemaPrinter() {
819850
}
820851

821852
if (needsSchemaPrinted) {
822-
if (hasAstDefinitionComments(schema) || hasDescription(schema)) {
823-
out.print(printComments(schema, ""));
824-
}
825-
List<GraphQLAppliedDirective> directives = DirectivesUtil.toAppliedDirectives(schema.getSchemaAppliedDirectives(), schema.getSchemaDirectives());
826-
out.format("schema %s{\n", directivesString(GraphQLSchemaElement.class, directives));
827-
if (queryType != null) {
828-
out.format(" query: %s\n", queryType.getName());
829-
}
830-
if (mutationType != null) {
831-
out.format(" mutation: %s\n", mutationType.getName());
832-
}
833-
if (subscriptionType != null) {
834-
out.format(" subscription: %s\n", subscriptionType.getName());
853+
if (shouldPrintAsAst(schema.getDefinition())) {
854+
printAsAst(out, schema.getDefinition(), schema.getExtensionDefinitions());
855+
} else {
856+
if (hasAstDefinitionComments(schema) || hasDescription(schema)) {
857+
out.print(printComments(schema, ""));
858+
}
859+
List<GraphQLAppliedDirective> directives = DirectivesUtil.toAppliedDirectives(schema.getSchemaAppliedDirectives(), schema.getSchemaDirectives());
860+
out.format("schema %s{\n", directivesString(GraphQLSchemaElement.class, directives));
861+
if (queryType != null) {
862+
out.format(" query: %s\n", queryType.getName());
863+
}
864+
if (mutationType != null) {
865+
out.format(" mutation: %s\n", mutationType.getName());
866+
}
867+
if (subscriptionType != null) {
868+
out.format(" subscription: %s\n", subscriptionType.getName());
869+
}
870+
out.format("}\n\n");
835871
}
836-
out.format("}\n\n");
837872
}
838873
};
839874
}

src/test/groovy/graphql/schema/idl/SchemaPrinterTest.groovy

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,9 +1342,195 @@ type Query {
13421342
'''
13431343
}
13441344

1345+
def "can print extend schema block when AST printing enabled"() {
1346+
def sdl = '''
1347+
directive @schemaDirective on SCHEMA
1348+
1349+
"""
1350+
My schema block description
1351+
"""
1352+
schema {
1353+
mutation: MyMutation
1354+
}
1355+
1356+
extend schema @schemaDirective {
1357+
query: MyQuery
1358+
}
1359+
1360+
extend schema {
1361+
subscription: MySubscription
1362+
}
1363+
1364+
type MyQuery {
1365+
foo: String
1366+
}
1367+
1368+
type MyMutation {
1369+
pizza: String
1370+
}
1371+
1372+
type MySubscription {
1373+
chippies: String
1374+
}
1375+
'''
1376+
1377+
when:
1378+
def runtimeWiring = newRuntimeWiring().build()
1379+
1380+
def options = SchemaGenerator.Options.defaultOptions()
1381+
def types = new SchemaParser().parse(sdl)
1382+
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(options, types, runtimeWiring)
1383+
1384+
def printOptions = defaultOptions()
1385+
.useAstDefinitions(true)
1386+
.includeSchemaDefinition(true)
1387+
def result = new SchemaPrinter(printOptions).print(schema)
1388+
1389+
then:
1390+
result == '''"""
1391+
My schema block description
1392+
"""
1393+
schema {
1394+
mutation: MyMutation
1395+
}
1396+
1397+
extend schema @schemaDirective {
1398+
query: MyQuery
1399+
}
1400+
1401+
extend schema {
1402+
subscription: MySubscription
1403+
}
1404+
1405+
"Marks the field, argument, input field or enum value as deprecated"
1406+
directive @deprecated(
1407+
"The reason for the deprecation"
1408+
reason: String = "No longer supported"
1409+
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION
1410+
1411+
"Directs the executor to include this field or fragment only when the `if` argument is true"
1412+
directive @include(
1413+
"Included when true."
1414+
if: Boolean!
1415+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
1416+
1417+
"Indicates an Input Object is a OneOf Input Object."
1418+
directive @oneOf on INPUT_OBJECT
1419+
1420+
directive @schemaDirective on SCHEMA
1421+
1422+
"Directs the executor to skip this field or fragment when the `if` argument is true."
1423+
directive @skip(
1424+
"Skipped when true."
1425+
if: Boolean!
1426+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
1427+
1428+
"Exposes a URL that specifies the behaviour of this scalar."
1429+
directive @specifiedBy(
1430+
"The URL that specifies the behaviour of this scalar."
1431+
url: String!
1432+
) on SCALAR
1433+
1434+
type MyMutation {
1435+
pizza: String
1436+
}
1437+
1438+
type MyQuery {
1439+
foo: String
1440+
}
1441+
1442+
type MySubscription {
1443+
chippies: String
1444+
}
1445+
'''
1446+
}
1447+
1448+
def "will not print extend schema block when AST printing not enabled"() {
1449+
def sdl = '''
1450+
directive @schemaDirective on SCHEMA
1451+
1452+
"""
1453+
My schema block description
1454+
"""
1455+
schema {
1456+
mutation: MyMutation
1457+
}
1458+
1459+
extend schema @schemaDirective {
1460+
query: MyQuery
1461+
}
1462+
1463+
type MyQuery {
1464+
foo: String
1465+
}
1466+
1467+
type MyMutation {
1468+
pizza: String
1469+
}
1470+
'''
1471+
1472+
when:
1473+
def runtimeWiring = newRuntimeWiring().build()
1474+
1475+
def options = SchemaGenerator.Options.defaultOptions()
1476+
def types = new SchemaParser().parse(sdl)
1477+
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(options, types, runtimeWiring)
1478+
1479+
def printOptions = defaultOptions()
1480+
.useAstDefinitions(false)
1481+
.includeSchemaDefinition(true)
1482+
def result = new SchemaPrinter(printOptions).print(schema)
1483+
1484+
then:
1485+
result == '''"My schema block description"
1486+
schema @schemaDirective{
1487+
query: MyQuery
1488+
mutation: MyMutation
1489+
}
1490+
1491+
"Marks the field, argument, input field or enum value as deprecated"
1492+
directive @deprecated(
1493+
"The reason for the deprecation"
1494+
reason: String = "No longer supported"
1495+
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION
1496+
1497+
"Directs the executor to include this field or fragment only when the `if` argument is true"
1498+
directive @include(
1499+
"Included when true."
1500+
if: Boolean!
1501+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
1502+
1503+
"Indicates an Input Object is a OneOf Input Object."
1504+
directive @oneOf on INPUT_OBJECT
1505+
1506+
directive @schemaDirective on SCHEMA
1507+
1508+
"Directs the executor to skip this field or fragment when the `if` argument is true."
1509+
directive @skip(
1510+
"Skipped when true."
1511+
if: Boolean!
1512+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
1513+
1514+
"Exposes a URL that specifies the behaviour of this scalar."
1515+
directive @specifiedBy(
1516+
"The URL that specifies the behaviour of this scalar."
1517+
url: String!
1518+
) on SCALAR
1519+
1520+
type MyMutation {
1521+
pizza: String
1522+
}
1523+
1524+
type MyQuery {
1525+
foo: String
1526+
}
1527+
'''
1528+
}
1529+
13451530
def "can print a schema as AST elements"() {
13461531
def sdl = '''
13471532
directive @directive1 on SCALAR
1533+
13481534
type Query {
13491535
foo : String
13501536
}

0 commit comments

Comments
 (0)