diff --git a/graphql/schema/gqlschema.go b/graphql/schema/gqlschema.go index 4774c7d7923..57800555ea2 100644 --- a/graphql/schema/gqlschema.go +++ b/graphql/schema/gqlschema.go @@ -2428,6 +2428,17 @@ func generateUnionString(typ *ast.Definition) string { strings.Join(typ.Types, " | ")) } +func hasStringifiableFields(typ *ast.Definition) bool { + queriesToWrite := false + for _, fld := range typ.Fields { + if !strings.HasPrefix(fld.Name, "__") { + queriesToWrite = true + break + } + } + return queriesToWrite +} + // Stringify the schema as a GraphQL SDL string. It's assumed that the schema was // built by completeSchema, and so contains an original set of definitions, the // definitions from schemaExtras and generated types, queries and mutations. @@ -2554,7 +2565,7 @@ func Stringify(schema *ast.Schema, originalTypes []string, apolloServiceQuery bo x.Check2(sch.WriteString(input.String())) } - if len(schema.Query.Fields) > 0 { + if hasStringifiableFields(schema.Query) { x.Check2(sch.WriteString( "#######################\n# Generated Query\n#######################\n\n")) x.Check2(sch.WriteString(generateObjectString(schema.Query) + "\n")) diff --git a/graphql/schema/testdata/apolloservice/input/single-extended-type.graphql b/graphql/schema/testdata/apolloservice/input/single-extended-type.graphql new file mode 100644 index 00000000000..fc4475d6c72 --- /dev/null +++ b/graphql/schema/testdata/apolloservice/input/single-extended-type.graphql @@ -0,0 +1,4 @@ +extend type Product @key(fields: "id") { + id: String! @id @external + name: String! +} diff --git a/graphql/schema/testdata/apolloservice/output/single-extended-type.graphql b/graphql/schema/testdata/apolloservice/output/single-extended-type.graphql new file mode 100644 index 00000000000..e63d6c9184d --- /dev/null +++ b/graphql/schema/testdata/apolloservice/output/single-extended-type.graphql @@ -0,0 +1,349 @@ +####################### +# Input Schema +####################### + +type Product @key(fields: "id") @extends { + id: String! @id @external + name: String! +} + +####################### +# Extended Definitions +####################### + +""" +The Int64 scalar type represents a signed 64‐bit numeric non‐fractional value. +Int64 can represent values in range [-(2^63),(2^63 - 1)]. +""" +scalar Int64 + +""" +The DateTime scalar type represents date and time as a string in RFC3339 format. +For example: "1985-04-12T23:20:50.52Z" represents 20 minutes and 50.52 seconds after the 23rd hour of April 12th, 1985 in UTC. +""" +scalar DateTime + +input IntRange{ + min: Int! + max: Int! +} + +input FloatRange{ + min: Float! + max: Float! +} + +input Int64Range{ + min: Int64! + max: Int64! +} + +input DateTimeRange{ + min: DateTime! + max: DateTime! +} + +input StringRange{ + min: String! + max: String! +} + +enum DgraphIndex { + int + int64 + float + bool + hash + exact + term + fulltext + trigram + regexp + year + month + day + hour + geo +} + +input AuthRule { + and: [AuthRule] + or: [AuthRule] + not: AuthRule + rule: String +} + +enum HTTPMethod { + GET + POST + PUT + PATCH + DELETE +} + +enum Mode { + BATCH + SINGLE +} + +input CustomHTTP { + url: String! + method: HTTPMethod! + body: String + graphql: String + mode: Mode + forwardHeaders: [String!] + secretHeaders: [String!] + introspectionHeaders: [String!] + skipIntrospection: Boolean +} + +type Point { + longitude: Float! + latitude: Float! +} + +input PointRef { + longitude: Float! + latitude: Float! +} + +input NearFilter { + distance: Float! + coordinate: PointRef! +} + +input PointGeoFilter { + near: NearFilter + within: WithinFilter +} + +type PointList { + points: [Point!]! +} + +input PointListRef { + points: [PointRef!]! +} + +type Polygon { + coordinates: [PointList!]! +} + +input PolygonRef { + coordinates: [PointListRef!]! +} + +type MultiPolygon { + polygons: [Polygon!]! +} + +input MultiPolygonRef { + polygons: [PolygonRef!]! +} + +input WithinFilter { + polygon: PolygonRef! +} + +input ContainsFilter { + point: PointRef + polygon: PolygonRef +} + +input IntersectsFilter { + polygon: PolygonRef + multiPolygon: MultiPolygonRef +} + +input PolygonGeoFilter { + near: NearFilter + within: WithinFilter + contains: ContainsFilter + intersects: IntersectsFilter +} + +input GenerateQueryParams { + get: Boolean + query: Boolean + password: Boolean + aggregate: Boolean +} + +input GenerateMutationParams { + add: Boolean + update: Boolean + delete: Boolean +} + +directive @hasInverse(field: String!) on FIELD_DEFINITION +directive @search(by: [DgraphIndex!]) on FIELD_DEFINITION +directive @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION +directive @id on FIELD_DEFINITION +directive @withSubscription on OBJECT | INTERFACE | FIELD_DEFINITION +directive @secret(field: String!, pred: String) on OBJECT | INTERFACE +directive @remote on OBJECT | INTERFACE | UNION | INPUT_OBJECT | ENUM +directive @remoteResponse(name: String) on FIELD_DEFINITION +directive @cascade(fields: [String]) on FIELD +directive @lambda on FIELD_DEFINITION +directive @cacheControl(maxAge: Int!) on QUERY + +input IntFilter { + eq: Int + in: [Int] + le: Int + lt: Int + ge: Int + gt: Int + between: IntRange +} + +input Int64Filter { + eq: Int64 + in: [Int64] + le: Int64 + lt: Int64 + ge: Int64 + gt: Int64 + between: Int64Range +} + +input FloatFilter { + eq: Float + in: [Float] + le: Float + lt: Float + ge: Float + gt: Float + between: FloatRange +} + +input DateTimeFilter { + eq: DateTime + in: [DateTime] + le: DateTime + lt: DateTime + ge: DateTime + gt: DateTime + between: DateTimeRange +} + +input StringTermFilter { + allofterms: String + anyofterms: String +} + +input StringRegExpFilter { + regexp: String +} + +input StringFullTextFilter { + alloftext: String + anyoftext: String +} + +input StringExactFilter { + eq: String + in: [String] + le: String + lt: String + ge: String + gt: String + between: StringRange +} + +input StringHashFilter { + eq: String + in: [String] +} + +####################### +# Generated Types +####################### + +type AddProductPayload { + product(filter: ProductFilter, order: ProductOrder, first: Int, offset: Int): [Product] + numUids: Int +} + +type DeleteProductPayload { + product(filter: ProductFilter, order: ProductOrder, first: Int, offset: Int): [Product] + msg: String + numUids: Int +} + +type ProductAggregateResult { + count: Int + idMin: String + idMax: String + nameMin: String + nameMax: String +} + +type UpdateProductPayload { + product(filter: ProductFilter, order: ProductOrder, first: Int, offset: Int): [Product] + numUids: Int +} + +####################### +# Generated Enums +####################### + +enum ProductHasFilter { + id + name +} + +enum ProductOrderable { + id + name +} + +####################### +# Generated Inputs +####################### + +input AddProductInput { + id: String! + name: String! +} + +input ProductFilter { + id: StringHashFilter + has: [ProductHasFilter] + and: [ProductFilter] + or: [ProductFilter] + not: ProductFilter +} + +input ProductOrder { + asc: ProductOrderable + desc: ProductOrderable + then: ProductOrder +} + +input ProductPatch { + name: String +} + +input ProductRef { + id: String + name: String +} + +input UpdateProductInput { + filter: ProductFilter! + set: ProductPatch + remove: ProductPatch +} + +####################### +# Generated Mutations +####################### + +type Mutation { + addProduct(input: [AddProductInput!]!, upsert: Boolean): AddProductPayload + updateProduct(input: UpdateProductInput!): UpdateProductPayload + deleteProduct(filter: ProductFilter!): DeleteProductPayload +} +