From ba9a784b51f94f8ea563be9f9ceee2e90373d35e Mon Sep 17 00:00:00 2001 From: Ben Kraft Date: Mon, 23 Aug 2021 12:37:30 -0700 Subject: [PATCH] Add support for interfaces, part 4: getter methods Right now, if you make a query like `{ myInterface { field } }`, you have to type-switch on all the possible implementations of `myInterface` to get at `field`. Now, we generate getter-methods (e.g. `GetField`), to make that access easier. Of course this only applies to shared fields (which for now are the only ones, but once we support fragments will no longer be). This also includes a small change to the way we generate type-names for interfaces: we no longer include the name of the concrete type in the interface we propagate forward, so we generate `MyInterfaceMyFieldMyType`, not `MyInterfaceMyImplMyFieldMyType`, in the case where you have an interface `MyInterface` implemented by `MyImpl` (and maybe other types) with field `myField: MyType`. This is necessary so the getter method returns a well-defined type, and also probably convenient for calling code. It will have to get a little bit more complicated once we support fragments, where you could have two implementing types with identically-named fields of different types, but I think it'll be easiest to figure out how to deal with that when implementing fragments. While I was in the area, I added to the interface doc-comment a list of the implementations. (In GraphQL, we're guaranteed to know them all assuming our schema is up to date.) Issue: https://github.com/Khan/genqlient/issues/8 Test plan: make check Reviewers: marksandstrom, adam, miguel --- generate/convert.go | 39 +- ...ield.graphql-InterfaceListField.graphql.go | 92 ++++- ...nterfaceListOfListsOfListsField.graphql.go | 110 +++++- ...esting.graphql-InterfaceNesting.graphql.go | 359 ++++++------------ ...ts.graphql-InterfaceNoFragments.graphql.go | 144 ++++++- ...gments.graphql-UnionNoFragments.graphql.go | 16 +- generate/types.go | 94 +++-- internal/integration/generated.go | 105 ++++- internal/integration/integration_test.go | 35 ++ 9 files changed, 718 insertions(+), 276 deletions(-) diff --git a/generate/convert.go b/generate/convert.go index 58f6493b..c86780f5 100644 --- a/generate/convert.go +++ b/generate/convert.go @@ -249,6 +249,7 @@ func (g *generator) convertDefinition( GoName: goName, GoType: fieldGoType, JSONName: field.Name, + GraphQLName: field.Name, Description: field.Description, } } @@ -264,19 +265,52 @@ func (g *generator) convertDefinition( GoName: name, Description: def.Description, GraphQLName: def.Name, + SharedFields: make([]*goStructField, 0, len(selectionSet)), Implementations: make([]*goStructType, len(implementationTypes)), } g.typeMap[name] = goType + // TODO(benkraft): This sorta-duplicates what we'll do in each + // implementation when it traverses the fields. But they'll differ + // more once we support fragments; at that point we should figure out + // how to refactor. + for _, selection := range selectionSet { + field, ok := selection.(*ast.Field) + if !ok { // fragment/interface, not a shared field + continue + } + _, fieldDirective, err := g.parsePrecedingComment(field, field.GetPosition()) + if err != nil { + return nil, err + } + fieldOptions := queryOptions.merge(fieldDirective) + + goField, err := g.convertField(namePrefix, field, fieldOptions, queryOptions) + if err != nil { + return nil, err + } + goType.SharedFields = append(goType.SharedFields, goField) + } + for i, implDef := range implementationTypes { - implName, implNamePrefix := g.typeName(namePrefix, implDef) + // Note for shared fields we propagate forward the interface's + // name-prefix: that is, the implementations will have fields with + // types like + // MyInterfaceMyFieldMyType + // not + // MyInterfaceMyImplMyFieldMyType + // ^^^^^^ + // In particular, this means that the Go type of MyField will be + // the same across all the implementations; this is important so + // that we can write a method GetMyField() that returns it! + implName, _ := 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) + implName, namePrefix, implDef, pos, selectionSet, queryOptions) if err != nil { return nil, err } @@ -356,6 +390,7 @@ func (g *generator) convertField( GoName: goName, GoType: fieldGoType, JSONName: field.Alias, + GraphQLName: field.Name, Description: field.Definition.Description, }, nil } diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go index 828fd6ef..df0cea50 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go @@ -65,21 +65,65 @@ type InterfaceListFieldRootTopicChildrenArticle struct { Name string `json:"name"` } -// InterfaceListFieldRootTopicChildrenContent includes the requested fields of the GraphQL type Content. +// InterfaceListFieldRootTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceListFieldRootTopicChildrenContent is implemented by the following types: +// InterfaceListFieldRootTopicChildrenArticle +// InterfaceListFieldRootTopicChildrenVideo +// InterfaceListFieldRootTopicChildrenTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceListFieldRootTopicChildrenContent interface { implementsGraphQLInterfaceInterfaceListFieldRootTopicChildrenContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *InterfaceListFieldRootTopicChildrenArticle) implementsGraphQLInterfaceInterfaceListFieldRootTopicChildrenContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenArticle) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenArticle) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenArticle) GetName() string { return v.Name } + func (v *InterfaceListFieldRootTopicChildrenVideo) implementsGraphQLInterfaceInterfaceListFieldRootTopicChildrenContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenVideo) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenVideo) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenVideo) GetName() string { return v.Name } + func (v *InterfaceListFieldRootTopicChildrenTopic) implementsGraphQLInterfaceInterfaceListFieldRootTopicChildrenContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenTopic) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldRootTopicChildrenContent. +func (v *InterfaceListFieldRootTopicChildrenTopic) GetName() string { return v.Name } + func __unmarshalInterfaceListFieldRootTopicChildrenContent(v *InterfaceListFieldRootTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil @@ -174,21 +218,65 @@ type InterfaceListFieldWithPointerTopicChildrenArticle struct { Name string `json:"name"` } -// InterfaceListFieldWithPointerTopicChildrenContent includes the requested fields of the GraphQL type Content. +// InterfaceListFieldWithPointerTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceListFieldWithPointerTopicChildrenContent is implemented by the following types: +// InterfaceListFieldWithPointerTopicChildrenArticle +// InterfaceListFieldWithPointerTopicChildrenVideo +// InterfaceListFieldWithPointerTopicChildrenTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceListFieldWithPointerTopicChildrenContent interface { implementsGraphQLInterfaceInterfaceListFieldWithPointerTopicChildrenContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *InterfaceListFieldWithPointerTopicChildrenArticle) implementsGraphQLInterfaceInterfaceListFieldWithPointerTopicChildrenContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenArticle) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenArticle) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenArticle) GetName() string { return v.Name } + func (v *InterfaceListFieldWithPointerTopicChildrenVideo) implementsGraphQLInterfaceInterfaceListFieldWithPointerTopicChildrenContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenVideo) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenVideo) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenVideo) GetName() string { return v.Name } + func (v *InterfaceListFieldWithPointerTopicChildrenTopic) implementsGraphQLInterfaceInterfaceListFieldWithPointerTopicChildrenContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenTopic) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListFieldWithPointerTopicChildrenContent. +func (v *InterfaceListFieldWithPointerTopicChildrenTopic) GetName() string { return v.Name } + func __unmarshalInterfaceListFieldWithPointerTopicChildrenContent(v *InterfaceListFieldWithPointerTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go index b4679c42..f91a299e 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go @@ -10,21 +10,83 @@ import ( "github.com/Khan/genqlient/internal/testutil" ) -// InterfaceListOfListOfListsFieldListOfListsOfListsOfContent includes the requested fields of the GraphQL type Content. +// InterfaceListOfListOfListsFieldListOfListsOfListsOfContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceListOfListOfListsFieldListOfListsOfListsOfContent is implemented by the following types: +// InterfaceListOfListOfListsFieldListOfListsOfListsOfContentArticle +// InterfaceListOfListOfListsFieldListOfListsOfListsOfContentVideo +// InterfaceListOfListOfListsFieldListOfListsOfListsOfContentTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceListOfListOfListsFieldListOfListsOfListsOfContent interface { implementsGraphQLInterfaceInterfaceListOfListOfListsFieldListOfListsOfListsOfContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentArticle) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldListOfListsOfListsOfContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentArticle) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentArticle) GetId() testutil.ID { + return v.Id +} + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentArticle) GetName() string { + return v.Name +} + func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentVideo) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldListOfListsOfListsOfContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentVideo) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentVideo) GetId() testutil.ID { + return v.Id +} + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentVideo) GetName() string { + return v.Name +} + func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentTopic) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldListOfListsOfListsOfContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentTopic) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentTopic) GetId() testutil.ID { + return v.Id +} + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldListOfListsOfListsOfContent. +func (v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContentTopic) GetName() string { + return v.Name +} + func __unmarshalInterfaceListOfListOfListsFieldListOfListsOfListsOfContent(v *InterfaceListOfListOfListsFieldListOfListsOfListsOfContent, m json.RawMessage) error { if string(m) == "null" { return nil @@ -166,21 +228,65 @@ type InterfaceListOfListOfListsFieldWithPointerArticle struct { Name *string `json:"name"` } -// InterfaceListOfListOfListsFieldWithPointerContent includes the requested fields of the GraphQL type Content. +// InterfaceListOfListOfListsFieldWithPointerContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceListOfListOfListsFieldWithPointerContent is implemented by the following types: +// InterfaceListOfListOfListsFieldWithPointerArticle +// InterfaceListOfListOfListsFieldWithPointerVideo +// InterfaceListOfListOfListsFieldWithPointerTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceListOfListOfListsFieldWithPointerContent interface { implementsGraphQLInterfaceInterfaceListOfListOfListsFieldWithPointerContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() *testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() *string } func (v *InterfaceListOfListOfListsFieldWithPointerArticle) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldWithPointerContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerArticle) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerArticle) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerArticle) GetName() *string { return v.Name } + func (v *InterfaceListOfListOfListsFieldWithPointerVideo) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldWithPointerContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerVideo) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerVideo) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerVideo) GetName() *string { return v.Name } + func (v *InterfaceListOfListOfListsFieldWithPointerTopic) implementsGraphQLInterfaceInterfaceListOfListOfListsFieldWithPointerContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerTopic) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceListOfListOfListsFieldWithPointerContent. +func (v *InterfaceListOfListOfListsFieldWithPointerTopic) GetName() *string { return v.Name } + func __unmarshalInterfaceListOfListOfListsFieldWithPointerContent(v *InterfaceListOfListOfListsFieldWithPointerContent, m json.RawMessage) error { if string(m) == "null" { return nil diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go index 6775e781..336bf1d3 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go @@ -59,130 +59,75 @@ func (v *InterfaceNestingRootTopic) UnmarshalJSON(b []byte) error { type InterfaceNestingRootTopicChildrenArticle struct { Typename string `json:"__typename"` // ID is the identifier of the content. - Id testutil.ID `json:"id"` - Parent InterfaceNestingRootTopicChildrenArticleParentTopic `json:"parent"` + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenParentTopic `json:"parent"` } -// InterfaceNestingRootTopicChildrenArticleParentTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenArticleParentTopic struct { - // ID is documented in the Content interface. - Id testutil.ID `json:"id"` - Children []InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent `json:"-"` -} - -func (v *InterfaceNestingRootTopicChildrenArticleParentTopic) UnmarshalJSON(b []byte) error { - - type InterfaceNestingRootTopicChildrenArticleParentTopicWrapper InterfaceNestingRootTopicChildrenArticleParentTopic - - var firstPass struct { - *InterfaceNestingRootTopicChildrenArticleParentTopicWrapper - Children []json.RawMessage `json:"children"` - } - firstPass.InterfaceNestingRootTopicChildrenArticleParentTopicWrapper = (*InterfaceNestingRootTopicChildrenArticleParentTopicWrapper)(v) - - err := json.Unmarshal(b, &firstPass) - if err != nil { - return err - } - - { - target := &v.Children - raw := firstPass.Children - *target = make( - []InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent, - len(raw)) - for i, raw := range raw { - target := &(*target)[i] - err = __unmarshalInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent( - target, raw) - if err != nil { - return err - } - } - } - return nil -} - -// InterfaceNestingRootTopicChildrenArticleParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. -type InterfaceNestingRootTopicChildrenArticleParentTopicChildrenArticle struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` -} - -// InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent includes the requested fields of the GraphQL type Content. +// InterfaceNestingRootTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceNestingRootTopicChildrenContent is implemented by the following types: +// InterfaceNestingRootTopicChildrenArticle +// InterfaceNestingRootTopicChildrenVideo +// InterfaceNestingRootTopicChildrenTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent interface { - implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent() +type InterfaceNestingRootTopicChildrenContent interface { + implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetParent returns the interface-field "parent" from its implementation. + GetParent() InterfaceNestingRootTopicChildrenParentTopic } -func (v *InterfaceNestingRootTopicChildrenArticleParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenArticleParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenArticleParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent() { +func (v *InterfaceNestingRootTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { } -func __unmarshalInterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent, m json.RawMessage) error { - if string(m) == "null" { - return nil - } +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenArticle) GetTypename() string { return v.Typename } - var tn struct { - TypeName string `json:"__typename"` - } - err := json.Unmarshal(m, &tn) - if err != nil { - return err - } +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenArticle) GetId() testutil.ID { return v.Id } - switch tn.TypeName { - case "Article": - *v = new(InterfaceNestingRootTopicChildrenArticleParentTopicChildrenArticle) - return json.Unmarshal(m, *v) - case "Video": - *v = new(InterfaceNestingRootTopicChildrenArticleParentTopicChildrenVideo) - return json.Unmarshal(m, *v) - case "Topic": - *v = new(InterfaceNestingRootTopicChildrenArticleParentTopicChildrenTopic) - return json.Unmarshal(m, *v) - default: - return fmt.Errorf( - `Unexpected concrete type for InterfaceNestingRootTopicChildrenArticleParentTopicChildrenContent: "%v"`, tn.TypeName) - } +// GetParent is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenArticle) GetParent() InterfaceNestingRootTopicChildrenParentTopic { + return v.Parent } -// InterfaceNestingRootTopicChildrenArticleParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenArticleParentTopicChildrenTopic struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` +func (v *InterfaceNestingRootTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { } -// InterfaceNestingRootTopicChildrenArticleParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type InterfaceNestingRootTopicChildrenArticleParentTopicChildrenVideo struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` -} +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenVideo) GetTypename() string { return v.Typename } -// InterfaceNestingRootTopicChildrenContent 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 InterfaceNestingRootTopicChildrenContent interface { - implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() -} +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenVideo) GetId() testutil.ID { return v.Id } -func (v *InterfaceNestingRootTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { +// GetParent is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenVideo) GetParent() InterfaceNestingRootTopicChildrenParentTopic { + return v.Parent } + func (v *InterfaceNestingRootTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenTopic) GetId() testutil.ID { return v.Id } + +// GetParent is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenTopic) GetParent() InterfaceNestingRootTopicChildrenParentTopic { + return v.Parent +} + func __unmarshalInterfaceNestingRootTopicChildrenContent(v *InterfaceNestingRootTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil @@ -212,30 +157,22 @@ func __unmarshalInterfaceNestingRootTopicChildrenContent(v *InterfaceNestingRoot } } -// InterfaceNestingRootTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenTopic struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` - Parent InterfaceNestingRootTopicChildrenTopicParentTopic `json:"parent"` -} - -// InterfaceNestingRootTopicChildrenTopicParentTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenTopicParentTopic struct { +// InterfaceNestingRootTopicChildrenParentTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNestingRootTopicChildrenParentTopic struct { // ID is documented in the Content interface. - Id testutil.ID `json:"id"` - Children []InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent `json:"-"` + Id testutil.ID `json:"id"` + Children []InterfaceNestingRootTopicChildrenParentTopicChildrenContent `json:"-"` } -func (v *InterfaceNestingRootTopicChildrenTopicParentTopic) UnmarshalJSON(b []byte) error { +func (v *InterfaceNestingRootTopicChildrenParentTopic) UnmarshalJSON(b []byte) error { - type InterfaceNestingRootTopicChildrenTopicParentTopicWrapper InterfaceNestingRootTopicChildrenTopicParentTopic + type InterfaceNestingRootTopicChildrenParentTopicWrapper InterfaceNestingRootTopicChildrenParentTopic var firstPass struct { - *InterfaceNestingRootTopicChildrenTopicParentTopicWrapper + *InterfaceNestingRootTopicChildrenParentTopicWrapper Children []json.RawMessage `json:"children"` } - firstPass.InterfaceNestingRootTopicChildrenTopicParentTopicWrapper = (*InterfaceNestingRootTopicChildrenTopicParentTopicWrapper)(v) + firstPass.InterfaceNestingRootTopicChildrenParentTopicWrapper = (*InterfaceNestingRootTopicChildrenParentTopicWrapper)(v) err := json.Unmarshal(b, &firstPass) if err != nil { @@ -246,11 +183,11 @@ func (v *InterfaceNestingRootTopicChildrenTopicParentTopic) UnmarshalJSON(b []by target := &v.Children raw := firstPass.Children *target = make( - []InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent, + []InterfaceNestingRootTopicChildrenParentTopicChildrenContent, len(raw)) for i, raw := range raw { target := &(*target)[i] - err = __unmarshalInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent( + err = __unmarshalInterfaceNestingRootTopicChildrenParentTopicChildrenContent( target, raw) if err != nil { return err @@ -260,142 +197,70 @@ func (v *InterfaceNestingRootTopicChildrenTopicParentTopic) UnmarshalJSON(b []by return nil } -// InterfaceNestingRootTopicChildrenTopicParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. -type InterfaceNestingRootTopicChildrenTopicParentTopicChildrenArticle struct { +// InterfaceNestingRootTopicChildrenParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. +type InterfaceNestingRootTopicChildrenParentTopicChildrenArticle struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` } -// InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent includes the requested fields of the GraphQL type Content. +// InterfaceNestingRootTopicChildrenParentTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceNestingRootTopicChildrenParentTopicChildrenContent is implemented by the following types: +// InterfaceNestingRootTopicChildrenParentTopicChildrenArticle +// InterfaceNestingRootTopicChildrenParentTopicChildrenVideo +// InterfaceNestingRootTopicChildrenParentTopicChildrenTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent interface { - implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent() +type InterfaceNestingRootTopicChildrenParentTopicChildrenContent interface { + implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID } -func (v *InterfaceNestingRootTopicChildrenTopicParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenTopicParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent() { +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { } -func (v *InterfaceNestingRootTopicChildrenTopicParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent() { -} - -func __unmarshalInterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent, 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(InterfaceNestingRootTopicChildrenTopicParentTopicChildrenArticle) - return json.Unmarshal(m, *v) - case "Video": - *v = new(InterfaceNestingRootTopicChildrenTopicParentTopicChildrenVideo) - return json.Unmarshal(m, *v) - case "Topic": - *v = new(InterfaceNestingRootTopicChildrenTopicParentTopicChildrenTopic) - return json.Unmarshal(m, *v) - default: - return fmt.Errorf( - `Unexpected concrete type for InterfaceNestingRootTopicChildrenTopicParentTopicChildrenContent: "%v"`, tn.TypeName) - } -} - -// InterfaceNestingRootTopicChildrenTopicParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenTopicParentTopicChildrenTopic struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) GetTypename() string { + return v.Typename } -// InterfaceNestingRootTopicChildrenTopicParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type InterfaceNestingRootTopicChildrenTopicParentTopicChildrenVideo struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) GetId() testutil.ID { + return v.Id } -// InterfaceNestingRootTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type InterfaceNestingRootTopicChildrenVideo struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` - Parent InterfaceNestingRootTopicChildrenVideoParentTopic `json:"parent"` +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { } -// InterfaceNestingRootTopicChildrenVideoParentTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenVideoParentTopic struct { - // ID is documented in the Content interface. - Id testutil.ID `json:"id"` - Children []InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent `json:"-"` +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) GetTypename() string { + return v.Typename } -func (v *InterfaceNestingRootTopicChildrenVideoParentTopic) UnmarshalJSON(b []byte) error { - - type InterfaceNestingRootTopicChildrenVideoParentTopicWrapper InterfaceNestingRootTopicChildrenVideoParentTopic +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) GetId() testutil.ID { return v.Id } - var firstPass struct { - *InterfaceNestingRootTopicChildrenVideoParentTopicWrapper - Children []json.RawMessage `json:"children"` - } - firstPass.InterfaceNestingRootTopicChildrenVideoParentTopicWrapper = (*InterfaceNestingRootTopicChildrenVideoParentTopicWrapper)(v) - - err := json.Unmarshal(b, &firstPass) - if err != nil { - return err - } - - { - target := &v.Children - raw := firstPass.Children - *target = make( - []InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent, - len(raw)) - for i, raw := range raw { - target := &(*target)[i] - err = __unmarshalInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent( - target, raw) - if err != nil { - return err - } - } - } - return nil -} - -// InterfaceNestingRootTopicChildrenVideoParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. -type InterfaceNestingRootTopicChildrenVideoParentTopicChildrenArticle struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { } -// InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent 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 InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent interface { - implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent() +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) GetTypename() string { + return v.Typename } -func (v *InterfaceNestingRootTopicChildrenVideoParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenVideoParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent() { -} -func (v *InterfaceNestingRootTopicChildrenVideoParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent() { -} +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) GetId() testutil.ID { return v.Id } -func __unmarshalInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent, m json.RawMessage) error { +func __unmarshalInterfaceNestingRootTopicChildrenParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenParentTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -410,34 +275,50 @@ func __unmarshalInterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent switch tn.TypeName { case "Article": - *v = new(InterfaceNestingRootTopicChildrenVideoParentTopicChildrenArticle) + *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) return json.Unmarshal(m, *v) case "Video": - *v = new(InterfaceNestingRootTopicChildrenVideoParentTopicChildrenVideo) + *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) return json.Unmarshal(m, *v) case "Topic": - *v = new(InterfaceNestingRootTopicChildrenVideoParentTopicChildrenTopic) + *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for InterfaceNestingRootTopicChildrenVideoParentTopicChildrenContent: "%v"`, tn.TypeName) + `Unexpected concrete type for InterfaceNestingRootTopicChildrenParentTopicChildrenContent: "%v"`, tn.TypeName) } } -// InterfaceNestingRootTopicChildrenVideoParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenVideoParentTopicChildrenTopic struct { +// InterfaceNestingRootTopicChildrenParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNestingRootTopicChildrenParentTopicChildrenTopic struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` } -// InterfaceNestingRootTopicChildrenVideoParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type InterfaceNestingRootTopicChildrenVideoParentTopicChildrenVideo struct { +// InterfaceNestingRootTopicChildrenParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. +type InterfaceNestingRootTopicChildrenParentTopicChildrenVideo struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` } +// InterfaceNestingRootTopicChildrenTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNestingRootTopicChildrenTopic struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenParentTopic `json:"parent"` +} + +// InterfaceNestingRootTopicChildrenVideo includes the requested fields of the GraphQL type Video. +type InterfaceNestingRootTopicChildrenVideo struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenParentTopic `json:"parent"` +} + func InterfaceNesting( client graphql.Client, ) (*InterfaceNestingResponse, error) { diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go index ee5ac581..a581c53b 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go @@ -18,21 +18,65 @@ type InterfaceNoFragmentsQueryRandomItemArticle struct { Name string `json:"name"` } -// InterfaceNoFragmentsQueryRandomItemContent includes the requested fields of the GraphQL type Content. +// InterfaceNoFragmentsQueryRandomItemContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceNoFragmentsQueryRandomItemContent is implemented by the following types: +// InterfaceNoFragmentsQueryRandomItemArticle +// InterfaceNoFragmentsQueryRandomItemVideo +// InterfaceNoFragmentsQueryRandomItemTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceNoFragmentsQueryRandomItemContent interface { implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *InterfaceNoFragmentsQueryRandomItemArticle) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemArticle) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemArticle) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemArticle) GetName() string { return v.Name } + func (v *InterfaceNoFragmentsQueryRandomItemVideo) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemVideo) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemVideo) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemVideo) GetName() string { return v.Name } + func (v *InterfaceNoFragmentsQueryRandomItemTopic) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemTopic) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemContent. +func (v *InterfaceNoFragmentsQueryRandomItemTopic) GetName() string { return v.Name } + func __unmarshalInterfaceNoFragmentsQueryRandomItemContent(v *InterfaceNoFragmentsQueryRandomItemContent, m json.RawMessage) error { if string(m) == "null" { return nil @@ -86,21 +130,71 @@ type InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle struct { Name string `json:"name"` } -// InterfaceNoFragmentsQueryRandomItemWithTypeNameContent includes the requested fields of the GraphQL type Content. +// InterfaceNoFragmentsQueryRandomItemWithTypeNameContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceNoFragmentsQueryRandomItemWithTypeNameContent is implemented by the following types: +// InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle +// InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo +// InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceNoFragmentsQueryRandomItemWithTypeNameContent interface { implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameArticle) GetName() string { return v.Name } + func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameVideo) GetName() string { return v.Name } + func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) implementsGraphQLInterfaceInterfaceNoFragmentsQueryRandomItemWithTypeNameContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) GetTypename() string { + return v.Typename +} + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) GetId() testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryRandomItemWithTypeNameContent. +func (v *InterfaceNoFragmentsQueryRandomItemWithTypeNameTopic) GetName() string { return v.Name } + func __unmarshalInterfaceNoFragmentsQueryRandomItemWithTypeNameContent(v *InterfaceNoFragmentsQueryRandomItemWithTypeNameContent, m json.RawMessage) error { if string(m) == "null" { return nil @@ -217,21 +311,65 @@ type InterfaceNoFragmentsQueryWithPointerArticle struct { Name *string `json:"name"` } -// InterfaceNoFragmentsQueryWithPointerContent includes the requested fields of the GraphQL type Content. +// InterfaceNoFragmentsQueryWithPointerContent includes the requested fields of the GraphQL interface Content. +// +// InterfaceNoFragmentsQueryWithPointerContent is implemented by the following types: +// InterfaceNoFragmentsQueryWithPointerArticle +// InterfaceNoFragmentsQueryWithPointerVideo +// InterfaceNoFragmentsQueryWithPointerTopic +// // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. type InterfaceNoFragmentsQueryWithPointerContent interface { implementsGraphQLInterfaceInterfaceNoFragmentsQueryWithPointerContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + // The GraphQL interface field's documentation follows. + // + // ID is the identifier of the content. + GetId() *testutil.ID + // GetName returns the interface-field "name" from its implementation. + GetName() *string } func (v *InterfaceNoFragmentsQueryWithPointerArticle) implementsGraphQLInterfaceInterfaceNoFragmentsQueryWithPointerContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerArticle) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerArticle) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerArticle) GetName() *string { return v.Name } + func (v *InterfaceNoFragmentsQueryWithPointerVideo) implementsGraphQLInterfaceInterfaceNoFragmentsQueryWithPointerContent() { } + +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerVideo) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerVideo) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerVideo) GetName() *string { return v.Name } + func (v *InterfaceNoFragmentsQueryWithPointerTopic) implementsGraphQLInterfaceInterfaceNoFragmentsQueryWithPointerContent() { } +// GetTypename is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerTopic) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerTopic) GetId() *testutil.ID { return v.Id } + +// GetName is a part of, and documented with, the interface InterfaceNoFragmentsQueryWithPointerContent. +func (v *InterfaceNoFragmentsQueryWithPointerTopic) GetName() *string { return v.Name } + func __unmarshalInterfaceNoFragmentsQueryWithPointerContent(v *InterfaceNoFragmentsQueryWithPointerContent, m json.RawMessage) error { if string(m) == "null" { return nil diff --git a/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go index ac214bee..43fe75b1 100644 --- a/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go @@ -14,19 +14,33 @@ type UnionNoFragmentsQueryRandomLeafArticle struct { Typename string `json:"__typename"` } -// UnionNoFragmentsQueryRandomLeafLeafContent includes the requested fields of the GraphQL type LeafContent. +// UnionNoFragmentsQueryRandomLeafLeafContent includes the requested fields of the GraphQL interface LeafContent. +// +// UnionNoFragmentsQueryRandomLeafLeafContent is implemented by the following types: +// UnionNoFragmentsQueryRandomLeafArticle +// UnionNoFragmentsQueryRandomLeafVideo +// // The GraphQL type's documentation follows. // // LeafContent represents content items that can't have child-nodes. type UnionNoFragmentsQueryRandomLeafLeafContent interface { implementsGraphQLInterfaceUnionNoFragmentsQueryRandomLeafLeafContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string } func (v *UnionNoFragmentsQueryRandomLeafArticle) implementsGraphQLInterfaceUnionNoFragmentsQueryRandomLeafLeafContent() { } + +// GetTypename is a part of, and documented with, the interface UnionNoFragmentsQueryRandomLeafLeafContent. +func (v *UnionNoFragmentsQueryRandomLeafArticle) GetTypename() string { return v.Typename } + func (v *UnionNoFragmentsQueryRandomLeafVideo) implementsGraphQLInterfaceUnionNoFragmentsQueryRandomLeafLeafContent() { } +// GetTypename is a part of, and documented with, the interface UnionNoFragmentsQueryRandomLeafLeafContent. +func (v *UnionNoFragmentsQueryRandomLeafVideo) GetTypename() string { return v.Typename } + func __unmarshalUnionNoFragmentsQueryRandomLeafLeafContent(v *UnionNoFragmentsQueryRandomLeafLeafContent, m json.RawMessage) error { if string(m) == "null" { return nil diff --git a/generate/types.go b/generate/types.go index e90c5c5f..a5433da1 100644 --- a/generate/types.go +++ b/generate/types.go @@ -114,7 +114,8 @@ type goStructType struct { type goStructField struct { GoName string GoType goType - JSONName string + JSONName string // i.e. the field's alias in this query + GraphQLName string // i.e. the field's name in its type-def Description string } @@ -126,7 +127,20 @@ func isAbstract(typ goType) bool { func (typ *goStructType) WriteDefinition(w io.Writer, g *generator) error { description := typ.Description if typ.Incomplete { - description = incompleteTypeDescription(typ.GoName, typ.GraphQLName, typ.Description) + // For types where we only have some fields, note that, along with + // the GraphQL documentation (if any). We don't want to just use + // the GraphQL documentation, since it may refer to fields we + // haven't selected, say. + prefix := fmt.Sprintf( + "%v includes the requested fields of the GraphQL type %v.", + typ.GoName, typ.GraphQLName) + if description != "" { + description = fmt.Sprintf( + "%v\nThe GraphQL type's documentation follows.\n\n%v", + prefix, description) + } else { + description = prefix + } } writeDescription(w, description) @@ -182,28 +196,76 @@ func (typ *goStructType) AbstractFields() []*goStructField { // goInterfaceType represents a Go interface type, used to represent a GraphQL // interface or union type. type goInterfaceType struct { - GoName string - Description string - GraphQLName string + GoName string + Description string + GraphQLName string + // Fields shared by all the interface's implementations; + // we'll generate getter methods for each. + SharedFields []*goStructField Implementations []*goStructType } func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error { - // TODO(benkraft): also mention the list of implementations. - description := incompleteTypeDescription(typ.GoName, typ.GraphQLName, typ.Description) + goTypeNames := make([]string, len(typ.Implementations)) + for i, impl := range typ.Implementations { + goTypeNames[i] = impl.Reference() + } + + description := fmt.Sprintf( + "%v includes the requested fields of the GraphQL interface %v.\n\n"+ + "%v is implemented by the following types:\n\t%v", + typ.GoName, typ.GraphQLName, typ.GoName, strings.Join(goTypeNames, "\n\t")) + if description != "" { + description = fmt.Sprintf( + "%v\n\nThe GraphQL type's documentation follows.\n\n%v", + description, typ.Description) + } writeDescription(w, description) // Write the interface. fmt.Fprintf(w, "type %s interface {\n", typ.GoName) implementsMethodName := fmt.Sprintf("implementsGraphQLInterface%v", typ.GoName) - // TODO(benkraft): Also write GetX() accessor methods for fields of the interface fmt.Fprintf(w, "\t%s()\n", implementsMethodName) + for _, sharedField := range typ.SharedFields { + methodName := "Get" + sharedField.GoName + description := "" + if sharedField.GraphQLName == "__typename" { + description = fmt.Sprintf( + "%s returns the receiver's concrete GraphQL type-name "+ + "(see interface doc for possible values).", methodName) + } else { + description = fmt.Sprintf( + `%s returns the interface-field "%s" from its implementation.`, + methodName, sharedField.GraphQLName) + if sharedField.Description != "" { + description = fmt.Sprintf( + "%s\nThe GraphQL interface field's documentation follows.\n\n%s", + description, sharedField.Description) + } + } + + writeDescription(w, description) + fmt.Fprintf(w, "\t%s() %s\n", methodName, sharedField.GoType.Reference()) + } fmt.Fprintf(w, "}\n") // Now, write out the implementations. for _, impl := range typ.Implementations { fmt.Fprintf(w, "func (v *%s) %s() {}\n", impl.Reference(), implementsMethodName) + for _, sharedField := range typ.SharedFields { + description := fmt.Sprintf( + "Get%s is a part of, and documented with, the interface %s.", + sharedField.GoName, typ.GoName) + writeDescription(w, description) + // In principle we should find the corresponding field of the + // implementation and use its name in `v.`. In practice, + // they're always the same. + fmt.Fprintf(w, "func (v *%s) Get%s() %s { return v.%s }\n", + impl.Reference(), sharedField.GoName, + sharedField.GoType.Reference(), sharedField.GoName) + } + fmt.Fprintf(w, "\n") // blank line between each type's implementations } // Finally, write the unmarshal-helper, which will be called by struct @@ -246,22 +308,6 @@ func (typ *goEnumType) IsPointer() bool { return false } func (typ *goStructType) IsPointer() bool { return false } func (typ *goInterfaceType) IsPointer() bool { return false } -func incompleteTypeDescription(goName, graphQLName, description string) string { - // For types where we only have some fields, note that, along with - // the GraphQL documentation (if any). We don't want to just use - // the GraphQL documentation, since it may refer to fields we - // haven't selected, say. - prefix := fmt.Sprintf( - "%v includes the requested fields of the GraphQL type %v.", - goName, graphQLName) - if description != "" { - return fmt.Sprintf( - "%v\nThe GraphQL type's documentation follows.\n\n%v", - prefix, description) - } - return prefix -} - func writeDescription(w io.Writer, desc string) { if desc != "" { for _, line := range strings.Split(desc, "\n") { diff --git a/internal/integration/generated.go b/internal/integration/generated.go index 025ece0f..69e7250f 100644 --- a/internal/integration/generated.go +++ b/internal/integration/generated.go @@ -17,16 +17,49 @@ type queryWithInterfaceListFieldBeingsAnimal struct { Name string `json:"name"` } -// queryWithInterfaceListFieldBeingsBeing includes the requested fields of the GraphQL type Being. +// queryWithInterfaceListFieldBeingsBeing includes the requested fields of the GraphQL interface Being. +// +// queryWithInterfaceListFieldBeingsBeing is implemented by the following types: +// queryWithInterfaceListFieldBeingsUser +// queryWithInterfaceListFieldBeingsAnimal +// +// The GraphQL type's documentation follows. +// +// type queryWithInterfaceListFieldBeingsBeing interface { implementsGraphQLInterfacequeryWithInterfaceListFieldBeingsBeing() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + GetId() string + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *queryWithInterfaceListFieldBeingsUser) implementsGraphQLInterfacequeryWithInterfaceListFieldBeingsBeing() { } + +// GetTypename is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsUser) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsUser) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsUser) GetName() string { return v.Name } + func (v *queryWithInterfaceListFieldBeingsAnimal) implementsGraphQLInterfacequeryWithInterfaceListFieldBeingsBeing() { } +// GetTypename is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsAnimal) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsAnimal) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceListFieldBeingsBeing. +func (v *queryWithInterfaceListFieldBeingsAnimal) GetName() string { return v.Name } + func __unmarshalqueryWithInterfaceListFieldBeingsBeing(v *queryWithInterfaceListFieldBeingsBeing, m json.RawMessage) error { if string(m) == "null" { return nil @@ -105,16 +138,49 @@ type queryWithInterfaceListPointerFieldBeingsAnimal struct { Name string `json:"name"` } -// queryWithInterfaceListPointerFieldBeingsBeing includes the requested fields of the GraphQL type Being. +// queryWithInterfaceListPointerFieldBeingsBeing includes the requested fields of the GraphQL interface Being. +// +// queryWithInterfaceListPointerFieldBeingsBeing is implemented by the following types: +// queryWithInterfaceListPointerFieldBeingsUser +// queryWithInterfaceListPointerFieldBeingsAnimal +// +// The GraphQL type's documentation follows. +// +// type queryWithInterfaceListPointerFieldBeingsBeing interface { implementsGraphQLInterfacequeryWithInterfaceListPointerFieldBeingsBeing() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + GetId() string + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *queryWithInterfaceListPointerFieldBeingsUser) implementsGraphQLInterfacequeryWithInterfaceListPointerFieldBeingsBeing() { } + +// GetTypename is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsUser) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsUser) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsUser) GetName() string { return v.Name } + func (v *queryWithInterfaceListPointerFieldBeingsAnimal) implementsGraphQLInterfacequeryWithInterfaceListPointerFieldBeingsBeing() { } +// GetTypename is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsAnimal) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsAnimal) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceListPointerFieldBeingsBeing. +func (v *queryWithInterfaceListPointerFieldBeingsAnimal) GetName() string { return v.Name } + func __unmarshalqueryWithInterfaceListPointerFieldBeingsBeing(v *queryWithInterfaceListPointerFieldBeingsBeing, m json.RawMessage) error { if string(m) == "null" { return nil @@ -187,16 +253,49 @@ func (v *queryWithInterfaceListPointerFieldResponse) UnmarshalJSON(b []byte) err return nil } -// queryWithInterfaceNoFragmentsBeing includes the requested fields of the GraphQL type Being. +// queryWithInterfaceNoFragmentsBeing includes the requested fields of the GraphQL interface Being. +// +// queryWithInterfaceNoFragmentsBeing is implemented by the following types: +// queryWithInterfaceNoFragmentsBeingUser +// queryWithInterfaceNoFragmentsBeingAnimal +// +// The GraphQL type's documentation follows. +// +// type queryWithInterfaceNoFragmentsBeing interface { implementsGraphQLInterfacequeryWithInterfaceNoFragmentsBeing() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + // GetId returns the interface-field "id" from its implementation. + GetId() string + // GetName returns the interface-field "name" from its implementation. + GetName() string } func (v *queryWithInterfaceNoFragmentsBeingUser) implementsGraphQLInterfacequeryWithInterfaceNoFragmentsBeing() { } + +// GetTypename is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingUser) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingUser) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingUser) GetName() string { return v.Name } + func (v *queryWithInterfaceNoFragmentsBeingAnimal) implementsGraphQLInterfacequeryWithInterfaceNoFragmentsBeing() { } +// GetTypename is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingAnimal) GetTypename() string { return v.Typename } + +// GetId is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingAnimal) GetId() string { return v.Id } + +// GetName is a part of, and documented with, the interface queryWithInterfaceNoFragmentsBeing. +func (v *queryWithInterfaceNoFragmentsBeingAnimal) GetName() string { return v.Name } + func __unmarshalqueryWithInterfaceNoFragmentsBeing(v *queryWithInterfaceNoFragmentsBeing, m json.RawMessage) error { if string(m) == "null" { return nil diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go index 193bdbf9..cb94ce76 100644 --- a/internal/integration/integration_test.go +++ b/internal/integration/integration_test.go @@ -71,9 +71,18 @@ func TestInterfaceNoFragments(t *testing.T) { resp, err := queryWithInterfaceNoFragments(ctx, client, "1") require.NoError(t, err) + // We should get the following response: + // me: User{Id: 1, Name: "Yours Truly"}, + // being: User{Id: 1, Name: "Yours Truly"}, + assert.Equal(t, "1", resp.Me.Id) assert.Equal(t, "Yours Truly", resp.Me.Name) + // Check fields both via interface and via type-assertion: + assert.Equal(t, "User", resp.Being.GetTypename()) + assert.Equal(t, "1", resp.Being.GetId()) + assert.Equal(t, "Yours Truly", resp.Being.GetName()) + user, ok := resp.Being.(*queryWithInterfaceNoFragmentsBeingUser) require.Truef(t, ok, "got %T, not User", resp.Being) assert.Equal(t, "1", user.Id) @@ -82,9 +91,17 @@ func TestInterfaceNoFragments(t *testing.T) { resp, err = queryWithInterfaceNoFragments(ctx, client, "3") require.NoError(t, err) + // We should get the following response: + // me: User{Id: 1, Name: "Yours Truly"}, + // being: Animal{Id: 3, Name: "Fido"}, + assert.Equal(t, "1", resp.Me.Id) assert.Equal(t, "Yours Truly", resp.Me.Name) + assert.Equal(t, "Animal", resp.Being.GetTypename()) + assert.Equal(t, "3", resp.Being.GetId()) + assert.Equal(t, "Fido", resp.Being.GetName()) + animal, ok := resp.Being.(*queryWithInterfaceNoFragmentsBeingAnimal) require.Truef(t, ok, "got %T, not Animal", resp.Being) assert.Equal(t, "3", animal.Id) @@ -93,6 +110,10 @@ func TestInterfaceNoFragments(t *testing.T) { resp, err = queryWithInterfaceNoFragments(ctx, client, "4757233945723") require.NoError(t, err) + // We should get the following response: + // me: User{Id: 1, Name: "Yours Truly"}, + // being: null + assert.Equal(t, "1", resp.Me.Id) assert.Equal(t, "Yours Truly", resp.Me.Name) @@ -116,11 +137,25 @@ func TestInterfaceListField(t *testing.T) { require.Len(t, resp.Beings, 3) + // We should get the following three beings: + // User{Id: 1, Name: "Yours Truly"}, + // Animal{Id: 3, Name: "Fido"}, + // null + + // Check fields both via interface and via type-assertion: + assert.Equal(t, "User", resp.Beings[0].GetTypename()) + assert.Equal(t, "1", resp.Beings[0].GetId()) + assert.Equal(t, "Yours Truly", resp.Beings[0].GetName()) + user, ok := resp.Beings[0].(*queryWithInterfaceListFieldBeingsUser) require.Truef(t, ok, "got %T, not User", resp.Beings[0]) assert.Equal(t, "1", user.Id) assert.Equal(t, "Yours Truly", user.Name) + assert.Equal(t, "Animal", resp.Beings[1].GetTypename()) + assert.Equal(t, "3", resp.Beings[1].GetId()) + assert.Equal(t, "Fido", resp.Beings[1].GetName()) + animal, ok := resp.Beings[1].(*queryWithInterfaceListFieldBeingsAnimal) require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) assert.Equal(t, "3", animal.Id)