From 4362cfec4808536e67a9a56efaf9976abd9d5e0e Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Wed, 14 Feb 2024 10:15:21 -0800 Subject: [PATCH 1/6] fix nested interface implementation --- generate/types.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/generate/types.go b/generate/types.go index 01f619f5..f87a04b4 100644 --- a/generate/types.go +++ b/generate/types.go @@ -522,6 +522,18 @@ func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error { for _, impl := range typ.Implementations { fmt.Fprintf(w, "func (v *%s) %s() {}\n", impl.Reference(), implementsMethodName) + + // implement nested interface union type + for _, sharedField := range typ.SharedFields { + if sharedField.IsAbstract() { + name := sharedField.GoName + if name == "" { + name = sharedField.GoType.Reference() + } + fmt.Fprintf(w, "func (v *%s) %s() {}\n", + impl.Reference(), fmt.Sprintf("implementsGraphQLInterface%s", name)) + } + } } // Finally, write the marshal- and unmarshal-helpers, which From 306f97054357673bdf4688c72df444a928d50517 Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Wed, 14 Feb 2024 13:15:42 -0800 Subject: [PATCH 2/6] test-case --- .../queries/ComplexNamedFragments.graphql | 31 +++++++++++++++++++ generate/testdata/queries/schema.graphql | 4 +++ 2 files changed, 35 insertions(+) diff --git a/generate/testdata/queries/ComplexNamedFragments.graphql b/generate/testdata/queries/ComplexNamedFragments.graphql index 57feb656..0e3cd55f 100644 --- a/generate/testdata/queries/ComplexNamedFragments.graphql +++ b/generate/testdata/queries/ComplexNamedFragments.graphql @@ -47,3 +47,34 @@ fragment ContentFields on Content { query ComplexNamedFragments { ... on Query { ...QueryFragment } } + +## two fragments of different but with fields containing the same type that is inline spread to a named fragment on a union +fragment SimpleLeafContent on LeafContent { + ... on Article { + id + } + ... on Video { + id + } +} + +fragment UserLastContent on User { + lastContent { + ... SimpleLeafContent + } +} + +fragment TopicNewestContent on Topic { + newestContent { + ... SimpleLeafContent + } +} + +query ComplexNamedFragmentsWithInlineUnion { + user { + ...UserLastContent + } + root { + ...TopicNewestContent + } +} \ No newline at end of file diff --git a/generate/testdata/queries/schema.graphql b/generate/testdata/queries/schema.graphql index 17db360a..eb71bdd4 100644 --- a/generate/testdata/queries/schema.graphql +++ b/generate/testdata/queries/schema.graphql @@ -69,6 +69,8 @@ type User { pokemon: [Pokemon!] greeting: Clip birthdate: Date + + lastContent: LeafContent } """An audio clip, such as of a user saying hello.""" @@ -141,6 +143,8 @@ type Topic implements Content { schoolGrade: String next: Topic related: [Topic!] + + newestContent: LeafContent } input RecursiveInput { From fa20c578a2c971ff611acf359077ffb408b5b788 Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Wed, 14 Feb 2024 13:30:06 -0800 Subject: [PATCH 3/6] changelog --- docs/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index bec20ef4..978ad90f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -30,6 +30,7 @@ When releasing a new version: ### Bug fixes: - The presence of negative pointer directives, i.e., `# @genqlient(pointer: false)` are now respected even in the when `optional: pointer` is set in the configuration file. - Made name collisions between query/mutation arguments and local function variables less likely. +- Fix generation issue related to golang type implementation of complex graphql union fragments ## v0.6.0 From bb6468e9de993a25a30ce3d408c226feea6ff8f6 Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Wed, 14 Feb 2024 13:33:37 -0800 Subject: [PATCH 4/6] update snapshot --- .../queries/ComplexNamedFragments.graphql | 4 +- ...s.graphql-ComplexNamedFragments.graphql.go | 635 ++++++++++++++++++ ...graphql-ComplexNamedFragments.graphql.json | 5 + ...ovariantInterfaceImplementation.graphql.go | 24 + 4 files changed, 666 insertions(+), 2 deletions(-) diff --git a/generate/testdata/queries/ComplexNamedFragments.graphql b/generate/testdata/queries/ComplexNamedFragments.graphql index 0e3cd55f..12036c80 100644 --- a/generate/testdata/queries/ComplexNamedFragments.graphql +++ b/generate/testdata/queries/ComplexNamedFragments.graphql @@ -48,7 +48,7 @@ query ComplexNamedFragments { ... on Query { ...QueryFragment } } -## two fragments of different but with fields containing the same type that is inline spread to a named fragment on a union +## two fragments of different types with fields containing the same inline named fragment of a union fragment SimpleLeafContent on LeafContent { ... on Article { id @@ -77,4 +77,4 @@ query ComplexNamedFragmentsWithInlineUnion { root { ...TopicNewestContent } -} \ No newline at end of file +} diff --git a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go index 5e7350c9..3a9096a5 100644 --- a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go @@ -113,6 +113,159 @@ func (v *ComplexNamedFragmentsResponse) __premarshalJSON() (*__premarshalComplex return &retval, nil } +// ComplexNamedFragmentsWithInlineUnionResponse is returned by ComplexNamedFragmentsWithInlineUnion on success. +type ComplexNamedFragmentsWithInlineUnionResponse struct { + // user looks up a user by some stuff. + // + // See UserQueryInput for what stuff is supported. + // If query is null, returns the current user. + User ComplexNamedFragmentsWithInlineUnionUser `json:"user"` + Root ComplexNamedFragmentsWithInlineUnionRootTopic `json:"root"` +} + +// GetUser returns ComplexNamedFragmentsWithInlineUnionResponse.User, and is useful for accessing the field via an interface. +func (v *ComplexNamedFragmentsWithInlineUnionResponse) GetUser() ComplexNamedFragmentsWithInlineUnionUser { + return v.User +} + +// GetRoot returns ComplexNamedFragmentsWithInlineUnionResponse.Root, and is useful for accessing the field via an interface. +func (v *ComplexNamedFragmentsWithInlineUnionResponse) GetRoot() ComplexNamedFragmentsWithInlineUnionRootTopic { + return v.Root +} + +// ComplexNamedFragmentsWithInlineUnionRootTopic includes the requested fields of the GraphQL type Topic. +type ComplexNamedFragmentsWithInlineUnionRootTopic struct { + TopicNewestContent `json:"-"` +} + +// GetNewestContent returns ComplexNamedFragmentsWithInlineUnionRootTopic.NewestContent, and is useful for accessing the field via an interface. +func (v *ComplexNamedFragmentsWithInlineUnionRootTopic) GetNewestContent() TopicNewestContentNewestContentLeafContent { + return v.TopicNewestContent.NewestContent +} + +func (v *ComplexNamedFragmentsWithInlineUnionRootTopic) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *ComplexNamedFragmentsWithInlineUnionRootTopic + graphql.NoUnmarshalJSON + } + firstPass.ComplexNamedFragmentsWithInlineUnionRootTopic = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.TopicNewestContent) + if err != nil { + return err + } + return nil +} + +type __premarshalComplexNamedFragmentsWithInlineUnionRootTopic struct { + NewestContent json.RawMessage `json:"newestContent"` +} + +func (v *ComplexNamedFragmentsWithInlineUnionRootTopic) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *ComplexNamedFragmentsWithInlineUnionRootTopic) __premarshalJSON() (*__premarshalComplexNamedFragmentsWithInlineUnionRootTopic, error) { + var retval __premarshalComplexNamedFragmentsWithInlineUnionRootTopic + + { + + dst := &retval.NewestContent + src := v.TopicNewestContent.NewestContent + var err error + *dst, err = __marshalTopicNewestContentNewestContentLeafContent( + &src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal ComplexNamedFragmentsWithInlineUnionRootTopic.TopicNewestContent.NewestContent: %w", err) + } + } + return &retval, nil +} + +// ComplexNamedFragmentsWithInlineUnionUser includes the requested fields of the GraphQL type User. +// The GraphQL type's documentation follows. +// +// A User is a user! +type ComplexNamedFragmentsWithInlineUnionUser struct { + UserLastContent `json:"-"` +} + +// GetLastContent returns ComplexNamedFragmentsWithInlineUnionUser.LastContent, and is useful for accessing the field via an interface. +func (v *ComplexNamedFragmentsWithInlineUnionUser) GetLastContent() UserLastContentLastContentLeafContent { + return v.UserLastContent.LastContent +} + +func (v *ComplexNamedFragmentsWithInlineUnionUser) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *ComplexNamedFragmentsWithInlineUnionUser + graphql.NoUnmarshalJSON + } + firstPass.ComplexNamedFragmentsWithInlineUnionUser = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.UserLastContent) + if err != nil { + return err + } + return nil +} + +type __premarshalComplexNamedFragmentsWithInlineUnionUser struct { + LastContent json.RawMessage `json:"lastContent"` +} + +func (v *ComplexNamedFragmentsWithInlineUnionUser) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *ComplexNamedFragmentsWithInlineUnionUser) __premarshalJSON() (*__premarshalComplexNamedFragmentsWithInlineUnionUser, error) { + var retval __premarshalComplexNamedFragmentsWithInlineUnionUser + + { + + dst := &retval.LastContent + src := v.UserLastContent.LastContent + var err error + *dst, err = __marshalUserLastContentLastContentLeafContent( + &src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal ComplexNamedFragmentsWithInlineUnionUser.UserLastContent.LastContent: %w", err) + } + } + return &retval, nil +} + // ContentFields includes the GraphQL fields of Content requested by the fragment ContentFields. // The GraphQL type's documentation follows. // @@ -722,10 +875,13 @@ type InnerQueryFragmentRandomItemContent interface { func (v *InnerQueryFragmentRandomItemArticle) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } +func (v *InnerQueryFragmentRandomItemArticle) implementsGraphQLInterfaceContentFields() {} func (v *InnerQueryFragmentRandomItemTopic) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } +func (v *InnerQueryFragmentRandomItemTopic) implementsGraphQLInterfaceContentFields() {} func (v *InnerQueryFragmentRandomItemVideo) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } +func (v *InnerQueryFragmentRandomItemVideo) implementsGraphQLInterfaceContentFields() {} func __unmarshalInnerQueryFragmentRandomItemContent(b []byte, v *InnerQueryFragmentRandomItemContent) error { if string(b) == "null" { @@ -1649,6 +1805,432 @@ func (v *QueryFragment) __premarshalJSON() (*__premarshalQueryFragment, error) { return &retval, nil } +// # two fragments of different types with fields containing the same inline named fragment of a union +// +// SimpleLeafContent is implemented by the following types: +// SimpleLeafContentArticle +// SimpleLeafContentVideo +type SimpleLeafContent interface { + implementsGraphQLInterfaceSimpleLeafContent() +} + +func (v *SimpleLeafContentArticle) implementsGraphQLInterfaceSimpleLeafContent() {} +func (v *SimpleLeafContentVideo) implementsGraphQLInterfaceSimpleLeafContent() {} + +func __unmarshalSimpleLeafContent(b []byte, v *SimpleLeafContent) error { + if string(b) == "null" { + return nil + } + + var tn struct { + TypeName string `json:"__typename"` + } + err := json.Unmarshal(b, &tn) + if err != nil { + return err + } + + switch tn.TypeName { + case "Article": + *v = new(SimpleLeafContentArticle) + return json.Unmarshal(b, *v) + case "Video": + *v = new(SimpleLeafContentVideo) + return json.Unmarshal(b, *v) + case "": + return fmt.Errorf( + "response was missing LeafContent.__typename") + default: + return fmt.Errorf( + `unexpected concrete type for SimpleLeafContent: "%v"`, tn.TypeName) + } +} + +func __marshalSimpleLeafContent(v *SimpleLeafContent) ([]byte, error) { + + var typename string + switch v := (*v).(type) { + case *SimpleLeafContentArticle: + typename = "Article" + + result := struct { + TypeName string `json:"__typename"` + *SimpleLeafContentArticle + }{typename, v} + return json.Marshal(result) + case *SimpleLeafContentVideo: + typename = "Video" + + result := struct { + TypeName string `json:"__typename"` + *SimpleLeafContentVideo + }{typename, v} + return json.Marshal(result) + case nil: + return []byte("null"), nil + default: + return nil, fmt.Errorf( + `unexpected concrete type for SimpleLeafContent: "%T"`, v) + } +} + +// # two fragments of different types with fields containing the same inline named fragment of a union +type SimpleLeafContentArticle struct { + // ID is documented in the Content interface. + Id testutil.ID `json:"id"` +} + +// GetId returns SimpleLeafContentArticle.Id, and is useful for accessing the field via an interface. +func (v *SimpleLeafContentArticle) GetId() testutil.ID { return v.Id } + +// # two fragments of different types with fields containing the same inline named fragment of a union +type SimpleLeafContentVideo struct { + // ID is documented in the Content interface. + Id testutil.ID `json:"id"` +} + +// GetId returns SimpleLeafContentVideo.Id, and is useful for accessing the field via an interface. +func (v *SimpleLeafContentVideo) GetId() testutil.ID { return v.Id } + +// TopicNewestContent includes the GraphQL fields of Topic requested by the fragment TopicNewestContent. +type TopicNewestContent struct { + NewestContent TopicNewestContentNewestContentLeafContent `json:"-"` +} + +// GetNewestContent returns TopicNewestContent.NewestContent, and is useful for accessing the field via an interface. +func (v *TopicNewestContent) GetNewestContent() TopicNewestContentNewestContentLeafContent { + return v.NewestContent +} + +func (v *TopicNewestContent) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *TopicNewestContent + NewestContent json.RawMessage `json:"newestContent"` + graphql.NoUnmarshalJSON + } + firstPass.TopicNewestContent = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.NewestContent + src := firstPass.NewestContent + if len(src) != 0 && string(src) != "null" { + err = __unmarshalTopicNewestContentNewestContentLeafContent( + src, dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal TopicNewestContent.NewestContent: %w", err) + } + } + } + return nil +} + +type __premarshalTopicNewestContent struct { + NewestContent json.RawMessage `json:"newestContent"` +} + +func (v *TopicNewestContent) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *TopicNewestContent) __premarshalJSON() (*__premarshalTopicNewestContent, error) { + var retval __premarshalTopicNewestContent + + { + + dst := &retval.NewestContent + src := v.NewestContent + var err error + *dst, err = __marshalTopicNewestContentNewestContentLeafContent( + &src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal TopicNewestContent.NewestContent: %w", err) + } + } + return &retval, nil +} + +// TopicNewestContentNewestContentArticle includes the requested fields of the GraphQL type Article. +type TopicNewestContentNewestContentArticle struct { + Typename string `json:"__typename"` +} + +// GetTypename returns TopicNewestContentNewestContentArticle.Typename, and is useful for accessing the field via an interface. +func (v *TopicNewestContentNewestContentArticle) GetTypename() string { return v.Typename } + +// TopicNewestContentNewestContentLeafContent includes the requested fields of the GraphQL interface LeafContent. +// +// TopicNewestContentNewestContentLeafContent is implemented by the following types: +// TopicNewestContentNewestContentArticle +// TopicNewestContentNewestContentVideo +// The GraphQL type's documentation follows. +// +// LeafContent represents content items that can't have child-nodes. +type TopicNewestContentNewestContentLeafContent interface { + implementsGraphQLInterfaceTopicNewestContentNewestContentLeafContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + SimpleLeafContent +} + +func (v *TopicNewestContentNewestContentArticle) implementsGraphQLInterfaceTopicNewestContentNewestContentLeafContent() { +} +func (v *TopicNewestContentNewestContentArticle) implementsGraphQLInterfaceSimpleLeafContent() {} +func (v *TopicNewestContentNewestContentVideo) implementsGraphQLInterfaceTopicNewestContentNewestContentLeafContent() { +} +func (v *TopicNewestContentNewestContentVideo) implementsGraphQLInterfaceSimpleLeafContent() {} + +func __unmarshalTopicNewestContentNewestContentLeafContent(b []byte, v *TopicNewestContentNewestContentLeafContent) error { + if string(b) == "null" { + return nil + } + + var tn struct { + TypeName string `json:"__typename"` + } + err := json.Unmarshal(b, &tn) + if err != nil { + return err + } + + switch tn.TypeName { + case "Article": + *v = new(TopicNewestContentNewestContentArticle) + return json.Unmarshal(b, *v) + case "Video": + *v = new(TopicNewestContentNewestContentVideo) + return json.Unmarshal(b, *v) + case "": + return fmt.Errorf( + "response was missing LeafContent.__typename") + default: + return fmt.Errorf( + `unexpected concrete type for TopicNewestContentNewestContentLeafContent: "%v"`, tn.TypeName) + } +} + +func __marshalTopicNewestContentNewestContentLeafContent(v *TopicNewestContentNewestContentLeafContent) ([]byte, error) { + + var typename string + switch v := (*v).(type) { + case *TopicNewestContentNewestContentArticle: + typename = "Article" + + result := struct { + TypeName string `json:"__typename"` + *TopicNewestContentNewestContentArticle + }{typename, v} + return json.Marshal(result) + case *TopicNewestContentNewestContentVideo: + typename = "Video" + + result := struct { + TypeName string `json:"__typename"` + *TopicNewestContentNewestContentVideo + }{typename, v} + return json.Marshal(result) + case nil: + return []byte("null"), nil + default: + return nil, fmt.Errorf( + `unexpected concrete type for TopicNewestContentNewestContentLeafContent: "%T"`, v) + } +} + +// TopicNewestContentNewestContentVideo includes the requested fields of the GraphQL type Video. +type TopicNewestContentNewestContentVideo struct { + Typename string `json:"__typename"` +} + +// GetTypename returns TopicNewestContentNewestContentVideo.Typename, and is useful for accessing the field via an interface. +func (v *TopicNewestContentNewestContentVideo) GetTypename() string { return v.Typename } + +// UserLastContent includes the GraphQL fields of User requested by the fragment UserLastContent. +// The GraphQL type's documentation follows. +// +// A User is a user! +type UserLastContent struct { + LastContent UserLastContentLastContentLeafContent `json:"-"` +} + +// GetLastContent returns UserLastContent.LastContent, and is useful for accessing the field via an interface. +func (v *UserLastContent) GetLastContent() UserLastContentLastContentLeafContent { + return v.LastContent +} + +func (v *UserLastContent) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *UserLastContent + LastContent json.RawMessage `json:"lastContent"` + graphql.NoUnmarshalJSON + } + firstPass.UserLastContent = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + dst := &v.LastContent + src := firstPass.LastContent + if len(src) != 0 && string(src) != "null" { + err = __unmarshalUserLastContentLastContentLeafContent( + src, dst) + if err != nil { + return fmt.Errorf( + "unable to unmarshal UserLastContent.LastContent: %w", err) + } + } + } + return nil +} + +type __premarshalUserLastContent struct { + LastContent json.RawMessage `json:"lastContent"` +} + +func (v *UserLastContent) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *UserLastContent) __premarshalJSON() (*__premarshalUserLastContent, error) { + var retval __premarshalUserLastContent + + { + + dst := &retval.LastContent + src := v.LastContent + var err error + *dst, err = __marshalUserLastContentLastContentLeafContent( + &src) + if err != nil { + return nil, fmt.Errorf( + "unable to marshal UserLastContent.LastContent: %w", err) + } + } + return &retval, nil +} + +// UserLastContentLastContentArticle includes the requested fields of the GraphQL type Article. +type UserLastContentLastContentArticle struct { + Typename string `json:"__typename"` +} + +// GetTypename returns UserLastContentLastContentArticle.Typename, and is useful for accessing the field via an interface. +func (v *UserLastContentLastContentArticle) GetTypename() string { return v.Typename } + +// UserLastContentLastContentLeafContent includes the requested fields of the GraphQL interface LeafContent. +// +// UserLastContentLastContentLeafContent is implemented by the following types: +// UserLastContentLastContentArticle +// UserLastContentLastContentVideo +// The GraphQL type's documentation follows. +// +// LeafContent represents content items that can't have child-nodes. +type UserLastContentLastContentLeafContent interface { + implementsGraphQLInterfaceUserLastContentLastContentLeafContent() + // GetTypename returns the receiver's concrete GraphQL type-name (see interface doc for possible values). + GetTypename() string + SimpleLeafContent +} + +func (v *UserLastContentLastContentArticle) implementsGraphQLInterfaceUserLastContentLastContentLeafContent() { +} +func (v *UserLastContentLastContentArticle) implementsGraphQLInterfaceSimpleLeafContent() {} +func (v *UserLastContentLastContentVideo) implementsGraphQLInterfaceUserLastContentLastContentLeafContent() { +} +func (v *UserLastContentLastContentVideo) implementsGraphQLInterfaceSimpleLeafContent() {} + +func __unmarshalUserLastContentLastContentLeafContent(b []byte, v *UserLastContentLastContentLeafContent) error { + if string(b) == "null" { + return nil + } + + var tn struct { + TypeName string `json:"__typename"` + } + err := json.Unmarshal(b, &tn) + if err != nil { + return err + } + + switch tn.TypeName { + case "Article": + *v = new(UserLastContentLastContentArticle) + return json.Unmarshal(b, *v) + case "Video": + *v = new(UserLastContentLastContentVideo) + return json.Unmarshal(b, *v) + case "": + return fmt.Errorf( + "response was missing LeafContent.__typename") + default: + return fmt.Errorf( + `unexpected concrete type for UserLastContentLastContentLeafContent: "%v"`, tn.TypeName) + } +} + +func __marshalUserLastContentLastContentLeafContent(v *UserLastContentLastContentLeafContent) ([]byte, error) { + + var typename string + switch v := (*v).(type) { + case *UserLastContentLastContentArticle: + typename = "Article" + + result := struct { + TypeName string `json:"__typename"` + *UserLastContentLastContentArticle + }{typename, v} + return json.Marshal(result) + case *UserLastContentLastContentVideo: + typename = "Video" + + result := struct { + TypeName string `json:"__typename"` + *UserLastContentLastContentVideo + }{typename, v} + return json.Marshal(result) + case nil: + return []byte("null"), nil + default: + return nil, fmt.Errorf( + `unexpected concrete type for UserLastContentLastContentLeafContent: "%T"`, v) + } +} + +// UserLastContentLastContentVideo includes the requested fields of the GraphQL type Video. +type UserLastContentLastContentVideo struct { + Typename string `json:"__typename"` +} + +// GetTypename returns UserLastContentLastContentVideo.Typename, and is useful for accessing the field via an interface. +func (v *UserLastContentLastContentVideo) GetTypename() string { return v.Typename } + // VideoFields includes the GraphQL fields of Video requested by the fragment VideoFields. type VideoFields struct { // ID is documented in the Content interface. @@ -1821,3 +2403,56 @@ func ComplexNamedFragments( return &data_, err_ } +// The query or mutation executed by ComplexNamedFragmentsWithInlineUnion. +const ComplexNamedFragmentsWithInlineUnion_Operation = ` +query ComplexNamedFragmentsWithInlineUnion { + user { + ... UserLastContent + } + root { + ... TopicNewestContent + } +} +fragment UserLastContent on User { + lastContent { + __typename + ... SimpleLeafContent + } +} +fragment TopicNewestContent on Topic { + newestContent { + __typename + ... SimpleLeafContent + } +} +fragment SimpleLeafContent on LeafContent { + ... on Article { + id + } + ... on Video { + id + } +} +` + +func ComplexNamedFragmentsWithInlineUnion( + client_ graphql.Client, +) (*ComplexNamedFragmentsWithInlineUnionResponse, error) { + req_ := &graphql.Request{ + OpName: "ComplexNamedFragmentsWithInlineUnion", + Query: ComplexNamedFragmentsWithInlineUnion_Operation, + } + var err_ error + + var data_ ComplexNamedFragmentsWithInlineUnionResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + nil, + req_, + resp_, + ) + + return &data_, err_ +} + diff --git a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.json b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.json index 114023cd..f78ee92c 100644 --- a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.json +++ b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.json @@ -4,6 +4,11 @@ "operationName": "ComplexNamedFragments", "query": "\nquery ComplexNamedFragments {\n\t... on Query {\n\t\t... QueryFragment\n\t}\n}\nfragment QueryFragment on Query {\n\t... InnerQueryFragment\n}\nfragment InnerQueryFragment on Query {\n\trandomItem {\n\t\t__typename\n\t\tid\n\t\tname\n\t\t... VideoFields\n\t\t... ContentFields\n\t}\n\trandomLeaf {\n\t\t__typename\n\t\t... VideoFields\n\t\t... MoreVideoFields\n\t\t... ContentFields\n\t}\n\totherLeaf: randomLeaf {\n\t\t__typename\n\t\t... on Video {\n\t\t\t... MoreVideoFields\n\t\t\t... ContentFields\n\t\t}\n\t\t... ContentFields\n\t}\n}\nfragment VideoFields on Video {\n\tid\n\tname\n\turl\n\tduration\n\tthumbnail {\n\t\tid\n\t}\n\t... ContentFields\n}\nfragment ContentFields on Content {\n\tname\n\turl\n}\nfragment MoreVideoFields on Video {\n\tid\n\tparent {\n\t\tname\n\t\turl\n\t\t... ContentFields\n\t\tchildren {\n\t\t\t__typename\n\t\t\t... VideoFields\n\t\t}\n\t}\n}\n", "sourceLocation": "testdata/queries/ComplexNamedFragments.graphql" + }, + { + "operationName": "ComplexNamedFragmentsWithInlineUnion", + "query": "\nquery ComplexNamedFragmentsWithInlineUnion {\n\tuser {\n\t\t... UserLastContent\n\t}\n\troot {\n\t\t... TopicNewestContent\n\t}\n}\nfragment UserLastContent on User {\n\tlastContent {\n\t\t__typename\n\t\t... SimpleLeafContent\n\t}\n}\nfragment TopicNewestContent on Topic {\n\tnewestContent {\n\t\t__typename\n\t\t... SimpleLeafContent\n\t}\n}\nfragment SimpleLeafContent on LeafContent {\n\t... on Article {\n\t\tid\n\t}\n\t... on Video {\n\t\tid\n\t}\n}\n", + "sourceLocation": "testdata/queries/ComplexNamedFragments.graphql" } ] } diff --git a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go index 74aa5774..3f549d01 100644 --- a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go @@ -28,8 +28,14 @@ type ContentFields interface { } func (v *ContentFieldsArticle) implementsGraphQLInterfaceContentFields() {} +func (v *ContentFieldsArticle) implementsGraphQLInterfaceNext() {} +func (v *ContentFieldsArticle) implementsGraphQLInterfaceRelated() {} func (v *ContentFieldsTopic) implementsGraphQLInterfaceContentFields() {} +func (v *ContentFieldsTopic) implementsGraphQLInterfaceNext() {} +func (v *ContentFieldsTopic) implementsGraphQLInterfaceRelated() {} func (v *ContentFieldsVideo) implementsGraphQLInterfaceContentFields() {} +func (v *ContentFieldsVideo) implementsGraphQLInterfaceNext() {} +func (v *ContentFieldsVideo) implementsGraphQLInterfaceRelated() {} func __unmarshalContentFields(b []byte, v *ContentFields) error { if string(b) == "null" { @@ -887,10 +893,16 @@ type CovariantInterfaceImplementationRandomItemContent interface { func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } +func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceNext() {} +func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceRelated() {} func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } +func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceNext() {} +func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceRelated() {} func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } +func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceNext() {} +func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceRelated() {} func __unmarshalCovariantInterfaceImplementationRandomItemContent(b []byte, v *CovariantInterfaceImplementationRandomItemContent) error { if string(b) == "null" { @@ -1089,10 +1101,16 @@ type CovariantInterfaceImplementationRandomItemContentNextContent interface { func (v *CovariantInterfaceImplementationRandomItemContentNextArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentNextArticle) implementsGraphQLInterfaceContentFields() { +} func (v *CovariantInterfaceImplementationRandomItemContentNextTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentNextTopic) implementsGraphQLInterfaceContentFields() { +} func (v *CovariantInterfaceImplementationRandomItemContentNextVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentNextVideo) implementsGraphQLInterfaceContentFields() { +} func __unmarshalCovariantInterfaceImplementationRandomItemContentNextContent(b []byte, v *CovariantInterfaceImplementationRandomItemContentNextContent) error { if string(b) == "null" { @@ -1489,10 +1507,16 @@ type CovariantInterfaceImplementationRandomItemContentRelatedContent interface { func (v *CovariantInterfaceImplementationRandomItemContentRelatedArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentRelatedArticle) implementsGraphQLInterfaceContentFields() { +} func (v *CovariantInterfaceImplementationRandomItemContentRelatedTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentRelatedTopic) implementsGraphQLInterfaceContentFields() { +} func (v *CovariantInterfaceImplementationRandomItemContentRelatedVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } +func (v *CovariantInterfaceImplementationRandomItemContentRelatedVideo) implementsGraphQLInterfaceContentFields() { +} func __unmarshalCovariantInterfaceImplementationRandomItemContentRelatedContent(b []byte, v *CovariantInterfaceImplementationRandomItemContentRelatedContent) error { if string(b) == "null" { From 414c3f22c33c7b9293695fa8e7c103f94d84b414 Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Wed, 14 Feb 2024 13:53:27 -0800 Subject: [PATCH 5/6] fix bug --- ...aphql-CovariantInterfaceImplementation.graphql.go | 12 ------------ generate/types.go | 9 ++++----- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go index 3f549d01..47213148 100644 --- a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go @@ -28,14 +28,8 @@ type ContentFields interface { } func (v *ContentFieldsArticle) implementsGraphQLInterfaceContentFields() {} -func (v *ContentFieldsArticle) implementsGraphQLInterfaceNext() {} -func (v *ContentFieldsArticle) implementsGraphQLInterfaceRelated() {} func (v *ContentFieldsTopic) implementsGraphQLInterfaceContentFields() {} -func (v *ContentFieldsTopic) implementsGraphQLInterfaceNext() {} -func (v *ContentFieldsTopic) implementsGraphQLInterfaceRelated() {} func (v *ContentFieldsVideo) implementsGraphQLInterfaceContentFields() {} -func (v *ContentFieldsVideo) implementsGraphQLInterfaceNext() {} -func (v *ContentFieldsVideo) implementsGraphQLInterfaceRelated() {} func __unmarshalContentFields(b []byte, v *ContentFields) error { if string(b) == "null" { @@ -893,16 +887,10 @@ type CovariantInterfaceImplementationRandomItemContent interface { func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } -func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceNext() {} -func (v *CovariantInterfaceImplementationRandomItemArticle) implementsGraphQLInterfaceRelated() {} func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } -func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceNext() {} -func (v *CovariantInterfaceImplementationRandomItemTopic) implementsGraphQLInterfaceRelated() {} func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContent() { } -func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceNext() {} -func (v *CovariantInterfaceImplementationRandomItemVideo) implementsGraphQLInterfaceRelated() {} func __unmarshalCovariantInterfaceImplementationRandomItemContent(b []byte, v *CovariantInterfaceImplementationRandomItemContent) error { if string(b) == "null" { diff --git a/generate/types.go b/generate/types.go index f87a04b4..7641d9b1 100644 --- a/generate/types.go +++ b/generate/types.go @@ -526,12 +526,11 @@ func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error { // implement nested interface union type for _, sharedField := range typ.SharedFields { if sharedField.IsAbstract() { - name := sharedField.GoName - if name == "" { - name = sharedField.GoType.Reference() + // embedded type + if sharedField.GoName == "" { + fmt.Fprintf(w, "func (v *%s) %s() {}\n", + impl.Reference(), fmt.Sprintf("implementsGraphQLInterface%s", sharedField.GoType.Reference())) } - fmt.Fprintf(w, "func (v *%s) %s() {}\n", - impl.Reference(), fmt.Sprintf("implementsGraphQLInterface%s", name)) } } } From a2a8d5886452e1b3bdee9c83e9a2782be7ab57bb Mon Sep 17 00:00:00 2001 From: Zihao Zhang Date: Fri, 16 Feb 2024 12:41:17 -0800 Subject: [PATCH 6/6] new strategy --- generate/convert.go | 11 + ...s.graphql-ComplexNamedFragments.graphql.go | 255 ++++++++++++++++-- ...ovariantInterfaceImplementation.graphql.go | 12 - generate/types.go | 11 - 4 files changed, 247 insertions(+), 42 deletions(-) diff --git a/generate/convert.go b/generate/convert.go index 3b1f750a..d3a9f8d3 100644 --- a/generate/convert.go +++ b/generate/convert.go @@ -701,6 +701,17 @@ func fragmentMatches(containingTypedef, fragmentTypedef *ast.Definition) bool { return true } } + + // Handle the special case where the fragment is on a union, then the + // fragment can match any of the types in the union. + if fragmentTypedef.Kind == ast.Union { + for _, typeName := range fragmentTypedef.Types { + if typeName == containingTypedef.Name { + return true + } + } + } + return false } diff --git a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go index 3a9096a5..7888b2e8 100644 --- a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go @@ -875,13 +875,10 @@ type InnerQueryFragmentRandomItemContent interface { func (v *InnerQueryFragmentRandomItemArticle) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } -func (v *InnerQueryFragmentRandomItemArticle) implementsGraphQLInterfaceContentFields() {} func (v *InnerQueryFragmentRandomItemTopic) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } -func (v *InnerQueryFragmentRandomItemTopic) implementsGraphQLInterfaceContentFields() {} func (v *InnerQueryFragmentRandomItemVideo) implementsGraphQLInterfaceInnerQueryFragmentRandomItemContent() { } -func (v *InnerQueryFragmentRandomItemVideo) implementsGraphQLInterfaceContentFields() {} func __unmarshalInnerQueryFragmentRandomItemContent(b []byte, v *InnerQueryFragmentRandomItemContent) error { if string(b) == "null" { @@ -1967,12 +1964,65 @@ func (v *TopicNewestContent) __premarshalJSON() (*__premarshalTopicNewestContent // TopicNewestContentNewestContentArticle includes the requested fields of the GraphQL type Article. type TopicNewestContentNewestContentArticle struct { - Typename string `json:"__typename"` + Typename string `json:"__typename"` + SimpleLeafContentArticle `json:"-"` } // GetTypename returns TopicNewestContentNewestContentArticle.Typename, and is useful for accessing the field via an interface. func (v *TopicNewestContentNewestContentArticle) GetTypename() string { return v.Typename } +// GetId returns TopicNewestContentNewestContentArticle.Id, and is useful for accessing the field via an interface. +func (v *TopicNewestContentNewestContentArticle) GetId() testutil.ID { + return v.SimpleLeafContentArticle.Id +} + +func (v *TopicNewestContentNewestContentArticle) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *TopicNewestContentNewestContentArticle + graphql.NoUnmarshalJSON + } + firstPass.TopicNewestContentNewestContentArticle = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.SimpleLeafContentArticle) + if err != nil { + return err + } + return nil +} + +type __premarshalTopicNewestContentNewestContentArticle struct { + Typename string `json:"__typename"` + + Id testutil.ID `json:"id"` +} + +func (v *TopicNewestContentNewestContentArticle) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *TopicNewestContentNewestContentArticle) __premarshalJSON() (*__premarshalTopicNewestContentNewestContentArticle, error) { + var retval __premarshalTopicNewestContentNewestContentArticle + + retval.Typename = v.Typename + retval.Id = v.SimpleLeafContentArticle.Id + return &retval, nil +} + // TopicNewestContentNewestContentLeafContent includes the requested fields of the GraphQL interface LeafContent. // // TopicNewestContentNewestContentLeafContent is implemented by the following types: @@ -1990,10 +2040,8 @@ type TopicNewestContentNewestContentLeafContent interface { func (v *TopicNewestContentNewestContentArticle) implementsGraphQLInterfaceTopicNewestContentNewestContentLeafContent() { } -func (v *TopicNewestContentNewestContentArticle) implementsGraphQLInterfaceSimpleLeafContent() {} func (v *TopicNewestContentNewestContentVideo) implementsGraphQLInterfaceTopicNewestContentNewestContentLeafContent() { } -func (v *TopicNewestContentNewestContentVideo) implementsGraphQLInterfaceSimpleLeafContent() {} func __unmarshalTopicNewestContentNewestContentLeafContent(b []byte, v *TopicNewestContentNewestContentLeafContent) error { if string(b) == "null" { @@ -2031,18 +2079,26 @@ func __marshalTopicNewestContentNewestContentLeafContent(v *TopicNewestContentNe case *TopicNewestContentNewestContentArticle: typename = "Article" + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } result := struct { TypeName string `json:"__typename"` - *TopicNewestContentNewestContentArticle - }{typename, v} + *__premarshalTopicNewestContentNewestContentArticle + }{typename, premarshaled} return json.Marshal(result) case *TopicNewestContentNewestContentVideo: typename = "Video" + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } result := struct { TypeName string `json:"__typename"` - *TopicNewestContentNewestContentVideo - }{typename, v} + *__premarshalTopicNewestContentNewestContentVideo + }{typename, premarshaled} return json.Marshal(result) case nil: return []byte("null"), nil @@ -2054,12 +2110,65 @@ func __marshalTopicNewestContentNewestContentLeafContent(v *TopicNewestContentNe // TopicNewestContentNewestContentVideo includes the requested fields of the GraphQL type Video. type TopicNewestContentNewestContentVideo struct { - Typename string `json:"__typename"` + Typename string `json:"__typename"` + SimpleLeafContentVideo `json:"-"` } // GetTypename returns TopicNewestContentNewestContentVideo.Typename, and is useful for accessing the field via an interface. func (v *TopicNewestContentNewestContentVideo) GetTypename() string { return v.Typename } +// GetId returns TopicNewestContentNewestContentVideo.Id, and is useful for accessing the field via an interface. +func (v *TopicNewestContentNewestContentVideo) GetId() testutil.ID { + return v.SimpleLeafContentVideo.Id +} + +func (v *TopicNewestContentNewestContentVideo) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *TopicNewestContentNewestContentVideo + graphql.NoUnmarshalJSON + } + firstPass.TopicNewestContentNewestContentVideo = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.SimpleLeafContentVideo) + if err != nil { + return err + } + return nil +} + +type __premarshalTopicNewestContentNewestContentVideo struct { + Typename string `json:"__typename"` + + Id testutil.ID `json:"id"` +} + +func (v *TopicNewestContentNewestContentVideo) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *TopicNewestContentNewestContentVideo) __premarshalJSON() (*__premarshalTopicNewestContentNewestContentVideo, error) { + var retval __premarshalTopicNewestContentNewestContentVideo + + retval.Typename = v.Typename + retval.Id = v.SimpleLeafContentVideo.Id + return &retval, nil +} + // UserLastContent includes the GraphQL fields of User requested by the fragment UserLastContent. // The GraphQL type's documentation follows. // @@ -2138,12 +2247,63 @@ func (v *UserLastContent) __premarshalJSON() (*__premarshalUserLastContent, erro // UserLastContentLastContentArticle includes the requested fields of the GraphQL type Article. type UserLastContentLastContentArticle struct { - Typename string `json:"__typename"` + Typename string `json:"__typename"` + SimpleLeafContentArticle `json:"-"` } // GetTypename returns UserLastContentLastContentArticle.Typename, and is useful for accessing the field via an interface. func (v *UserLastContentLastContentArticle) GetTypename() string { return v.Typename } +// GetId returns UserLastContentLastContentArticle.Id, and is useful for accessing the field via an interface. +func (v *UserLastContentLastContentArticle) GetId() testutil.ID { return v.SimpleLeafContentArticle.Id } + +func (v *UserLastContentLastContentArticle) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *UserLastContentLastContentArticle + graphql.NoUnmarshalJSON + } + firstPass.UserLastContentLastContentArticle = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.SimpleLeafContentArticle) + if err != nil { + return err + } + return nil +} + +type __premarshalUserLastContentLastContentArticle struct { + Typename string `json:"__typename"` + + Id testutil.ID `json:"id"` +} + +func (v *UserLastContentLastContentArticle) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *UserLastContentLastContentArticle) __premarshalJSON() (*__premarshalUserLastContentLastContentArticle, error) { + var retval __premarshalUserLastContentLastContentArticle + + retval.Typename = v.Typename + retval.Id = v.SimpleLeafContentArticle.Id + return &retval, nil +} + // UserLastContentLastContentLeafContent includes the requested fields of the GraphQL interface LeafContent. // // UserLastContentLastContentLeafContent is implemented by the following types: @@ -2161,10 +2321,8 @@ type UserLastContentLastContentLeafContent interface { func (v *UserLastContentLastContentArticle) implementsGraphQLInterfaceUserLastContentLastContentLeafContent() { } -func (v *UserLastContentLastContentArticle) implementsGraphQLInterfaceSimpleLeafContent() {} func (v *UserLastContentLastContentVideo) implementsGraphQLInterfaceUserLastContentLastContentLeafContent() { } -func (v *UserLastContentLastContentVideo) implementsGraphQLInterfaceSimpleLeafContent() {} func __unmarshalUserLastContentLastContentLeafContent(b []byte, v *UserLastContentLastContentLeafContent) error { if string(b) == "null" { @@ -2202,18 +2360,26 @@ func __marshalUserLastContentLastContentLeafContent(v *UserLastContentLastConten case *UserLastContentLastContentArticle: typename = "Article" + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } result := struct { TypeName string `json:"__typename"` - *UserLastContentLastContentArticle - }{typename, v} + *__premarshalUserLastContentLastContentArticle + }{typename, premarshaled} return json.Marshal(result) case *UserLastContentLastContentVideo: typename = "Video" + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } result := struct { TypeName string `json:"__typename"` - *UserLastContentLastContentVideo - }{typename, v} + *__premarshalUserLastContentLastContentVideo + }{typename, premarshaled} return json.Marshal(result) case nil: return []byte("null"), nil @@ -2225,12 +2391,63 @@ func __marshalUserLastContentLastContentLeafContent(v *UserLastContentLastConten // UserLastContentLastContentVideo includes the requested fields of the GraphQL type Video. type UserLastContentLastContentVideo struct { - Typename string `json:"__typename"` + Typename string `json:"__typename"` + SimpleLeafContentVideo `json:"-"` } // GetTypename returns UserLastContentLastContentVideo.Typename, and is useful for accessing the field via an interface. func (v *UserLastContentLastContentVideo) GetTypename() string { return v.Typename } +// GetId returns UserLastContentLastContentVideo.Id, and is useful for accessing the field via an interface. +func (v *UserLastContentLastContentVideo) GetId() testutil.ID { return v.SimpleLeafContentVideo.Id } + +func (v *UserLastContentLastContentVideo) UnmarshalJSON(b []byte) error { + + if string(b) == "null" { + return nil + } + + var firstPass struct { + *UserLastContentLastContentVideo + graphql.NoUnmarshalJSON + } + firstPass.UserLastContentLastContentVideo = v + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + err = json.Unmarshal( + b, &v.SimpleLeafContentVideo) + if err != nil { + return err + } + return nil +} + +type __premarshalUserLastContentLastContentVideo struct { + Typename string `json:"__typename"` + + Id testutil.ID `json:"id"` +} + +func (v *UserLastContentLastContentVideo) MarshalJSON() ([]byte, error) { + premarshaled, err := v.__premarshalJSON() + if err != nil { + return nil, err + } + return json.Marshal(premarshaled) +} + +func (v *UserLastContentLastContentVideo) __premarshalJSON() (*__premarshalUserLastContentLastContentVideo, error) { + var retval __premarshalUserLastContentLastContentVideo + + retval.Typename = v.Typename + retval.Id = v.SimpleLeafContentVideo.Id + return &retval, nil +} + // VideoFields includes the GraphQL fields of Video requested by the fragment VideoFields. type VideoFields struct { // ID is documented in the Content interface. diff --git a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go index 47213148..74aa5774 100644 --- a/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-CovariantInterfaceImplementation.graphql-CovariantInterfaceImplementation.graphql.go @@ -1089,16 +1089,10 @@ type CovariantInterfaceImplementationRandomItemContentNextContent interface { func (v *CovariantInterfaceImplementationRandomItemContentNextArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentNextArticle) implementsGraphQLInterfaceContentFields() { -} func (v *CovariantInterfaceImplementationRandomItemContentNextTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentNextTopic) implementsGraphQLInterfaceContentFields() { -} func (v *CovariantInterfaceImplementationRandomItemContentNextVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentNextContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentNextVideo) implementsGraphQLInterfaceContentFields() { -} func __unmarshalCovariantInterfaceImplementationRandomItemContentNextContent(b []byte, v *CovariantInterfaceImplementationRandomItemContentNextContent) error { if string(b) == "null" { @@ -1495,16 +1489,10 @@ type CovariantInterfaceImplementationRandomItemContentRelatedContent interface { func (v *CovariantInterfaceImplementationRandomItemContentRelatedArticle) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentRelatedArticle) implementsGraphQLInterfaceContentFields() { -} func (v *CovariantInterfaceImplementationRandomItemContentRelatedTopic) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentRelatedTopic) implementsGraphQLInterfaceContentFields() { -} func (v *CovariantInterfaceImplementationRandomItemContentRelatedVideo) implementsGraphQLInterfaceCovariantInterfaceImplementationRandomItemContentRelatedContent() { } -func (v *CovariantInterfaceImplementationRandomItemContentRelatedVideo) implementsGraphQLInterfaceContentFields() { -} func __unmarshalCovariantInterfaceImplementationRandomItemContentRelatedContent(b []byte, v *CovariantInterfaceImplementationRandomItemContentRelatedContent) error { if string(b) == "null" { diff --git a/generate/types.go b/generate/types.go index 7641d9b1..01f619f5 100644 --- a/generate/types.go +++ b/generate/types.go @@ -522,17 +522,6 @@ func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error { for _, impl := range typ.Implementations { fmt.Fprintf(w, "func (v *%s) %s() {}\n", impl.Reference(), implementsMethodName) - - // implement nested interface union type - for _, sharedField := range typ.SharedFields { - if sharedField.IsAbstract() { - // embedded type - if sharedField.GoName == "" { - fmt.Fprintf(w, "func (v *%s) %s() {}\n", - impl.Reference(), fmt.Sprintf("implementsGraphQLInterface%s", sharedField.GoType.Reference())) - } - } - } } // Finally, write the marshal- and unmarshal-helpers, which