From 9883c82ca898502dea935a5a1a1ca11bae196ece Mon Sep 17 00:00:00 2001 From: andimarek Date: Wed, 24 May 2017 22:16:31 +0200 Subject: [PATCH 01/10] wip --- src/main/java/graphql/Assert.java | 5 + .../IntrospectionResultToSchema.java | 61 + .../IntrospectionResultToSchemaTest.groovy | 85 ++ .../groovy/graphql/introspection/example.json | 1257 +++++++++++++++++ 4 files changed, 1408 insertions(+) create mode 100644 src/main/java/graphql/introspection/IntrospectionResultToSchema.java create mode 100644 src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy create mode 100644 src/test/groovy/graphql/introspection/example.json diff --git a/src/main/java/graphql/Assert.java b/src/main/java/graphql/Assert.java index 5bb3bfbe37..218be88db0 100644 --- a/src/main/java/graphql/Assert.java +++ b/src/main/java/graphql/Assert.java @@ -19,6 +19,11 @@ public static Collection assertNotEmpty(Collection c, String errorMess return c; } + public static void assertTrue(boolean condition, String errorMessage) { + if (condition) return; + throw new AssertException(errorMessage); + } + private static final String invalidNameErrorMessage = "Name must be non-null, non-empty and match [_A-Za-z][_0-9A-Za-z]*"; /** diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java new file mode 100644 index 0000000000..b27d1cfd57 --- /dev/null +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -0,0 +1,61 @@ +package graphql.introspection; + +import graphql.Assert; +import graphql.language.Comment; +import graphql.language.FieldDefinition; +import graphql.language.InputValueDefinition; +import graphql.language.ObjectTypeDefinition; +import graphql.language.SourceLocation; +import graphql.language.TypeName; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class IntrospectionResultToSchema { + + + public String introscpectionResultToSchema(Map introspectionResult) { + return null; + } + + private List toComment(String description) { + if (description == null) return Collections.emptyList(); + Comment comment = new Comment(description, new SourceLocation(1, 1)); + return Arrays.asList(comment); + } + + /* + type QueryType { + hero(episode: Episode): Character + human(id : String) : Human + droid(id: ID!): Droid + } + */ + public ObjectTypeDefinition createObject(Map input) { + Assert.assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); + ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name")); + objectTypeDefinition.setComments(toComment((String) input.get("description"))); + List> fields = (List>) input.get("fields"); + for (Map field : fields) { + FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name")); + fieldDefinition.setComments(toComment((String) field.get("description"))); + fieldDefinition.setType(createType((Map) field.get("type"))); + + List> args = (List>) field.get("args"); + for (Map arg : args) { + TypeName typeName = createType((Map) arg.get("type")); + InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), typeName); + fieldDefinition.getInputValueDefinitions().add(inputValueDefinition); + } + objectTypeDefinition.getFieldDefinitions().add(fieldDefinition); + } + return objectTypeDefinition; + } + + TypeName createType(Map type) { + TypeName typeName = new TypeName((String) type.get("name")); + return typeName; + } +} diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy new file mode 100644 index 0000000000..e774169b79 --- /dev/null +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -0,0 +1,85 @@ +package graphql.introspection + +import graphql.GraphQL +import graphql.StarWarsSchema +import graphql.language.AstPrinter +import graphql.language.ObjectTypeDefinition +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +import spock.lang.Specification + +class IntrospectionResultToSchemaTest extends Specification { + + def "Allow querying the schema with pre-defined full introspection query"() { + given: + def query = IntrospectionQuery.INTROSPECTION_QUERY + + when: + def result = GraphQL.newGraphQL(StarWarsSchema.starWarsSchema).build().execute(query) + println result.data + println JsonOutput.prettyPrint(JsonOutput.toJson(result.data)) + + then: + Map schema = (Map) result.data + schema.size() == 1 + Map schemaParts = (Map) schema.get("__schema") + schemaParts.size() == 5 + schemaParts.get('queryType').size() == 1 + schemaParts.get('mutationType') == null + schemaParts.get('subscriptionType') == null + schemaParts.get('types').size() == 15 + schemaParts.get('directives').size() == 2 + } + + def introspectionResultToSchema = new IntrospectionResultToSchema() + + def "create object"() { + def input = """ { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "hero", + "description": null, + "args": [ + { + "name": "episode", + "description": "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", + "type": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + ObjectTypeDefinition objectTypeDefinition = introspectionResultToSchema.createObject(parsed) + AstPrinter astPrinter = new AstPrinter() + println astPrinter.printAst(objectTypeDefinition) + + then: + true + + } +} + diff --git a/src/test/groovy/graphql/introspection/example.json b/src/test/groovy/graphql/introspection/example.json new file mode 100644 index 0000000000..1a98643aa9 --- /dev/null +++ b/src/test/groovy/graphql/introspection/example.json @@ -0,0 +1,1257 @@ +{ + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": null, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "hero", + "description": null, + "args": [ + { + "name": "episode", + "description": "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", + "type": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "human", + "description": null, + "args": [ + { + "name": "id", + "description": "id of the human", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "droid", + "description": null, + "args": [ + { + "name": "id", + "description": "id of the droid", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INTERFACE", + "name": "Character", + "description": "A character in the Star Wars Trilogy", + "fields": [ + { + "name": "id", + "description": "The id of the character.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the character.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the character, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + } + ] + }, + { + "kind": "SCALAR", + "name": "String", + "description": "Built-in String", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "Episode", + "description": "One of the films in the Star Wars Trilogy", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "NEWHOPE", + "description": "Released in 1977.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "EMPIRE", + "description": "Released in 1980.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "JEDI", + "description": "Released in 1983.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Human", + "description": "A humanoid creature in the Star Wars universe.", + "fields": [ + { + "name": "id", + "description": "The id of the human.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the human.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the human, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "homePlanet", + "description": "The home planet of the human, or null if unknown.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "description": "A mechanical creature in the Star Wars universe.", + "fields": [ + { + "name": "id", + "description": "The id of the droid.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the droid.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the droid, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "primaryFunction", + "description": "The primary function of the droid.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "'A list of all directives supported by this server.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "'If this server support subscription, the type that subscription operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": null, + "fields": [ + { + "name": "kind", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given __Type is", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "Built-in Boolean", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "An enum describing valid locations where a directive can be placed", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Indicates the directive is valid on queries.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Indicates the directive is valid on mutations.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Indicates the directive is valid on fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Indicates the directive is valid on fragment definitions.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Indicates the directive is valid on fragment spreads.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Indicates the directive is valid on inline fragments.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + } + ] + } +} + From e74167a22bb9e44f476ab41c4ac934b144ea2c06 Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 07:44:00 +0200 Subject: [PATCH 02/10] wip --- src/main/java/graphql/Assert.java | 8 +++++ .../IntrospectionResultToSchema.java | 31 ++++++++++++++++--- .../language/InputValueDefinition.java | 2 +- .../parser/GraphqlAntlrToLanguage.java | 2 +- .../IntrospectionResultToSchemaTest.groovy | 18 +++++++++-- 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/main/java/graphql/Assert.java b/src/main/java/graphql/Assert.java index 218be88db0..259b22cc5d 100644 --- a/src/main/java/graphql/Assert.java +++ b/src/main/java/graphql/Assert.java @@ -14,6 +14,14 @@ public static T assertNeverCalled() { throw new AssertException("Should never been called"); } + public static T assertShouldNeverHappen(String errorMessage) { + throw new AssertException("Internal error: should never happen: " + errorMessage); + } + + public static T assertShouldNeverHappen() { + throw new AssertException("Internal error: should never happen"); + } + public static Collection assertNotEmpty(Collection c, String errorMessage) { if (c == null || c.isEmpty()) throw new AssertException(errorMessage); return c; diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index b27d1cfd57..f4ab3392ef 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -1,11 +1,11 @@ package graphql.introspection; -import graphql.Assert; import graphql.language.Comment; import graphql.language.FieldDefinition; import graphql.language.InputValueDefinition; import graphql.language.ObjectTypeDefinition; import graphql.language.SourceLocation; +import graphql.language.StringValue; import graphql.language.TypeName; import java.util.Arrays; @@ -13,6 +13,9 @@ import java.util.List; import java.util.Map; +import static graphql.Assert.assertShouldNeverHappen; +import static graphql.Assert.assertTrue; + public class IntrospectionResultToSchema { @@ -33,20 +36,29 @@ private List toComment(String description) { droid(id: ID!): Droid } */ + @SuppressWarnings("unchecked") public ObjectTypeDefinition createObject(Map input) { - Assert.assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); + assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); + ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name")); objectTypeDefinition.setComments(toComment((String) input.get("description"))); List> fields = (List>) input.get("fields"); + for (Map field : fields) { FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name")); fieldDefinition.setComments(toComment((String) field.get("description"))); fieldDefinition.setType(createType((Map) field.get("type"))); List> args = (List>) field.get("args"); + for (Map arg : args) { TypeName typeName = createType((Map) arg.get("type")); InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), typeName); + + if (arg.get("defaultValue") != null) { + StringValue defaultValue = new StringValue((String) arg.get("defaultValue")); + inputValueDefinition.setDefaultValue(defaultValue); + } fieldDefinition.getInputValueDefinitions().add(inputValueDefinition); } objectTypeDefinition.getFieldDefinitions().add(fieldDefinition); @@ -55,7 +67,18 @@ public ObjectTypeDefinition createObject(Map input) { } TypeName createType(Map type) { - TypeName typeName = new TypeName((String) type.get("name")); - return typeName; + String kind = (String) type.get("kind"); + switch (kind) { + case "INTERFACE": + case "OBJECT": + case "UNION": + case "ENUM": + return new TypeName((String) type.get("name")); + case "SCALAR": + return new TypeName((String) type.get("name")); + default: + return assertShouldNeverHappen("Unknown kind " + kind); + } } + } diff --git a/src/main/java/graphql/language/InputValueDefinition.java b/src/main/java/graphql/language/InputValueDefinition.java index 51904d09fc..6bb69cea8e 100644 --- a/src/main/java/graphql/language/InputValueDefinition.java +++ b/src/main/java/graphql/language/InputValueDefinition.java @@ -39,7 +39,7 @@ public Value getDefaultValue() { return defaultValue; } - public void setValue(Value defaultValue) { + public void setDefaultValue(Value defaultValue) { this.defaultValue = defaultValue; } diff --git a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java index a9a2c26b90..98f5277938 100644 --- a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java +++ b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java @@ -537,7 +537,7 @@ public Void visitInputValueDefinition(GraphqlParser.InputValueDefinitionContext InputValueDefinition def = new InputValueDefinition(ctx.name().getText()); newNode(def, ctx); if (ctx.defaultValue() != null) { - def.setValue(getValue(ctx.defaultValue().value())); + def.setDefaultValue(getValue(ctx.defaultValue().value())); } for (ContextEntry contextEntry : contextStack) { if (contextEntry.contextProperty == ContextProperty.FieldDefinition) { diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index e774169b79..2902cbc7ed 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -45,13 +45,23 @@ class IntrospectionResultToSchemaTest extends Specification { "args": [ { "name": "episode", - "description": "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", + "description": "comment about episode", "type": { "kind": "ENUM", "name": "Episode", "ofType": null }, "defaultValue": null + }, + { + "name": "foo", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "bar" } ], "type": { @@ -75,10 +85,12 @@ class IntrospectionResultToSchemaTest extends Specification { when: ObjectTypeDefinition objectTypeDefinition = introspectionResultToSchema.createObject(parsed) AstPrinter astPrinter = new AstPrinter() - println astPrinter.printAst(objectTypeDefinition) + def result = astPrinter.printAst(objectTypeDefinition) then: - true + result == """type QueryType { + hero(episode: Episode, foo: String = \"bar\"): Character +}""" } } From a0de08ee38a1f7fc46d7e8055e60134cb49c485e Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 08:02:36 +0200 Subject: [PATCH 03/10] wip --- .../IntrospectionResultToSchema.java | 48 +++++-- .../IntrospectionResultToSchemaTest.groovy | 135 ++++++++++++++---- 2 files changed, 147 insertions(+), 36 deletions(-) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index f4ab3392ef..d63ac35e11 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -3,11 +3,16 @@ import graphql.language.Comment; import graphql.language.FieldDefinition; import graphql.language.InputValueDefinition; +import graphql.language.InterfaceTypeDefinition; +import graphql.language.ListType; +import graphql.language.NonNullType; import graphql.language.ObjectTypeDefinition; import graphql.language.SourceLocation; import graphql.language.StringValue; +import graphql.language.Type; import graphql.language.TypeName; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -29,13 +34,20 @@ private List toComment(String description) { return Arrays.asList(comment); } - /* - type QueryType { - hero(episode: Episode): Character - human(id : String) : Human - droid(id: ID!): Droid - } - */ + + @SuppressWarnings("unchecked") + public InterfaceTypeDefinition createInterface(Map input) { + assertTrue(input.get("kind").equals("INTERFACE"), "wrong input"); + + InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name")); + List> fields = (List>) input.get("fields"); + interfaceTypeDefinition.getFieldDefinitions().addAll(createFields(fields)); + + return interfaceTypeDefinition; + + } + + @SuppressWarnings("unchecked") public ObjectTypeDefinition createObject(Map input) { assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); @@ -44,6 +56,13 @@ public ObjectTypeDefinition createObject(Map input) { objectTypeDefinition.setComments(toComment((String) input.get("description"))); List> fields = (List>) input.get("fields"); + objectTypeDefinition.getFieldDefinitions().addAll(createFields(fields)); + + return objectTypeDefinition; + } + + private List createFields(List> fields) { + List result = new ArrayList<>(); for (Map field : fields) { FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name")); fieldDefinition.setComments(toComment((String) field.get("description"))); @@ -52,8 +71,8 @@ public ObjectTypeDefinition createObject(Map input) { List> args = (List>) field.get("args"); for (Map arg : args) { - TypeName typeName = createType((Map) arg.get("type")); - InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), typeName); + Type argType = createType((Map) arg.get("type")); + InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType); if (arg.get("defaultValue") != null) { StringValue defaultValue = new StringValue((String) arg.get("defaultValue")); @@ -61,12 +80,13 @@ public ObjectTypeDefinition createObject(Map input) { } fieldDefinition.getInputValueDefinitions().add(inputValueDefinition); } - objectTypeDefinition.getFieldDefinitions().add(fieldDefinition); + result.add(fieldDefinition); } - return objectTypeDefinition; + return result; } - TypeName createType(Map type) { + @SuppressWarnings("unchecked") + Type createType(Map type) { String kind = (String) type.get("kind"); switch (kind) { case "INTERFACE": @@ -76,6 +96,10 @@ TypeName createType(Map type) { return new TypeName((String) type.get("name")); case "SCALAR": return new TypeName((String) type.get("name")); + case "NON_NULL": + return new NonNullType(createType((Map) type.get("ofType"))); + case "LIST": + return new ListType(createType((Map) type.get("ofType"))); default: return assertShouldNeverHappen("Unknown kind " + kind); } diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 2902cbc7ed..8f555a2cc1 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -1,36 +1,13 @@ package graphql.introspection -import graphql.GraphQL -import graphql.StarWarsSchema import graphql.language.AstPrinter +import graphql.language.InterfaceTypeDefinition import graphql.language.ObjectTypeDefinition -import groovy.json.JsonOutput import groovy.json.JsonSlurper import spock.lang.Specification class IntrospectionResultToSchemaTest extends Specification { - def "Allow querying the schema with pre-defined full introspection query"() { - given: - def query = IntrospectionQuery.INTROSPECTION_QUERY - - when: - def result = GraphQL.newGraphQL(StarWarsSchema.starWarsSchema).build().execute(query) - println result.data - println JsonOutput.prettyPrint(JsonOutput.toJson(result.data)) - - then: - Map schema = (Map) result.data - schema.size() == 1 - Map schemaParts = (Map) schema.get("__schema") - schemaParts.size() == 5 - schemaParts.get('queryType').size() == 1 - schemaParts.get('mutationType') == null - schemaParts.get('subscriptionType') == null - schemaParts.get('types').size() == 15 - schemaParts.get('directives').size() == 2 - } - def introspectionResultToSchema = new IntrospectionResultToSchema() def "create object"() { @@ -93,5 +70,115 @@ class IntrospectionResultToSchemaTest extends Specification { }""" } + + def "create interface"() { + def input = """ { + "kind": "INTERFACE", + "name": "Character", + "description": "A character in the Star Wars Trilogy", + "fields": [ + { + "name": "id", + "description": "The id of the character.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the character.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the character, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + } + ] + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + InterfaceTypeDefinition interfaceTypeDefinition = introspectionResultToSchema.createInterface(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(interfaceTypeDefinition) + + then: + result == """interface Character { + #The id of the character. + id: String! + #The name of the character. + name: String + #The friends of the character, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] +}""" + + } } From d67772986b4b459be57393c291b0b56045a1a2eb Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 08:46:23 +0200 Subject: [PATCH 04/10] enums --- .../IntrospectionResultToSchema.java | 21 ++++++++ .../java/graphql/language/AstPrinter.java | 22 +++++--- .../IntrospectionResultToSchemaTest.groovy | 53 +++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index d63ac35e11..1ffc0c0d63 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -1,6 +1,8 @@ package graphql.introspection; import graphql.language.Comment; +import graphql.language.EnumTypeDefinition; +import graphql.language.EnumValueDefinition; import graphql.language.FieldDefinition; import graphql.language.InputValueDefinition; import graphql.language.InterfaceTypeDefinition; @@ -34,12 +36,31 @@ private List toComment(String description) { return Arrays.asList(comment); } + @SuppressWarnings("unchecked") + public EnumTypeDefinition createEnum(Map input) { + assertTrue(input.get("kind").equals("ENUM"), "wrong input"); + + EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition((String) input.get("name")); + enumTypeDefinition.setComments(toComment((String) input.get("description"))); + + List> enumValues = (List>) input.get("enumValues"); + + for (Map enumValue : enumValues) { + + EnumValueDefinition enumValueDefinition = new EnumValueDefinition((String) enumValue.get("name")); + enumValueDefinition.setComments(toComment((String) enumValue.get("description"))); + enumTypeDefinition.getEnumValueDefinitions().add(enumValueDefinition); + } + + return enumTypeDefinition; + } @SuppressWarnings("unchecked") public InterfaceTypeDefinition createInterface(Map input) { assertTrue(input.get("kind").equals("INTERFACE"), "wrong input"); InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name")); + interfaceTypeDefinition.setComments(toComment((String) input.get("description"))); List> fields = (List>) input.get("fields"); interfaceTypeDefinition.getFieldDefinitions().addAll(createFields(fields)); diff --git a/src/main/java/graphql/language/AstPrinter.java b/src/main/java/graphql/language/AstPrinter.java index c32883f97a..5943191482 100644 --- a/src/main/java/graphql/language/AstPrinter.java +++ b/src/main/java/graphql/language/AstPrinter.java @@ -89,12 +89,16 @@ private static NodePrinter directiveLocation() { } private static NodePrinter enumTypeDefinition() { - return (out, node) -> out.printf("%s", spaced( - "enum", - node.getName(), - directives(node.getDirectives()), - block(node.getEnumValueDefinitions()) - )); + return (out, node) -> { + out.printf("%s", comments(node)); + out.printf("%s", + spaced( + "enum", + node.getName(), + directives(node.getDirectives()), + block(node.getEnumValueDefinitions()) + )); + }; } private static NodePrinter enumValue() { @@ -102,7 +106,10 @@ private static NodePrinter enumValue() { } private static NodePrinter enumValueDefinition() { - return (out, node) -> out.printf("%s", node.getName()); + return (out, node) -> { + out.printf("%s", comments(node)); + out.printf("%s", node.getName()); + }; } private static NodePrinter field() { @@ -461,7 +468,6 @@ static String wrap(String start, Node maybeNode, String end) { * This will pretty print the AST node in graphql language format * * @param node the AST node to print - * * @return the printed node in graphql language format */ public static String printAst(Node node) { diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 8f555a2cc1..529bc1b2bc 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -1,6 +1,7 @@ package graphql.introspection import graphql.language.AstPrinter +import graphql.language.EnumTypeDefinition import graphql.language.InterfaceTypeDefinition import graphql.language.ObjectTypeDefinition import groovy.json.JsonSlurper @@ -180,5 +181,57 @@ class IntrospectionResultToSchemaTest extends Specification { }""" } + + def "create enum"() { + def input = """ { + "kind": "ENUM", + "name": "Episode", + "description": "One of the films in the Star Wars Trilogy", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "NEWHOPE", + "description": "Released in 1977.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "EMPIRE", + "description": "Released in 1980.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "JEDI", + "description": "Released in 1983.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + EnumTypeDefinition interfaceTypeDefinition = introspectionResultToSchema.createEnum(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(interfaceTypeDefinition) + + then: + result == """#One of the films in the Star Wars Trilogy +enum Episode { + #Released in 1977. + NEWHOPE + #Released in 1980. + EMPIRE + #Released in 1983. + JEDI +}""" + + } } From 1ab4eaad7714bb92ba56920e4f47ae9cf25a6558 Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 08:52:00 +0200 Subject: [PATCH 05/10] wip --- .../introspection/IntrospectionResultToSchemaTest.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 529bc1b2bc..13c8f185cf 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -169,7 +169,8 @@ class IntrospectionResultToSchemaTest extends Specification { def result = astPrinter.printAst(interfaceTypeDefinition) then: - result == """interface Character { + result == """#A character in the Star Wars Trilogy +interface Character { #The id of the character. id: String! #The name of the character. From cb030f79c0f80d32e1e6ff143b55e81579a77969 Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 09:08:10 +0200 Subject: [PATCH 06/10] wip --- .../IntrospectionResultToSchema.java | 24 +- .../IntrospectionResultToSchemaTest.groovy | 44 +- .../graphql/introspection/example2.json | 1300 +++++++++++++++++ 3 files changed, 1361 insertions(+), 7 deletions(-) create mode 100644 src/test/groovy/graphql/introspection/example2.json diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index 1ffc0c0d63..5bc1ced719 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -13,6 +13,7 @@ import graphql.language.StringValue; import graphql.language.Type; import graphql.language.TypeName; +import graphql.language.UnionTypeDefinition; import java.util.ArrayList; import java.util.Arrays; @@ -26,9 +27,9 @@ public class IntrospectionResultToSchema { - public String introscpectionResultToSchema(Map introspectionResult) { - return null; - } +// public String to(Map introspectionResult) { +// return null; +// } private List toComment(String description) { if (description == null) return Collections.emptyList(); @@ -36,6 +37,23 @@ private List toComment(String description) { return Arrays.asList(comment); } + @SuppressWarnings("unchecked") + public UnionTypeDefinition createUnion(Map input) { + assertTrue(input.get("kind").equals("UNION"), "wrong input"); + + UnionTypeDefinition unionTypeDefinition = new UnionTypeDefinition((String) input.get("name")); + unionTypeDefinition.setComments(toComment((String) input.get("description"))); + + List> possibleTypes = (List>) input.get("possibleTypes"); + + for (Map possibleType : possibleTypes) { + TypeName typeName = new TypeName((String) possibleType.get("name")); + unionTypeDefinition.getMemberTypes().add(typeName); + } + + return unionTypeDefinition; + } + @SuppressWarnings("unchecked") public EnumTypeDefinition createEnum(Map input) { assertTrue(input.get("kind").equals("ENUM"), "wrong input"); diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 13c8f185cf..d758ea9b1a 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -1,9 +1,6 @@ package graphql.introspection -import graphql.language.AstPrinter -import graphql.language.EnumTypeDefinition -import graphql.language.InterfaceTypeDefinition -import graphql.language.ObjectTypeDefinition +import graphql.language.* import groovy.json.JsonSlurper import spock.lang.Specification @@ -234,5 +231,44 @@ enum Episode { }""" } + + def "create union"() { + def input = """ { + "kind": "UNION", + "name": "Everything", + "description": "all the stuff", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + ] + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + UnionTypeDefinition unionTypeDefinition = introspectionResultToSchema.createUnion(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(unionTypeDefinition) + + then: + result == """#all the stuff +union Everything = Character | Episode""" + + } + + } diff --git a/src/test/groovy/graphql/introspection/example2.json b/src/test/groovy/graphql/introspection/example2.json new file mode 100644 index 0000000000..448ece6b88 --- /dev/null +++ b/src/test/groovy/graphql/introspection/example2.json @@ -0,0 +1,1300 @@ +{ + "data": { + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": { + "name": "MutationType" + }, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "character", + "description": null, + "args": [ + { + "name": "firstName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "search", + "description": null, + "args": [ + { + "name": "searchFor", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "UNION", + "name": "Everything", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Character", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "firstName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "lastName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "family", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "ID", + "description": "Built-in ID", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "Built-in String", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "Built-in Boolean", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "args": [], + "type": { + "kind": "ENUM", + "name": "Season", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "number", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "numberOverall", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "Season", + "description": " Simpson seasons", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "Season1", + "description": " the beginning", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season2", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season3", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season4", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season5", + "description": " Another one", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season6", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season7", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season8", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season9", + "description": " Not really the last one :-)", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Int", + "description": "Built-in Int", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "UNION", + "name": "Everything", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + ] + }, + { + "kind": "OBJECT", + "name": "MutationType", + "description": null, + "fields": [ + { + "name": "addCharacter", + "description": null, + "args": [ + { + "name": "character", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MutationResult", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "MutationResult", + "description": null, + "fields": [ + { + "name": "success", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "firstName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "lastName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "family", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "'A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "'If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": null, + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given __Type is", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "An enum describing valid locations where a directive can be placed", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Indicates the directive is valid on queries.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Indicates the directive is valid on mutations.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Indicates the directive is valid on fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Indicates the directive is valid on fragment definitions.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Indicates the directive is valid on fragment spreads.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Indicates the directive is valid on inline fragments.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + } + ] + } + } +} \ No newline at end of file From c9df1142054b17ecfc907eb65a2208a048af3a8b Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 09:50:02 +0200 Subject: [PATCH 07/10] wip --- .../IntrospectionResultToSchema.java | 41 ++++++++--- .../java/graphql/language/AstPrinter.java | 26 +++++-- .../IntrospectionResultToSchemaTest.groovy | 68 ++++++++++++++++++- .../graphql/parser/IDLParserTest.groovy | 25 ++++++- 4 files changed, 140 insertions(+), 20 deletions(-) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index 5bc1ced719..14935ede3a 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -4,6 +4,7 @@ import graphql.language.EnumTypeDefinition; import graphql.language.EnumValueDefinition; import graphql.language.FieldDefinition; +import graphql.language.InputObjectTypeDefinition; import graphql.language.InputValueDefinition; import graphql.language.InterfaceTypeDefinition; import graphql.language.ListType; @@ -86,6 +87,18 @@ public InterfaceTypeDefinition createInterface(Map input) { } + @SuppressWarnings("unchecked") + public InputObjectTypeDefinition createInputObject(Map input) { + assertTrue(input.get("kind").equals("INPUT_OBJECT"), "wrong input"); + + InputObjectTypeDefinition inputObjectTypeDefinition = new InputObjectTypeDefinition((String) input.get("name")); + inputObjectTypeDefinition.setComments(toComment((String) input.get("description"))); + List> fields = (List>) input.get("inputFields"); + List inputValueDefinitions = createInputValueDefinitions(fields); + inputObjectTypeDefinition.getInputValueDefinitions().addAll(inputValueDefinitions); + + return inputObjectTypeDefinition; + } @SuppressWarnings("unchecked") public ObjectTypeDefinition createObject(Map input) { @@ -108,18 +121,26 @@ private List createFields(List> fields) { fieldDefinition.setType(createType((Map) field.get("type"))); List> args = (List>) field.get("args"); + List inputValueDefinitions = createInputValueDefinitions(args); + fieldDefinition.getInputValueDefinitions().addAll(inputValueDefinitions); + result.add(fieldDefinition); + } + return result; + } - for (Map arg : args) { - Type argType = createType((Map) arg.get("type")); - InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType); - - if (arg.get("defaultValue") != null) { - StringValue defaultValue = new StringValue((String) arg.get("defaultValue")); - inputValueDefinition.setDefaultValue(defaultValue); - } - fieldDefinition.getInputValueDefinitions().add(inputValueDefinition); + @SuppressWarnings("unchecked") + private List createInputValueDefinitions(List> args) { + List result = new ArrayList<>(); + for (Map arg : args) { + Type argType = createType((Map) arg.get("type")); + InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType); + inputValueDefinition.setComments(toComment((String) arg.get("description"))); + + if (arg.get("defaultValue") != null) { + StringValue defaultValue = new StringValue((String) arg.get("defaultValue")); + inputValueDefinition.setDefaultValue(defaultValue); } - result.add(fieldDefinition); + result.add(inputValueDefinition); } return result; } diff --git a/src/main/java/graphql/language/AstPrinter.java b/src/main/java/graphql/language/AstPrinter.java index 5943191482..e596d07bf1 100644 --- a/src/main/java/graphql/language/AstPrinter.java +++ b/src/main/java/graphql/language/AstPrinter.java @@ -131,16 +131,30 @@ private static NodePrinter field() { private static NodePrinter fieldDefinition() { return (out, node) -> { - String args = join(node.getInputValueDefinitions(), ", "); out.printf("%s", comments(node)); - out.printf("%s", node.getName() + - wrap("(", args, ")") + - ": " + type(node.getType()) + - directives(node.getDirectives()) - ); + String args; + if (hasComments(node.getInputValueDefinitions())) { + args = join(node.getInputValueDefinitions(), "\n"); + out.printf("%s", node.getName() + + wrap("(\n", args, "\n)") + + ": " + type(node.getType()) + + directives(node.getDirectives()) + ); + } else { + args = join(node.getInputValueDefinitions(), ", "); + out.printf("%s", node.getName() + + wrap("(", args, ")") + + ": " + type(node.getType()) + + directives(node.getDirectives()) + ); + } }; } + private static boolean hasComments(List nodes) { + return nodes.stream().filter(it -> it.getComments().size() > 0).count() > 0; + } + private static NodePrinter fragmentDefinition() { return (out, node) -> { String name = node.getName(); diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index d758ea9b1a..9f50cd9ad0 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -30,7 +30,7 @@ class IntrospectionResultToSchemaTest extends Specification { }, { "name": "foo", - "description": "", + "description": null, "type": { "kind": "SCALAR", "name": "String", @@ -64,7 +64,11 @@ class IntrospectionResultToSchemaTest extends Specification { then: result == """type QueryType { - hero(episode: Episode, foo: String = \"bar\"): Character + hero( + #comment about episode + episode: Episode + foo: String = \"bar\" + ): Character }""" } @@ -269,6 +273,66 @@ union Everything = Character | Episode""" } + def "create input object"() { + def input = """ { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "description": "input for characters", + "fields": null, + "inputFields": [ + { + "name": "firstName", + "description": "first name", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "lastName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "family", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + InputObjectTypeDefinition inputObjectTypeDefinition = introspectionResultToSchema.createInputObject(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(inputObjectTypeDefinition) + + then: + result == """#input for characters +CharacterInput { + #first name + firstName: String + lastName: String + family: Boolean +}""" + } } diff --git a/src/test/groovy/graphql/parser/IDLParserTest.groovy b/src/test/groovy/graphql/parser/IDLParserTest.groovy index fa91517ff5..a619fb9c7b 100644 --- a/src/test/groovy/graphql/parser/IDLParserTest.groovy +++ b/src/test/groovy/graphql/parser/IDLParserTest.groovy @@ -372,7 +372,7 @@ directive @DirectiveName(arg1:String arg2:Int=23) on FIELD | QUERY List commentContent(List comments) { - comments.stream().map {c -> c.content}.collect(Collectors.toList()) + comments.stream().map { c -> c.content }.collect(Collectors.toList()) } def "comment support on definitions"() { @@ -447,7 +447,6 @@ input Gun { commentContent(schemaDef.comments) == ["schema comment 1", " schema comment 2 with leading spaces"] commentContent(schemaDef.operationTypeDefinitions[0].comments) == [" schema operation comment query"] commentContent(schemaDef.operationTypeDefinitions[1].comments) == [" schema operation comment mutation"] - ObjectTypeDefinition typeDef = document.definitions[1] as ObjectTypeDefinition commentContent(typeDef.comments) == [" type query comment 1", " type query comment 2"] commentContent(typeDef.fieldDefinitions[0].comments) == [" query field 'hero' comment"] @@ -473,4 +472,26 @@ input Gun { } + def "comments on field arguments"() { + def input = """ + type QueryType { + hero( + #comment about episode + episode: Episode + # second + foo: String = \"bar\" + ): Character + } +""" + when: + def document = new Parser().parseDocument(input) + + then: + ObjectTypeDefinition typeDef = document.definitions[0] as ObjectTypeDefinition + def inputValueDefinitions = typeDef.fieldDefinitions[0].inputValueDefinitions + commentContent(inputValueDefinitions[0].comments) == ["comment about episode"] + commentContent(inputValueDefinitions[1].comments) == [" second"] + } + } + From eae0efa9fb84097887b24a56cd71cbbca8e538dd Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 10:44:15 +0200 Subject: [PATCH 08/10] wip --- .../IntrospectionResultToSchema.java | 96 +++++++++++++++---- .../IntrospectionResultToSchemaTest.groovy | 29 ++++++ 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index 14935ede3a..0fbfccc3ec 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -1,6 +1,8 @@ package graphql.introspection; +import graphql.PublicApi; import graphql.language.Comment; +import graphql.language.Document; import graphql.language.EnumTypeDefinition; import graphql.language.EnumValueDefinition; import graphql.language.FieldDefinition; @@ -10,9 +12,12 @@ import graphql.language.ListType; import graphql.language.NonNullType; import graphql.language.ObjectTypeDefinition; +import graphql.language.OperationTypeDefinition; +import graphql.language.SchemaDefinition; import graphql.language.SourceLocation; import graphql.language.StringValue; import graphql.language.Type; +import graphql.language.TypeDefinition; import graphql.language.TypeName; import graphql.language.UnionTypeDefinition; @@ -22,24 +27,75 @@ import java.util.List; import java.util.Map; +import static graphql.Assert.assertNotNull; import static graphql.Assert.assertShouldNeverHappen; import static graphql.Assert.assertTrue; +@PublicApi public class IntrospectionResultToSchema { -// public String to(Map introspectionResult) { -// return null; -// } + @SuppressWarnings("unchecked") + public Document createSchemaDefinition(Map introspectionResult) { + assertTrue(introspectionResult.get("__schema") != null, "__schema expected"); + Map schema = (Map) introspectionResult.get("__schema"); - private List toComment(String description) { - if (description == null) return Collections.emptyList(); - Comment comment = new Comment(description, new SourceLocation(1, 1)); - return Arrays.asList(comment); + SchemaDefinition schemaDefinition = new SchemaDefinition(); + + Map queryType = (Map) schema.get("queryType"); + assertNotNull(queryType, "queryType expected"); + TypeName query = new TypeName((String) queryType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("query", query)); + + Map mutationType = (Map) schema.get("mutationType"); + if (mutationType != null) { + TypeName mutation = new TypeName((String) mutationType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("mutation", mutation)); + } + + Map subscriptionType = (Map) schema.get("subscriptionType"); + if (subscriptionType != null) { + TypeName subscription = new TypeName((String) subscriptionType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("subscription", subscription)); + } + + Document document = new Document(); + document.getDefinitions().add(schemaDefinition); + + List> types = (List>) introspectionResult.get("types"); + if (types != null) { + for (Map type : types) { + TypeDefinition typeDefinition = createTypeDefintion(type); + document.getDefinitions().add(typeDefinition); + } + } + + return document; + } + + private TypeDefinition createTypeDefintion(Map type) { + String kind = (String) type.get("kind"); + switch (kind) { + case "INTERFACE": + return createInterface(type); + case "OBJECT": + return createObject(type); + case "UNION": + return createUnion(type); + case "ENUM": + return createEnum(type); + case "INPUT_OBJECT": + return createInputObject(type); +// case "SCALAR": +// return new TypeName((String) type.get("name")); + default: + return assertShouldNeverHappen("unexpected kind " + kind); + } } + @SuppressWarnings("unchecked") - public UnionTypeDefinition createUnion(Map input) { + UnionTypeDefinition createUnion(Map input) { assertTrue(input.get("kind").equals("UNION"), "wrong input"); UnionTypeDefinition unionTypeDefinition = new UnionTypeDefinition((String) input.get("name")); @@ -56,7 +112,7 @@ public UnionTypeDefinition createUnion(Map input) { } @SuppressWarnings("unchecked") - public EnumTypeDefinition createEnum(Map input) { + EnumTypeDefinition createEnum(Map input) { assertTrue(input.get("kind").equals("ENUM"), "wrong input"); EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition((String) input.get("name")); @@ -75,7 +131,7 @@ public EnumTypeDefinition createEnum(Map input) { } @SuppressWarnings("unchecked") - public InterfaceTypeDefinition createInterface(Map input) { + InterfaceTypeDefinition createInterface(Map input) { assertTrue(input.get("kind").equals("INTERFACE"), "wrong input"); InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name")); @@ -88,7 +144,7 @@ public InterfaceTypeDefinition createInterface(Map input) { } @SuppressWarnings("unchecked") - public InputObjectTypeDefinition createInputObject(Map input) { + InputObjectTypeDefinition createInputObject(Map input) { assertTrue(input.get("kind").equals("INPUT_OBJECT"), "wrong input"); InputObjectTypeDefinition inputObjectTypeDefinition = new InputObjectTypeDefinition((String) input.get("name")); @@ -101,7 +157,7 @@ public InputObjectTypeDefinition createInputObject(Map input) { } @SuppressWarnings("unchecked") - public ObjectTypeDefinition createObject(Map input) { + ObjectTypeDefinition createObject(Map input) { assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name")); @@ -118,7 +174,7 @@ private List createFields(List> fields) { for (Map field : fields) { FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name")); fieldDefinition.setComments(toComment((String) field.get("description"))); - fieldDefinition.setType(createType((Map) field.get("type"))); + fieldDefinition.setType(createTypeIndirection((Map) field.get("type"))); List> args = (List>) field.get("args"); List inputValueDefinitions = createInputValueDefinitions(args); @@ -132,7 +188,7 @@ private List createFields(List> fields) { private List createInputValueDefinitions(List> args) { List result = new ArrayList<>(); for (Map arg : args) { - Type argType = createType((Map) arg.get("type")); + Type argType = createTypeIndirection((Map) arg.get("type")); InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType); inputValueDefinition.setComments(toComment((String) arg.get("description"))); @@ -146,7 +202,7 @@ private List createInputValueDefinitions(List type) { + private Type createTypeIndirection(Map type) { String kind = (String) type.get("kind"); switch (kind) { case "INTERFACE": @@ -157,12 +213,18 @@ Type createType(Map type) { case "SCALAR": return new TypeName((String) type.get("name")); case "NON_NULL": - return new NonNullType(createType((Map) type.get("ofType"))); + return new NonNullType(createTypeIndirection((Map) type.get("ofType"))); case "LIST": - return new ListType(createType((Map) type.get("ofType"))); + return new ListType(createTypeIndirection((Map) type.get("ofType"))); default: return assertShouldNeverHappen("Unknown kind " + kind); } } + private List toComment(String description) { + if (description == null) return Collections.emptyList(); + Comment comment = new Comment(description, new SourceLocation(1, 1)); + return Arrays.asList(comment); + } + } diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 9f50cd9ad0..3312a09a30 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -334,5 +334,34 @@ CharacterInput { }""" } + + def "create schema"() { + def input = """{ + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": {"name":"MutationType"}, + "subscriptionType": {"name":"SubscriptionType"}, + "types": [ + ] + }""" + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType + mutation: MutationType + subscription: SubscriptionType +} +""" + + } } From eea8ef7b4635fd221eb297edbb186ba8ada114f4 Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 11:11:47 +0200 Subject: [PATCH 09/10] wip --- .../IntrospectionResultToSchema.java | 20 ++-- .../IntrospectionResultToSchemaTest.groovy | 91 ++++++++++++++++++- .../simpsons-introspection.json} | 0 .../starwars-introspection.json} | 0 4 files changed, 101 insertions(+), 10 deletions(-) rename src/test/{groovy/graphql/introspection/example2.json => resources/simpsons-introspection.json} (100%) rename src/test/{groovy/graphql/introspection/example.json => resources/starwars-introspection.json} (100%) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index 0fbfccc3ec..54569829df 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -62,19 +62,20 @@ public Document createSchemaDefinition(Map introspectionResult) Document document = new Document(); document.getDefinitions().add(schemaDefinition); - List> types = (List>) introspectionResult.get("types"); - if (types != null) { - for (Map type : types) { - TypeDefinition typeDefinition = createTypeDefintion(type); - document.getDefinitions().add(typeDefinition); - } + List> types = (List>) schema.get("types"); + for (Map type : types) { + TypeDefinition typeDefinition = createTypeDefinition(type); + if (typeDefinition == null) continue; + document.getDefinitions().add(typeDefinition); } return document; } - private TypeDefinition createTypeDefintion(Map type) { + private TypeDefinition createTypeDefinition(Map type) { String kind = (String) type.get("kind"); + String name = (String) type.get("name"); + if (name.startsWith("__")) return null; switch (kind) { case "INTERFACE": return createInterface(type); @@ -86,8 +87,9 @@ private TypeDefinition createTypeDefintion(Map type) { return createEnum(type); case "INPUT_OBJECT": return createInputObject(type); -// case "SCALAR": -// return new TypeName((String) type.get("name")); + case "SCALAR": + // todo don't ignore all scalars + return null; default: return assertShouldNeverHappen("unexpected kind " + kind); } diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index 3312a09a30..a876d4f613 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -1,6 +1,12 @@ package graphql.introspection -import graphql.language.* +import graphql.language.AstPrinter +import graphql.language.Document +import graphql.language.EnumTypeDefinition +import graphql.language.InputObjectTypeDefinition +import graphql.language.InterfaceTypeDefinition +import graphql.language.ObjectTypeDefinition +import graphql.language.UnionTypeDefinition import groovy.json.JsonSlurper import spock.lang.Specification @@ -363,5 +369,88 @@ CharacterInput { """ } + + def "test starwars introspection result"() { + given: + String starwars = this.getClass().getResource('/starwars-introspection.json').text + def slurper = new JsonSlurper() + def parsed = slurper.parseText(starwars) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType +} + +type QueryType { + hero( + #If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode. + episode: Episode + ): Character + human( + #id of the human + id: String! + ): Human + droid( + #id of the droid + id: String! + ): Droid +} + +#A character in the Star Wars Trilogy +interface Character { + #The id of the character. + id: String! + #The name of the character. + name: String + #The friends of the character, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] +} + +#One of the films in the Star Wars Trilogy +enum Episode { + #Released in 1977. + NEWHOPE + #Released in 1980. + EMPIRE + #Released in 1983. + JEDI +} + +#A humanoid creature in the Star Wars universe. +type Human { + #The id of the human. + id: String! + #The name of the human. + name: String + #The friends of the human, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] + #The home planet of the human, or null if unknown. + homePlanet: String +} + +#A mechanical creature in the Star Wars universe. +type Droid { + #The id of the droid. + id: String! + #The name of the droid. + name: String + #The friends of the droid, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] + #The primary function of the droid. + primaryFunction: String +} +""" + } } diff --git a/src/test/groovy/graphql/introspection/example2.json b/src/test/resources/simpsons-introspection.json similarity index 100% rename from src/test/groovy/graphql/introspection/example2.json rename to src/test/resources/simpsons-introspection.json diff --git a/src/test/groovy/graphql/introspection/example.json b/src/test/resources/starwars-introspection.json similarity index 100% rename from src/test/groovy/graphql/introspection/example.json rename to src/test/resources/starwars-introspection.json From ab6405cc4ca5115d7b645fcbf5048bdd30fc1284 Mon Sep 17 00:00:00 2001 From: andimarek Date: Thu, 25 May 2017 11:17:01 +0200 Subject: [PATCH 10/10] done for now --- .../IntrospectionResultToSchema.java | 2 +- .../IntrospectionResultToSchemaTest.groovy | 75 + .../resources/simpsons-introspection.json | 2340 ++++++++--------- 3 files changed, 1245 insertions(+), 1172 deletions(-) diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java index 54569829df..06c74bbba2 100644 --- a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -211,7 +211,7 @@ private Type createTypeIndirection(Map type) { case "OBJECT": case "UNION": case "ENUM": - return new TypeName((String) type.get("name")); + case "INPUT_OBJECT": case "SCALAR": return new TypeName((String) type.get("name")); case "NON_NULL": diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy index a876d4f613..c8002d93c2 100644 --- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -450,6 +450,81 @@ type Droid { #The primary function of the droid. primaryFunction: String } +""" + } + + def "test simpsons introspection result"() { + given: + String simpsons = this.getClass().getResource('/simpsons-introspection.json').text + def slurper = new JsonSlurper() + def parsed = slurper.parseText(simpsons) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType + mutation: MutationType +} + +type QueryType { + character(firstName: String): Character + characters: [Character] + episodes: [Episode] + search(searchFor: String): [Everything] +} + +type Character { + id: ID! + firstName: String + lastName: String + family: Boolean + episodes: [Episode] +} + +type Episode { + id: ID! + name: String + season: Season + number: Int + numberOverall: Int + characters: [Character] +} + +# Simpson seasons +enum Season { + # the beginning + Season1 + Season2 + Season3 + Season4 + # Another one + Season5 + Season6 + Season7 + Season8 + # Not really the last one :-) + Season9 +} + +union Everything = Character | Episode + +type MutationType { + addCharacter(character: CharacterInput): MutationResult +} + +type MutationResult { + success: Boolean +} + +CharacterInput { + firstName: String + lastName: String + family: Boolean +} """ } } diff --git a/src/test/resources/simpsons-introspection.json b/src/test/resources/simpsons-introspection.json index 448ece6b88..447a6c8641 100644 --- a/src/test/resources/simpsons-introspection.json +++ b/src/test/resources/simpsons-introspection.json @@ -1,701 +1,513 @@ { - "data": { - "__schema": { - "queryType": { - "name": "QueryType" - }, - "mutationType": { - "name": "MutationType" - }, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "QueryType", - "description": null, - "fields": [ - { - "name": "character", - "description": null, - "args": [ - { - "name": "firstName", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "characters", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Episode", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "search", - "description": null, - "args": [ - { - "name": "searchFor", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "UNION", - "name": "Everything", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Character", - "description": null, - "fields": [ - { - "name": "id", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": { + "name": "MutationType" + }, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "character", + "description": null, + "args": [ + { + "name": "firstName", + "description": null, + "type": { "kind": "SCALAR", - "name": "ID", + "name": "String", "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "firstName", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Character", + "ofType": null }, - { - "name": "lastName", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Character", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "family", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Boolean", + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Episode", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "Built-in ID", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "Built-in String", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "Built-in Boolean", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Episode", - "description": null, - "fields": [ - { - "name": "id", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "search", + "description": null, + "args": [ + { + "name": "searchFor", + "description": null, + "type": { "kind": "SCALAR", - "name": "ID", + "name": "String", "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "UNION", + "name": "Everything", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "season", - "description": null, - "args": [], - "type": { - "kind": "ENUM", - "name": "Season", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "number", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "numberOverall", - "description": null, - "args": [], - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Character", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", - "name": "Int", + "name": "ID", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "characters", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "Season", - "description": " Simpson seasons", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "Season1", - "description": " the beginning", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season2", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season3", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season4", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season5", - "description": " Another one", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season6", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season7", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Season8", - "description": null, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "firstName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "Season9", - "description": " Not really the last one :-)", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "Built-in Int", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "UNION", - "name": "Everything", - "description": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Character", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "lastName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", "ofType": null }, - { - "kind": "OBJECT", - "name": "Episode", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "family", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", "ofType": null - } - ] - }, - { - "kind": "OBJECT", - "name": "MutationType", - "description": null, - "fields": [ - { - "name": "addCharacter", - "description": null, - "args": [ - { - "name": "character", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "CharacterInput", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "MutationResult", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "MutationResult", - "description": null, - "fields": [ - { - "name": "success", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CharacterInput", - "description": null, - "fields": null, - "inputFields": [ - { - "name": "firstName", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null }, - { - "name": "lastName", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", "ofType": null - }, - "defaultValue": null - }, - { - "name": "family", - "description": null, - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "ID", + "description": "Built-in ID", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "Built-in String", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "Built-in Boolean", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", - "name": "Boolean", + "name": "ID", "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "args": [], + "type": { + "kind": "ENUM", + "name": "Season", + "ofType": null }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "number", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null }, - { - "name": "directives", - "description": "'A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "numberOverall", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null }, - { - "name": "subscriptionType", - "description": "'If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "OBJECT", - "name": "__Type", + "name": "Character", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": null, - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "Season", + "description": " Simpson seasons", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "Season1", + "description": " the beginning", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season2", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season3", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season4", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season5", + "description": " Another one", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season6", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season7", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season8", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season9", + "description": " Not really the last one :-)", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Int", + "description": "Built-in Int", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "UNION", + "name": "Everything", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + ] + }, + { + "kind": "OBJECT", + "name": "MutationType", + "description": null, + "fields": [ + { + "name": "addCharacter", + "description": null, + "args": [ + { + "name": "character", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MutationResult", + "ofType": null }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "MutationResult", + "description": null, + "fields": [ + { + "name": "success", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "firstName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null + "defaultValue": null + }, + { + "name": "lastName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null + "defaultValue": null + }, + { + "name": "family", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "LIST", "name": null, "ofType": { @@ -707,46 +519,47 @@ "ofType": null } } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null }, - { - "name": "inputFields", - "description": null, - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "'A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "LIST", "name": null, "ofType": { @@ -754,153 +567,117 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "__InputValue", + "name": "__Directive", "ofType": null } } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "'If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": null, + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given __Type is", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": null, - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { "kind": "SCALAR", - "name": "String", + "name": "Boolean", "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } + "kind": "OBJECT", + "name": "__Field", + "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "NON_NULL", "name": null, "ofType": { @@ -908,393 +685,614 @@ "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "Boolean", + "kind": "OBJECT", + "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": null, - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { "kind": "SCALAR", - "name": "String", + "name": "Boolean", "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", - "name": "__Type", + "name": "__EnumValue", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": null, - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "__InputValue", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null }, - { - "name": "description", - "description": null, - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given __Type is", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": null, - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "description", - "description": null, - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Boolean", "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null }, - { - "name": "locations", - "description": null, - "args": [], - "type": { + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", + "kind": "OBJECT", + "name": "__InputValue", "ofType": null } } - }, - "isDeprecated": false, - "deprecationReason": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, - { - "name": "onOperation", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, - { - "name": "onFragment", - "description": null, - "args": [], - "type": { + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "An enum describing valid locations where a directive can be placed", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Indicates the directive is valid on queries.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Indicates the directive is valid on mutations.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Indicates the directive is valid on fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Indicates the directive is valid on fragment definitions.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Indicates the directive is valid on fragment spreads.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Indicates the directive is valid on inline fragments.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." + } }, - { - "name": "onField", - "description": null, - "args": [], - "type": { + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "An enum describing valid locations where a directive can be placed", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Indicates the directive is valid on queries.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Indicates the directive is valid on mutations.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Indicates the directive is valid on fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Indicates the directive is valid on fragment definitions.", - "isDeprecated": false, - "deprecationReason": null + } }, - { - "name": "FRAGMENT_SPREAD", - "description": "Indicates the directive is valid on fragment spreads.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Indicates the directive is valid on inline fragments.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - } - ] - } + "defaultValue": null + } + ] + } + ] } } \ No newline at end of file