From 17717587a4dc3d117f5e8a96fd47dfe28dcc608d Mon Sep 17 00:00:00 2001 From: Ben Kraft Date: Mon, 23 Aug 2021 11:15:35 -0700 Subject: [PATCH] Automatically add __typename to fields of interface type In #52, I added support for interface types, but with the simplifying restriction (among others) that the user must request the field `__typename`. In this commit, I remove this restriction. The basic idea is simple: we preprocess the query to add `__typename`. The implementation isn't much more complicated! Although it required some new wiring in a few places. Issue: https://github.com/Khan/genqlient/issues/8 Test plan: make tesc Reviewers: marksandstrom, adam, miguel --- generate/comments.go | 4 + generate/generate.go | 80 +++++++++++++- generate/testdata/errors/MissingTypeName.go | 5 - .../testdata/errors/MissingTypeName.graphql | 1 - .../errors/MissingTypeName.schema.graphql | 11 -- .../queries/InterfaceListField.graphql | 2 - .../InterfaceListOfListsOfListsField.graphql | 4 +- .../testdata/queries/InterfaceNesting.graphql | 3 - .../queries/InterfaceNoFragments.graphql | 5 +- ...nterfaceListOfListsOfListsField.graphql.go | 6 +- ...esting.graphql-InterfaceNesting.graphql.go | 4 - ...ting.graphql-InterfaceNesting.graphql.json | 2 +- ...ts.graphql-InterfaceNoFragments.graphql.go | 100 ++++++++++++++++-- ....graphql-InterfaceNoFragments.graphql.json | 2 +- generate/traverse.go | 18 +--- go.sum | 7 ++ internal/integration/integration_test.go | 4 +- 17 files changed, 196 insertions(+), 62 deletions(-) delete mode 100644 generate/testdata/errors/MissingTypeName.go delete mode 100644 generate/testdata/errors/MissingTypeName.graphql delete mode 100644 generate/testdata/errors/MissingTypeName.schema.graphql diff --git a/generate/comments.go b/generate/comments.go index c870a835..ab78029e 100644 --- a/generate/comments.go +++ b/generate/comments.go @@ -146,6 +146,10 @@ func (g *generator) parsePrecedingComment( pos *ast.Position, ) (comment string, directive *GenqlientDirective, err error) { directive = new(GenqlientDirective) + if pos == nil || pos.Src == nil { // node was added by genqlient itself + return "", directive, nil // treated as if there were no comment + } + var commentLines []string sourceLines := strings.Split(pos.Src.Input, "\n") for i := pos.Line - 1; i > 0; i-- { diff --git a/generate/generate.go b/generate/generate.go index 19f9a656..545d85d6 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -14,6 +14,7 @@ import ( "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/formatter" + "github.com/vektah/gqlparser/v2/validator" "golang.org/x/tools/imports" ) @@ -140,17 +141,88 @@ func (g *generator) getArgument( }, nil } +// Preprocess each query to make any changes that genqlient needs. +// +// At present, the only change is that we add __typename, if not already +// requested, to each field of interface type, so we can use the right types +// when unmarshaling. +func (g *generator) preprocessQueryDocument(doc *ast.QueryDocument) { + var observers validator.Events + // We want to ensure that everywhere you ask for some list of fields (a + // selection-set) from an interface (or union) type, you ask for its + // __typename field. There are four places we might find a selection-set: + // at the toplevel of a query, on a field, or in an inline or named + // fragment. The toplevel of a query must be an object type, so we don't + // need to consider that. + // TODO(benkraft): Once we support fragments, figure out whether we need to + // traverse inline/named fragments here too. + observers.OnField(func(_ *validator.Walker, field *ast.Field) { + // We are interested in a field from the query like + // field { subField ... } + // where the schema looks like + // type ... { # or interface/union + // field: FieldType # or [FieldType!]! etc. + // } + // interface FieldType { # or union + // subField: ... + // } + // If FieldType is an interface/union, and none of the subFields is + // __typename, we want to change the query to + // field { __typename subField ... } + + fieldType := g.schema.Types[field.Definition.Type.Name()] + if fieldType.Kind != ast.Interface && fieldType.Kind != ast.Union { + return // a concrete type + } + + hasTypename := false + for _, selection := range field.SelectionSet { + // Check if we already selected __typename. We ignore fragments, + // because we want __typename as a toplevel field. + subField, ok := selection.(*ast.Field) + if ok && subField.Name == "__typename" { + hasTypename = true + } + } + if !hasTypename { + // Ok, we need to add the field! + field.SelectionSet = append(ast.SelectionSet{ + &ast.Field{ + Alias: "__typename", Name: "__typename", + // Fake definition for the magic field __typename cribbed + // from gqlparser's validator/walk.go, equivalent to + // __typename: String + // TODO(benkraft): This should in principle be + // __typename: String! + // But genqlient doesn't care, so we just match gqlparser. + Definition: &ast.FieldDefinition{ + Name: "__typename", + Type: ast.NamedType("String", nil /* pos */), + }, + // Definition of the object that contains this field, i.e. + // FieldType. + ObjectDefinition: fieldType, + }, + }, field.SelectionSet...) + } + }) + validator.Walk(g.schema, doc, &observers) +} + func (g *generator) addOperation(op *ast.OperationDefinition) error { if op.Name == "" { return errorf(op.Position, "operations must have operation-names") } - var builder strings.Builder - f := formatter.NewFormatter(&builder) - f.FormatQueryDocument(&ast.QueryDocument{ + queryDoc := &ast.QueryDocument{ Operations: ast.OperationList{op}, // TODO: handle fragments - }) + } + g.preprocessQueryDocument(queryDoc) + + var builder strings.Builder + f := formatter.NewFormatter(&builder) + f.FormatQueryDocument(queryDoc) commentLines, directive, err := g.parsePrecedingComment(op, op.Position) if err != nil { diff --git a/generate/testdata/errors/MissingTypeName.go b/generate/testdata/errors/MissingTypeName.go deleted file mode 100644 index 12d9eb3c..00000000 --- a/generate/testdata/errors/MissingTypeName.go +++ /dev/null @@ -1,5 +0,0 @@ -package errors - -const _ = `# @genqlient - query MyQuery { i { f } } -` diff --git a/generate/testdata/errors/MissingTypeName.graphql b/generate/testdata/errors/MissingTypeName.graphql deleted file mode 100644 index c6b95aa6..00000000 --- a/generate/testdata/errors/MissingTypeName.graphql +++ /dev/null @@ -1 +0,0 @@ -query MyQuery { i { f } } diff --git a/generate/testdata/errors/MissingTypeName.schema.graphql b/generate/testdata/errors/MissingTypeName.schema.graphql deleted file mode 100644 index c990ba3d..00000000 --- a/generate/testdata/errors/MissingTypeName.schema.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type Query { - i: I -} - -type T implements I { - f: String! -} - -interface I { - f: String! -} diff --git a/generate/testdata/queries/InterfaceListField.graphql b/generate/testdata/queries/InterfaceListField.graphql index dc57f93b..8c571112 100644 --- a/generate/testdata/queries/InterfaceListField.graphql +++ b/generate/testdata/queries/InterfaceListField.graphql @@ -3,7 +3,6 @@ query InterfaceListField { id name children { - __typename id name } @@ -13,7 +12,6 @@ query InterfaceListField { id name children { - __typename id name } diff --git a/generate/testdata/queries/InterfaceListOfListsOfListsField.graphql b/generate/testdata/queries/InterfaceListOfListsOfListsField.graphql index 69ec1d36..e7ffea36 100644 --- a/generate/testdata/queries/InterfaceListOfListsOfListsField.graphql +++ b/generate/testdata/queries/InterfaceListOfListsOfListsField.graphql @@ -1,5 +1,5 @@ query InterfaceListOfListOfListsField { - listOfListsOfListsOfContent { __typename id name } + listOfListsOfListsOfContent { id name } # @genqlient(pointer: true) - withPointer: listOfListsOfListsOfContent { __typename id name } + withPointer: listOfListsOfListsOfContent { id name } } diff --git a/generate/testdata/queries/InterfaceNesting.graphql b/generate/testdata/queries/InterfaceNesting.graphql index d3618ac7..be0151d0 100644 --- a/generate/testdata/queries/InterfaceNesting.graphql +++ b/generate/testdata/queries/InterfaceNesting.graphql @@ -2,13 +2,10 @@ query InterfaceNesting { root { id children { - __typename id parent { - __typename id children { - __typename id } } diff --git a/generate/testdata/queries/InterfaceNoFragments.graphql b/generate/testdata/queries/InterfaceNoFragments.graphql index f9d552aa..6b4b3a72 100644 --- a/generate/testdata/queries/InterfaceNoFragments.graphql +++ b/generate/testdata/queries/InterfaceNoFragments.graphql @@ -1,6 +1,7 @@ query InterfaceNoFragmentsQuery { root { id name } # (make sure sibling fields work) - randomItem { __typename id name } + randomItem { id name } + randomItemWithTypeName: randomItem { __typename id name } # @genqlient(pointer: true) - withPointer: randomItem { __typename id name } + withPointer: randomItem { id name } } diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go index 4d3d3022..986177de 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go @@ -159,7 +159,7 @@ func (v *InterfaceListOfListOfListsFieldResponse) UnmarshalJSON(b []byte) error // InterfaceListOfListOfListsFieldWithPointerArticle includes the requested fields of the GraphQL type Article. type InterfaceListOfListOfListsFieldWithPointerArticle struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` @@ -211,7 +211,7 @@ func __unmarshalInterfaceListOfListOfListsFieldWithPointerContent(v *InterfaceLi // InterfaceListOfListOfListsFieldWithPointerTopic includes the requested fields of the GraphQL type Topic. type InterfaceListOfListOfListsFieldWithPointerTopic struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` @@ -219,7 +219,7 @@ type InterfaceListOfListOfListsFieldWithPointerTopic struct { // InterfaceListOfListOfListsFieldWithPointerVideo includes the requested fields of the GraphQL type Video. type InterfaceListOfListOfListsFieldWithPointerVideo struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go index e94a80cf..6775e781 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go @@ -65,7 +65,6 @@ type InterfaceNestingRootTopicChildrenArticle struct { // InterfaceNestingRootTopicChildrenArticleParentTopic includes the requested fields of the GraphQL type Topic. type InterfaceNestingRootTopicChildrenArticleParentTopic struct { - Typename string `json:"__typename"` // ID is documented in the Content interface. Id testutil.ID `json:"id"` Children []InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent `json:"-"` @@ -223,7 +222,6 @@ type InterfaceNestingRootTopicChildrenTopic struct { // InterfaceNestingRootTopicChildrenTopicParentTopic includes the requested fields of the GraphQL type Topic. type InterfaceNestingRootTopicChildrenTopicParentTopic struct { - Typename string `json:"__typename"` // ID is documented in the Content interface. Id testutil.ID `json:"id"` Children []InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent `json:"-"` @@ -337,7 +335,6 @@ type InterfaceNestingRootTopicChildrenVideo struct { // InterfaceNestingRootTopicChildrenVideoParentTopic includes the requested fields of the GraphQL type Topic. type InterfaceNestingRootTopicChildrenVideoParentTopic struct { - Typename string `json:"__typename"` // ID is documented in the Content interface. Id testutil.ID `json:"id"` Children []InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent `json:"-"` @@ -456,7 +453,6 @@ query InterfaceNesting { __typename id parent { - __typename id children { __typename diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.json b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.json index aa620137..2a91e66e 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.json +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.json @@ -2,7 +2,7 @@ "operations": [ { "operationName": "InterfaceNesting", - "query": "\nquery InterfaceNesting {\n\troot {\n\t\tid\n\t\tchildren {\n\t\t\t__typename\n\t\t\tid\n\t\t\tparent {\n\t\t\t\t__typename\n\t\t\t\tid\n\t\t\t\tchildren {\n\t\t\t\t\t__typename\n\t\t\t\t\tid\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n", + "query": "\nquery InterfaceNesting {\n\troot {\n\t\tid\n\t\tchildren {\n\t\t\t__typename\n\t\t\tid\n\t\t\tparent {\n\t\t\t\tid\n\t\t\t\tchildren {\n\t\t\t\t\t__typename\n\t\t\t\t\tid\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n", "sourceLocation": "testdata/queries/InterfaceNesting.graphql" } ] diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go index 73af3cb4..ac074d3b 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go @@ -78,11 +78,80 @@ type InterfaceNoFragmentsQueryRandomItemVideo struct { Name string `json:"name"` } +// InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle includes the requested fields of the GraphQL type Article. +type InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Name string `json:"name"` +} + +// InterfaceNoFragmentsQueryRandomItemWithTypeNameContent includes the requested fields of the GraphQL type Content. +// The GraphQL type's documentation follows. +// +// Content is implemented by various types like Article, Video, and Topic. +type InterfaceNoFragmentsQueryRandomItemWithTypeNameContent interface { + implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() +} + +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { +} +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { +} +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { +} + +func __unmarshalInterfaceNoFragmentsQueryRandomItemWithTypeNameContent(v *InterfaceNoFragmentsQueryRandomItemWithTypeNameContent, m json.RawMessage) error { + if string(m) == "null" { + return nil + } + + var tn struct { + TypeName string `json:"__typename"` + } + err := json.Unmarshal(m, &tn) + if err != nil { + return err + } + + switch tn.TypeName { + case "Article": + *v = new(InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) + return json.Unmarshal(m, *v) + case "Video": + *v = new(InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) + return json.Unmarshal(m, *v) + case "Topic": + *v = new(InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) + return json.Unmarshal(m, *v) + default: + return fmt.Errorf( + `Unexpected concrete type for InterfaceNoFragmentsQueryRandomItemWithTypeNameContent: "%v"`, tn.TypeName) + } +} + +// InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Name string `json:"name"` +} + +// InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo includes the requested fields of the GraphQL type Video. +type InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Name string `json:"name"` +} + // InterfaceNoFragmentsQueryResponse is returned by InterfaceNoFragmentsQuery on success. type InterfaceNoFragmentsQueryResponse struct { - Root InterfaceNoFragmentsQueryRootTopic `json:"root"` - RandomItem InterfaceNoFragmentsQueryRandomItemContent `json:"-"` - WithPointer *InterfaceNoFragmentsQueryWithPointerContent `json:"-"` + Root InterfaceNoFragmentsQueryRootTopic `json:"root"` + RandomItem InterfaceNoFragmentsQueryRandomItemContent `json:"-"` + RandomItemWithTypeName InterfaceNoFragmentsQueryRandomItemWithTypeNameContent `json:"-"` + WithPointer *InterfaceNoFragmentsQueryWithPointerContent `json:"-"` } func (v *InterfaceNoFragmentsQueryResponse) UnmarshalJSON(b []byte) error { @@ -91,8 +160,9 @@ func (v *InterfaceNoFragmentsQueryResponse) UnmarshalJSON(b []byte) error { var firstPass struct { *InterfaceNoFragmentsQueryResponseWrapper - RandomItem json.RawMessage `json:"randomItem"` - WithPointer json.RawMessage `json:"withPointer"` + RandomItem json.RawMessage `json:"randomItem"` + RandomItemWithTypeName json.RawMessage `json:"randomItemWithTypeName"` + WithPointer json.RawMessage `json:"withPointer"` } firstPass.InterfaceNoFragmentsQueryResponseWrapper = (*InterfaceNoFragmentsQueryResponseWrapper)(v) @@ -110,6 +180,15 @@ func (v *InterfaceNoFragmentsQueryResponse) UnmarshalJSON(b []byte) error { return err } } + { + target := &v.RandomItemWithTypeName + raw := firstPass.RandomItemWithTypeName + err = __unmarshalInterfaceNoFragmentsQueryRandomItemWithTypeNameContent( + target, raw) + if err != nil { + return err + } + } { target := &v.WithPointer raw := firstPass.WithPointer @@ -131,7 +210,7 @@ type InterfaceNoFragmentsQueryRootTopic struct { // InterfaceNoFragmentsQueryWithPointerArticle includes the requested fields of the GraphQL type Article. type InterfaceNoFragmentsQueryWithPointerArticle struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` @@ -183,7 +262,7 @@ func __unmarshalInterfaceNoFragmentsQueryWithPointerContent(v *InterfaceNoFragme // InterfaceNoFragmentsQueryWithPointerTopic includes the requested fields of the GraphQL type Topic. type InterfaceNoFragmentsQueryWithPointerTopic struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` @@ -191,7 +270,7 @@ type InterfaceNoFragmentsQueryWithPointerTopic struct { // InterfaceNoFragmentsQueryWithPointerVideo includes the requested fields of the GraphQL type Video. type InterfaceNoFragmentsQueryWithPointerVideo struct { - Typename *string `json:"__typename"` + Typename string `json:"__typename"` // ID is the identifier of the content. Id *testutil.ID `json:"id"` Name *string `json:"name"` @@ -215,6 +294,11 @@ query InterfaceNoFragmentsQuery { id name } + randomItemWithTypeName: randomItem { + __typename + id + name + } withPointer: randomItem { __typename id diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.json b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.json index 0d1b8be1..236fd138 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.json +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.json @@ -2,7 +2,7 @@ "operations": [ { "operationName": "InterfaceNoFragmentsQuery", - "query": "\nquery InterfaceNoFragmentsQuery {\n\troot {\n\t\tid\n\t\tname\n\t}\n\trandomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t}\n\twithPointer: randomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t}\n}\n", + "query": "\nquery InterfaceNoFragmentsQuery {\n\troot {\n\t\tid\n\t\tname\n\t}\n\trandomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t}\n\trandomItemWithTypeName: randomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t}\n\twithPointer: randomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t}\n}\n", "sourceLocation": "testdata/queries/InterfaceNoFragments.graphql" } ] diff --git a/generate/traverse.go b/generate/traverse.go index b1c6cbfe..83acee2a 100644 --- a/generate/traverse.go +++ b/generate/traverse.go @@ -260,19 +260,6 @@ func (g *generator) convertDefinition( return nil, errorf(pos, "not implemented: %v", def.Kind) } - // We need to request __typename so we know which concrete type to use. - hasTypename := false - for _, selection := range selectionSet { - field, ok := selection.(*ast.Field) - if ok && field.Name == "__typename" { - hasTypename = true - } - } - if !hasTypename { - // TODO(benkraft): Instead, modify the query to add __typename. - return nil, errorf(pos, "union/interface type %s must request __typename", def.Name) - } - implementationTypes := g.schema.GetPossibleTypes(def) goType := &goInterfaceType{ GoName: name, @@ -284,6 +271,11 @@ func (g *generator) convertDefinition( for i, implDef := range implementationTypes { implName, implNamePrefix := g.typeName(namePrefix, implDef) + // TODO(benkraft): In principle we should skip generating a Go + // field for __typename each of these impl-defs if you didn't + // request it (and it was automatically added by + // preprocessQueryDocument). But in practice it doesn't really + // hurt, and would be extra work to avoid, so we just leave it. implTyp, err := g.convertDefinition( implName, implNamePrefix, implDef, pos, selectionSet, queryOptions) if err != nil { diff --git a/go.sum b/go.sum index d51696fc..e53dd370 100644 --- a/go.sum +++ b/go.sum @@ -134,8 +134,10 @@ github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -612,7 +614,9 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.2.3 h1:ww2fsjqocGCAFamzvv/b8IsRduuHHeK2MHTcTxZTQX8= github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= @@ -632,6 +636,7 @@ github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PX github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -710,7 +715,9 @@ github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lP github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4= github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go index d057766f..a94ffa1d 100644 --- a/internal/integration/integration_test.go +++ b/internal/integration/integration_test.go @@ -59,7 +59,7 @@ func TestVariables(t *testing.T) { func TestInterfaceNoFragments(t *testing.T) { _ = `# @genqlient query queryWithInterfaceNoFragments($id: ID!) { - being(id: $id) { __typename id name } + being(id: $id) { id name } me { id name } }` @@ -102,7 +102,7 @@ func TestInterfaceNoFragments(t *testing.T) { func TestInterfaceListField(t *testing.T) { _ = `# @genqlient query queryWithInterfaceListField($ids: [ID!]!) { - beings(ids: $ids) { __typename id name } + beings(ids: $ids) { id name } }` ctx := context.Background()