From 302058a7705f008c6877373e2e701332b6e50469 Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Sat, 17 Mar 2018 10:46:18 +1100 Subject: [PATCH] Use default entry points for Query/Mutation/Subscription --- codegen/build.go | 5 +++++ example/chat/generated.go | 2 +- example/chat/schema.graphql | 6 ------ example/dataloader/generated.go | 2 +- example/dataloader/schema.graphql | 4 ---- example/scalars/generated.go | 2 +- example/scalars/schema.graphql | 4 ---- example/starwars/generated.go | 2 +- example/starwars/schema.graphql | 4 ---- neelance/schema/schema.go | 18 ++++++++++++++++++ test/generated.go | 2 +- test/schema.graphql | 4 ---- 12 files changed, 28 insertions(+), 27 deletions(-) diff --git a/codegen/build.go b/codegen/build.go index 847cdebcce..c4cfcb4655 100644 --- a/codegen/build.go +++ b/codegen/build.go @@ -1,6 +1,7 @@ package codegen import ( + "fmt" "go/build" "go/types" "os" @@ -83,6 +84,10 @@ func Bind(schema *schema.Schema, userTypes map[string]string, destDir string) (* b.SubscriptionRoot = b.Objects.ByName(sr.TypeName()) } + if b.QueryRoot == nil { + return b, fmt.Errorf("query entry point missing") + } + // Poke a few magic methods into query q := b.Objects.ByName(b.QueryRoot.GQLType) q.Fields = append(q.Fields, Field{ diff --git a/example/chat/generated.go b/example/chat/generated.go index 7f756e9562..6008f708f2 100644 --- a/example/chat/generated.go +++ b/example/chat/generated.go @@ -864,7 +864,7 @@ func (ec *executionContext) ___Type_ofType(field graphql.CollectedField, obj *in return ec.___Type(field.Selections, res) } -var parsedSchema = schema.MustParse("type Chatroom {\n name: String!\n messages: [Message!]!\n}\n\ntype Message {\n id: ID!\n text: String!\n createdBy: String!\n createdAt: Time!\n}\n\ntype Query {\n room(name:String!): Chatroom\n}\n\ntype Mutation {\n post(text: String!, username: String!, roomName: String!): Message!\n}\n\ntype Subscription {\n messageAdded(roomName: String!): Message!\n}\n\nschema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\nscalar Time\n") +var parsedSchema = schema.MustParse("type Chatroom {\n name: String!\n messages: [Message!]!\n}\n\ntype Message {\n id: ID!\n text: String!\n createdBy: String!\n createdAt: Time!\n}\n\ntype Query {\n room(name:String!): Chatroom\n}\n\ntype Mutation {\n post(text: String!, username: String!, roomName: String!): Message!\n}\n\ntype Subscription {\n messageAdded(roomName: String!): Message!\n}\n\nscalar Time\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/example/chat/schema.graphql b/example/chat/schema.graphql index 9cb79ed912..85a46768ed 100644 --- a/example/chat/schema.graphql +++ b/example/chat/schema.graphql @@ -22,10 +22,4 @@ type Subscription { messageAdded(roomName: String!): Message! } -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - scalar Time diff --git a/example/dataloader/generated.go b/example/dataloader/generated.go index 45c6262ba4..8b4659711b 100644 --- a/example/dataloader/generated.go +++ b/example/dataloader/generated.go @@ -895,7 +895,7 @@ func (ec *executionContext) ___Type_ofType(field graphql.CollectedField, obj *in return ec.___Type(field.Selections, res) } -var parsedSchema = schema.MustParse("schema {\n query: Query\n}\n\ntype Query {\n customers: [Customer!]\n\n # this method is here to test code generation of nested arrays\n torture(customerIds: [[Int]]): [[Customer!]]\n}\n\ntype Customer {\n id: Int!\n name: String!\n address: Address\n orders: [Order!]\n}\n\ntype Address {\n id: Int!\n street: String!\n country: String!\n}\n\ntype Order {\n id: Int!\n date: Time!\n amount: Float!\n items: [Item!]\n}\n\ntype Item {\n name: String!\n}\nscalar Time\n") +var parsedSchema = schema.MustParse("type Query {\n customers: [Customer!]\n\n # this method is here to test code generation of nested arrays\n torture(customerIds: [[Int]]): [[Customer!]]\n}\n\ntype Customer {\n id: Int!\n name: String!\n address: Address\n orders: [Order!]\n}\n\ntype Address {\n id: Int!\n street: String!\n country: String!\n}\n\ntype Order {\n id: Int!\n date: Time!\n amount: Float!\n items: [Item!]\n}\n\ntype Item {\n name: String!\n}\nscalar Time\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/example/dataloader/schema.graphql b/example/dataloader/schema.graphql index 152d944fdf..1d8165bbb4 100644 --- a/example/dataloader/schema.graphql +++ b/example/dataloader/schema.graphql @@ -1,7 +1,3 @@ -schema { - query: Query -} - type Query { customers: [Customer!] diff --git a/example/scalars/generated.go b/example/scalars/generated.go index f0052d0c25..78c75b25e7 100644 --- a/example/scalars/generated.go +++ b/example/scalars/generated.go @@ -776,7 +776,7 @@ func UnmarshalSearchArgs(v interface{}) (SearchArgs, error) { return it, nil } -var parsedSchema = schema.MustParse("schema {\n query: Query\n}\n\ntype Query {\n user(id: ID!): User\n search(input: SearchArgs = {location: \"37,144\"}): [User!]!\n}\n\ntype User {\n id: ID!\n name: String!\n created: Timestamp\n location: Point\n isBanned: Boolean!\n}\n\ninput SearchArgs {\n location: Point\n createdAfter: Timestamp\n isBanned: Boolean\n}\n\nscalar Timestamp\nscalar Point\n") +var parsedSchema = schema.MustParse("type Query {\n user(id: ID!): User\n search(input: SearchArgs = {location: \"37,144\"}): [User!]!\n}\n\ntype User {\n id: ID!\n name: String!\n created: Timestamp\n location: Point\n isBanned: Boolean!\n}\n\ninput SearchArgs {\n location: Point\n createdAfter: Timestamp\n isBanned: Boolean\n}\n\nscalar Timestamp\nscalar Point\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/example/scalars/schema.graphql b/example/scalars/schema.graphql index f841391ac4..0ca4c890b0 100644 --- a/example/scalars/schema.graphql +++ b/example/scalars/schema.graphql @@ -1,7 +1,3 @@ -schema { - query: Query -} - type Query { user(id: ID!): User search(input: SearchArgs = {location: "37,144"}): [User!]! diff --git a/example/starwars/generated.go b/example/starwars/generated.go index 2b2c0a60a3..f88d61e518 100644 --- a/example/starwars/generated.go +++ b/example/starwars/generated.go @@ -1583,7 +1583,7 @@ func UnmarshalReviewInput(v interface{}) (Review, error) { return it, nil } -var parsedSchema = schema.MustParse("schema {\n query: Query\n mutation: Mutation\n}\n# The query type, represents all of the entry points into our object graph\ntype Query {\n hero(episode: Episode = NEWHOPE): Character\n reviews(episode: Episode!, since: Time): [Review]!\n search(text: String!): [SearchResult]!\n character(id: ID!): Character\n droid(id: ID!): Droid\n human(id: ID!): Human\n starship(id: ID!): Starship\n}\n# The mutation type, represents all updates we can make to our data\ntype Mutation {\n createReview(episode: Episode!, review: ReviewInput!): Review\n}\n# The episodes in the Star Wars trilogy\nenum Episode {\n # Star Wars Episode IV: A New Hope, released in 1977.\n NEWHOPE\n # Star Wars Episode V: The Empire Strikes Back, released in 1980.\n EMPIRE\n # Star Wars Episode VI: Return of the Jedi, released in 1983.\n JEDI\n}\n# A character from the Star Wars universe\ninterface Character {\n # The ID of the character\n id: ID!\n # The name of the character\n name: String!\n # The friends of the character, or an empty list if they have none\n friends: [Character]\n # The friends of the character exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this character appears in\n appearsIn: [Episode!]!\n}\n# Units of height\nenum LengthUnit {\n # The standard unit around the world\n METER\n # Primarily used in the United States\n FOOT\n}\n# A humanoid creature from the Star Wars universe\ntype Human implements Character {\n # The ID of the human\n id: ID!\n # What this human calls themselves\n name: String!\n # Height in the preferred unit, default is meters\n height(unit: LengthUnit = METER): Float!\n # Mass in kilograms, or null if unknown\n mass: Float\n # This human's friends, or an empty list if they have none\n friends: [Character]\n # The friends of the human exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this human appears in\n appearsIn: [Episode!]!\n # A list of starships this person has piloted, or an empty list if none\n starships: [Starship]\n}\n# An autonomous mechanical character in the Star Wars universe\ntype Droid implements Character {\n # The ID of the droid\n id: ID!\n # What others call this droid\n name: String!\n # This droid's friends, or an empty list if they have none\n friends: [Character]\n # The friends of the droid exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this droid appears in\n appearsIn: [Episode!]!\n # This droid's primary function\n primaryFunction: String\n}\n# A connection object for a character's friends\ntype FriendsConnection {\n # The total number of friends\n totalCount: Int!\n # The edges for each of the character's friends.\n edges: [FriendsEdge]\n # A list of the friends, as a convenience when edges are not needed.\n friends: [Character]\n # Information for paginating this connection\n pageInfo: PageInfo!\n}\n# An edge object for a character's friends\ntype FriendsEdge {\n # A cursor used for pagination\n cursor: ID!\n # The character represented by this friendship edge\n node: Character\n}\n# Information for paginating this connection\ntype PageInfo {\n startCursor: ID!\n endCursor: ID!\n hasNextPage: Boolean!\n}\n# Represents a review for a movie\ntype Review {\n # The number of stars this review gave, 1-5\n stars: Int!\n # Comment about the movie\n commentary: String\n # when the review was posted\n time: Time\n}\n# The input object sent when someone is creating a new review\ninput ReviewInput {\n # 0-5 stars\n stars: Int!\n # Comment about the movie, optional\n commentary: String\n # when the review was posted\n time: Time\n}\ntype Starship {\n # The ID of the starship\n id: ID!\n # The name of the starship\n name: String!\n # Length of the starship, along the longest axis\n length(unit: LengthUnit = METER): Float!\n # coordinates tracking this ship\n history: [[Int]]\n}\nunion SearchResult = Human | Droid | Starship\nscalar Time\n") +var parsedSchema = schema.MustParse("# The query type, represents all of the entry points into our object graph\ntype Query {\n hero(episode: Episode = NEWHOPE): Character\n reviews(episode: Episode!, since: Time): [Review]!\n search(text: String!): [SearchResult]!\n character(id: ID!): Character\n droid(id: ID!): Droid\n human(id: ID!): Human\n starship(id: ID!): Starship\n}\n# The mutation type, represents all updates we can make to our data\ntype Mutation {\n createReview(episode: Episode!, review: ReviewInput!): Review\n}\n# The episodes in the Star Wars trilogy\nenum Episode {\n # Star Wars Episode IV: A New Hope, released in 1977.\n NEWHOPE\n # Star Wars Episode V: The Empire Strikes Back, released in 1980.\n EMPIRE\n # Star Wars Episode VI: Return of the Jedi, released in 1983.\n JEDI\n}\n# A character from the Star Wars universe\ninterface Character {\n # The ID of the character\n id: ID!\n # The name of the character\n name: String!\n # The friends of the character, or an empty list if they have none\n friends: [Character]\n # The friends of the character exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this character appears in\n appearsIn: [Episode!]!\n}\n# Units of height\nenum LengthUnit {\n # The standard unit around the world\n METER\n # Primarily used in the United States\n FOOT\n}\n# A humanoid creature from the Star Wars universe\ntype Human implements Character {\n # The ID of the human\n id: ID!\n # What this human calls themselves\n name: String!\n # Height in the preferred unit, default is meters\n height(unit: LengthUnit = METER): Float!\n # Mass in kilograms, or null if unknown\n mass: Float\n # This human's friends, or an empty list if they have none\n friends: [Character]\n # The friends of the human exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this human appears in\n appearsIn: [Episode!]!\n # A list of starships this person has piloted, or an empty list if none\n starships: [Starship]\n}\n# An autonomous mechanical character in the Star Wars universe\ntype Droid implements Character {\n # The ID of the droid\n id: ID!\n # What others call this droid\n name: String!\n # This droid's friends, or an empty list if they have none\n friends: [Character]\n # The friends of the droid exposed as a connection with edges\n friendsConnection(first: Int, after: ID): FriendsConnection!\n # The movies this droid appears in\n appearsIn: [Episode!]!\n # This droid's primary function\n primaryFunction: String\n}\n# A connection object for a character's friends\ntype FriendsConnection {\n # The total number of friends\n totalCount: Int!\n # The edges for each of the character's friends.\n edges: [FriendsEdge]\n # A list of the friends, as a convenience when edges are not needed.\n friends: [Character]\n # Information for paginating this connection\n pageInfo: PageInfo!\n}\n# An edge object for a character's friends\ntype FriendsEdge {\n # A cursor used for pagination\n cursor: ID!\n # The character represented by this friendship edge\n node: Character\n}\n# Information for paginating this connection\ntype PageInfo {\n startCursor: ID!\n endCursor: ID!\n hasNextPage: Boolean!\n}\n# Represents a review for a movie\ntype Review {\n # The number of stars this review gave, 1-5\n stars: Int!\n # Comment about the movie\n commentary: String\n # when the review was posted\n time: Time\n}\n# The input object sent when someone is creating a new review\ninput ReviewInput {\n # 0-5 stars\n stars: Int!\n # Comment about the movie, optional\n commentary: String\n # when the review was posted\n time: Time\n}\ntype Starship {\n # The ID of the starship\n id: ID!\n # The name of the starship\n name: String!\n # Length of the starship, along the longest axis\n length(unit: LengthUnit = METER): Float!\n # coordinates tracking this ship\n history: [[Int]]\n}\nunion SearchResult = Human | Droid | Starship\nscalar Time\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/example/starwars/schema.graphql b/example/starwars/schema.graphql index f55b801c17..58007fac2b 100644 --- a/example/starwars/schema.graphql +++ b/example/starwars/schema.graphql @@ -1,7 +1,3 @@ -schema { - query: Query - mutation: Mutation -} # The query type, represents all of the entry points into our object graph type Query { hero(episode: Episode = NEWHOPE): Character diff --git a/neelance/schema/schema.go b/neelance/schema/schema.go index c5a644f25a..0b1317a5e4 100644 --- a/neelance/schema/schema.go +++ b/neelance/schema/schema.go @@ -20,6 +20,12 @@ type Schema struct { enums []*Enum } +var defaultEntrypoints = map[string]string{ + "query": "Query", + "mutation": "Mutation", + "subscription": "Subscription", +} + func (s *Schema) Resolve(name string) common.Type { return s.Types[name] } @@ -203,6 +209,18 @@ func (s *Schema) Parse(schemaString string) error { s.EntryPoints[key] = t } + for entrypointName, typeName := range defaultEntrypoints { + if _, ok := s.EntryPoints[entrypointName]; ok { + continue + } + + if _, ok := s.Types[typeName]; !ok { + continue + } + + s.EntryPoints[entrypointName] = s.Types[typeName] + } + for _, obj := range s.objects { obj.Interfaces = make([]*Interface, len(obj.interfaceNames)) for i, intfName := range obj.interfaceNames { diff --git a/test/generated.go b/test/generated.go index 3c17333773..5922ce6cd6 100644 --- a/test/generated.go +++ b/test/generated.go @@ -798,7 +798,7 @@ func UnmarshalOuterInput(v interface{}) (OuterInput, error) { return it, nil } -var parsedSchema = schema.MustParse("input InnerInput {\n id:Int!\n}\n\ninput OuterInput {\n inner: InnerInput!\n}\n\ntype OuterObject {\n inner: InnerObject!\n}\n\ntype InnerObject {\n id: Int!\n}\n\ntype Query {\n nestedInputs(input: [[OuterInput]] = [[{inner: {id: 1}}]]): Boolean\n nestedOutputs: [[OuterObject]]\n}\n\nschema {\n query :Query\n}\n") +var parsedSchema = schema.MustParse("input InnerInput {\n id:Int!\n}\n\ninput OuterInput {\n inner: InnerInput!\n}\n\ntype OuterObject {\n inner: InnerObject!\n}\n\ntype InnerObject {\n id: Int!\n}\n\ntype Query {\n nestedInputs(input: [[OuterInput]] = [[{inner: {id: 1}}]]): Boolean\n nestedOutputs: [[OuterObject]]\n}\n") func (ec *executionContext) introspectSchema() *introspection.Schema { return introspection.WrapSchema(parsedSchema) diff --git a/test/schema.graphql b/test/schema.graphql index 1caa376017..143a76cc01 100644 --- a/test/schema.graphql +++ b/test/schema.graphql @@ -18,7 +18,3 @@ type Query { nestedInputs(input: [[OuterInput]] = [[{inner: {id: 1}}]]): Boolean nestedOutputs: [[OuterObject]] } - -schema { - query :Query -}