From f3ad6f061bca880ea94a05e8702dc2dc8f463c6d Mon Sep 17 00:00:00 2001 From: Ben Kraft Date: Wed, 25 Aug 2021 17:35:50 -0700 Subject: [PATCH] Fix type-naming in the presence of interfaces, and refactor it a lot When adding support for interfaces, I did not do the type-names as I intended: they came out to be `MyFieldMyType`, not `MyInterfaceMyFieldMyType`, which is inconsistent, but not strictly wrong. But once supporting fragments, this is also now incorrect. (Exactly why is described in the comments inline.) In this commit, in any case, I fix it. To do that, I finally did the last of the refactors I've been hoping to do but unable to successfully implement, which is to make the type-name and type-name-prefix management clearer. In the past it was kind of spread out, and each caller would have to pass the right name into `convertDefinition`, which go quite unwieldy. Now, the case that really wanted that -- the operation toplevel -- just does it own thing; and the main name-generation code is factored out into a separate file with tests, and with a long comment that goes into all the details of the algorithm that the design-doc didn't cover. (I even had some fun using a linked list to implement the prefix-stack!) This allowed me to fix the above bug fairly easily -- actually the fix was pretty much automatic once I understood how to organize things. There is one change which is that if your query name is unexported, we no longer do the same with the input-type names; it's unclear to me if anyone will actually care about this behavior (Khan always makes the queries exported) but if they did it was very inconsistent (only at the query toplevel, and only for input-objects, not enums), so we can reimplement it properly if that comes up. As a bonus fix, we now better handle the case where your type-names are lowercase, which is legal if nonstandard GraphQL. Issue: https://github.com/Khan/genqlient/issues/8 Test plan: make tesc Reviewers: marksandstrom, adam, miguel --- DESIGN.md | 2 + generate/convert.go | 127 +++---- generate/generate.go | 6 +- generate/names.go | 157 ++++++++ generate/names_test.go | 62 +++ ....graphql-ComplexInlineFragments.graphql.go | 356 +++++++++--------- ...esting.graphql-InterfaceNesting.graphql.go | 110 +++--- ...e-unexported.graphql-unexported.graphql.go | 32 +- generate/util.go | 15 - generate/util_test.go | 22 -- internal/integration/generated.go | 165 ++++---- internal/integration/integration_test.go | 7 +- 12 files changed, 610 insertions(+), 451 deletions(-) create mode 100644 generate/names.go create mode 100644 generate/names_test.go diff --git a/DESIGN.md b/DESIGN.md index c7c2a521..806ffe5f 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -108,6 +108,8 @@ We'll do something similar to Apollo's naming scheme. Specifically: - Fragments will have some naming scheme TBD but starting at the fragment. - Input objects will have a name starting at the type, since they always have the same fields, and often have naming schemes like "MyFieldInput" already. +See `generate/names.go` for the precise algorithm. + All of this may be configurable later. ### How to represent interfaces diff --git a/generate/convert.go b/generate/convert.go index 8d471176..0f743da0 100644 --- a/generate/convert.go +++ b/generate/convert.go @@ -11,7 +11,6 @@ package generate import ( "fmt" - "strings" "github.com/vektah/gqlparser/v2/ast" ) @@ -51,20 +50,26 @@ func (g *generator) convertOperation( return nil, errorf(operation.Position, "%v", err) } - goTyp, err := g.convertDefinition( - name, operation.Name, baseType, operation.Position, - operation.SelectionSet, queryOptions, queryOptions) - - if structType, ok := goTyp.(*goStructType); ok { - // Override the ordinary description; the GraphQL documentation for - // Query/Mutation is unlikely to be of value. - // TODO(benkraft): This is a bit awkward/fragile. - structType.Description = - fmt.Sprintf("%v is returned by %v on success.", name, operation.Name) - structType.Incomplete = false + // Instead of calling out to convertType/convertDefinition, we do our own + // thing, because we want to do a few things differently, and because we + // know we have an object type, so we can include only that case. + fields, err := g.convertSelectionSet( + &prefixList{last: operation.Name}, operation.SelectionSet, baseType, queryOptions) + if err != nil { + return nil, err } - return goTyp, err + goType := &goStructType{ + GoName: name, + Description: fmt.Sprintf( + "%v is returned by %v on success.", name, operation.Name), + GraphQLName: baseType.Name, + Fields: fields, + Incomplete: false, + } + g.typeMap[name] = goType + + return goType, nil } var builtinTypes = map[string]string{ @@ -76,58 +81,15 @@ var builtinTypes = map[string]string{ "ID": "string", } -// typeName computes the name, in Go, that we should use for the given -// GraphQL type definition. This is dependent on its location within the query -// (see DESIGN.md for more on why we generate type-names this way), which is -// determined by the prefix argument; the nextPrefix result should be passed to -// calls to typeName on any child types. -func (g *generator) typeName(prefix string, typ *ast.Definition) (name, nextPrefix string) { - typeGoName := upperFirst(typ.Name) - if typ.Kind == ast.Enum || typ.Kind == ast.InputObject { - // If we're an enum or an input-object, there is only one type we - // will ever possibly generate for this type, so we don't need any - // of the qualifiers. This is especially helpful because the - // caller is very likely to need to reference these types in their - // code. - return typeGoName, typeGoName - } - - name = prefix - if !strings.HasSuffix(prefix, typeGoName) { - // If the field and type names are the same, we can avoid the - // duplication. (We include the field name in case there are - // multiple fields with the same type, and the type name because - // that's the actual name (the rest are really qualifiers); but if - // they are the same then including it once suffices for both - // purposes.) - name += typeGoName - } - - if typ.Kind == ast.Interface || typ.Kind == ast.Union { - // for interface/union types, we do not add the type name to the - // name prefix; we want to have QueryFieldType rather than - // QueryFieldInterfaceType. So we just use the input prefix. - return name, prefix - } - - // Otherwise, the name will also be the prefix for the next type. - return name, name -} - // convertInputType decides the Go type we will generate corresponding to an // argument to a GraphQL operation. func (g *generator) convertInputType( - opName string, typ *ast.Type, options, queryOptions *GenqlientDirective, ) (goType, error) { - // Sort of a hack: case the input type name to match the op-name. - // TODO(benkraft): this is another thing that breaks the assumption that we - // only need one of an input type, albeit in a relatively safe way. - name := matchFirst(typ.Name(), opName) // note prefix is ignored here (see generator.typeName), as is selectionSet // (for input types we use the whole thing)). - return g.convertType(name, "", typ, nil, options, queryOptions) + return g.convertType(nil, typ, nil, options, queryOptions) } // convertType decides the Go type we will generate corresponding to a @@ -135,7 +97,7 @@ func (g *generator) convertInputType( // field, and may be a list or a reference to a named type, with or without the // "non-null" annotation. func (g *generator) convertType( - name, namePrefix string, + namePrefix *prefixList, typ *ast.Type, selectionSet ast.SelectionSet, options, queryOptions *GenqlientDirective, @@ -152,14 +114,14 @@ func (g *generator) convertType( if typ.Elem != nil { // Type is a list. elem, err := g.convertType( - name, namePrefix, typ.Elem, selectionSet, options, queryOptions) + namePrefix, typ.Elem, selectionSet, options, queryOptions) return &goSliceType{elem}, err } // If this is a builtin type or custom scalar, just refer to it. def := g.schema.Types[typ.Name()] goTyp, err := g.convertDefinition( - name, namePrefix, def, typ.Position, selectionSet, options, queryOptions) + namePrefix, def, typ.Position, selectionSet, options, queryOptions) if options.GetPointer() { // Whatever we get, wrap it in a pointer. (Because of the way the @@ -177,7 +139,7 @@ func (g *generator) convertType( // *ast.Definition, which represents the definition of a type in the GraphQL // schema, which may be referenced by a field-type (see convertType). func (g *generator) convertDefinition( - name, namePrefix string, + namePrefix *prefixList, def *ast.Definition, pos *ast.Position, selectionSet ast.SelectionSet, @@ -200,6 +162,8 @@ func (g *generator) convertDefinition( switch def.Kind { case ast.Object: + name := makeTypeName(namePrefix, def.Name) + fields, err := g.convertSelectionSet( namePrefix, selectionSet, def, queryOptions) if err != nil { @@ -217,6 +181,12 @@ func (g *generator) convertDefinition( return goType, nil case ast.InputObject: + // If we're an input-object, there is only one type we will ever + // possibly generate for this type, so we don't need any of the + // qualifiers. This is especially helpful because the caller is very + // likely to need to reference these types in their code. + name := upperFirst(def.Name) + goType := &goStructType{ GoName: name, Description: def.Description, @@ -236,7 +206,7 @@ func (g *generator) convertDefinition( // will be ignored? We know field.Type is a scalar, enum, or input // type. But plumbing that is a bit tricky in practice. fieldGoType, err := g.convertType( - field.Type.Name(), "", field.Type, nil, queryOptions, queryOptions) + namePrefix, field.Type, nil, queryOptions, queryOptions) if err != nil { return nil, err } @@ -252,6 +222,8 @@ func (g *generator) convertDefinition( return goType, nil case ast.Interface, ast.Union: + name := makeTypeName(namePrefix, def.Name) + sharedFields, err := g.convertSelectionSet( namePrefix, selectionSet, def, queryOptions) if err != nil { @@ -279,14 +251,14 @@ func (g *generator) convertDefinition( // 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) + // STOPSHIP: update all this nonsense // 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, namePrefix, implDef, pos, selectionSet, options, queryOptions) + namePrefix, implDef, pos, selectionSet, options, queryOptions) if err != nil { return nil, err } @@ -302,6 +274,10 @@ func (g *generator) convertDefinition( return goType, nil case ast.Enum: + // Like with InputObject, there's only one type we will ever generate + // for an enum. + name := upperFirst(def.Name) + goType := &goEnumType{ GoName: name, Description: def.Description, @@ -335,7 +311,7 @@ func (g *generator) convertDefinition( // convertSelectionSet once for the interface, and once for each // implementation. func (g *generator) convertSelectionSet( - namePrefix string, + namePrefix *prefixList, selectionSet ast.SelectionSet, containingTypedef *ast.Definition, queryOptions *GenqlientDirective, @@ -457,7 +433,7 @@ func fragmentMatches(containingTypedef, fragmentTypedef *ast.Definition) bool { // parent selection-set (except of course they are only included in types the // fragment matches); see DESIGN.md for more. func (g *generator) convertInlineFragment( - namePrefix string, + namePrefix *prefixList, fragment *ast.InlineFragment, containingTypedef *ast.Definition, queryOptions *GenqlientDirective, @@ -479,7 +455,7 @@ func (g *generator) convertInlineFragment( // convertDefinition), because they come from the type-definition, not the // operation. func (g *generator) convertField( - namePrefix string, + namePrefix *prefixList, field *ast.Field, fieldOptions, queryOptions *GenqlientDirective, ) (*goStructField, error) { @@ -490,24 +466,11 @@ func (g *generator) convertField( field.Position, "undefined field %v", field.Alias) } - // Needs to be exported for JSON-marshaling goName := upperFirst(field.Alias) + namePrefix = nextPrefix(namePrefix, field) - typ := field.Definition.Type - fieldTypedef := g.schema.Types[typ.Name()] - - // Note we don't deduplicate suffixes here -- if our prefix is GetUser and - // the field name is User, we do GetUserUser. This is important because if - // you have a field called user on a type called User we need - // `query q { user { user { id } } }` to generate two types, QUser and - // QUserUser. Note also this is named based on the GraphQL alias (Go - // name), not the field-name, because if we have - // `query q { a: f { b }, c: f { d } }` we need separate types for a and c, - // even though they are the same type in GraphQL, because they have - // different fields. - name, namePrefix := g.typeName(namePrefix+goName, fieldTypedef) fieldGoType, err := g.convertType( - name, namePrefix, typ, field.SelectionSet, + namePrefix, field.Definition.Type, field.SelectionSet, fieldOptions, queryOptions) if err != nil { return nil, err diff --git a/generate/generate.go b/generate/generate.go index fc1abdf3..befd9511 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -117,7 +117,6 @@ func (g *generator) Types() (string, error) { } func (g *generator) getArgument( - opName string, arg *ast.VariableDefinition, operationDirective *GenqlientDirective, ) (argument, error) { @@ -127,8 +126,7 @@ func (g *generator) getArgument( } graphQLName := arg.Variable - goTyp, err := g.convertInputType( - opName, arg.Type, directive, operationDirective) + goTyp, err := g.convertInputType(arg.Type, directive, operationDirective) if err != nil { return argument{}, err } @@ -231,7 +229,7 @@ func (g *generator) addOperation(op *ast.OperationDefinition) error { args := make([]argument, len(op.VariableDefinitions)) for i, arg := range op.VariableDefinitions { - args[i], err = g.getArgument(op.Name, arg, directive) + args[i], err = g.getArgument(arg, directive) if err != nil { return err } diff --git a/generate/names.go b/generate/names.go new file mode 100644 index 00000000..9fd2d191 --- /dev/null +++ b/generate/names.go @@ -0,0 +1,157 @@ +package generate + +// This file generates the names for genqlient's generated types. This is +// somewhat tricky because the names need to be unique, stable, and, to the +// extent possible, human-readable and -writable. See DESIGN.md for an +// overview of the considerations; in short, we need long names. +// +// Specifically, the names we generate are of the form: +// MyOperationMyFieldMyTypeMySubFieldMySubType +// We need the "MyOperation" prefix because different operations may have +// different fields selected in the same "location" within the query. We need +// to include the field-path, because even within the same query, the same +// GraphQL type may have different selections in different locations. +// Including the types along the path is only strictly necessary in the case of +// interfaces, where, in a query like +// query Q { +// f { # type: I +// ... on T { g { h } } +// ... on U { g { h } } +// } +// } +// the type of .f.g may be different depending on whether the +// concrete type is a T or a U; if we simply called the types QFG they'd +// collide. We could in principle omit the types where there are no interfaces +// in sight, but having the last thing in the name be the actual GraphQL type +// name (MySubType in the first example) makes things more readable, and the +// value of consistency seems greater than the value of brevity, given the +// types are quite verbose either way. Note that in all cases the "MyField" is +// the alias of the field -- the name it has in this query -- since you could +// have `query Q { a: f { b }, c: f { d } }` and Q.A and Q.B must have +// different types. +// +// One subtlety in the above description is: is the "MyType" the interface or +// the impelmentation? When it's a suffix, the answer is both: we generate +// both MyFieldMyInterface and MyFieldMyImplementation, and the latter, in Go, +// implements the former. (See DESIGN.md for more.) But as an infix, we use +// the type on which the field is requested. Concretely, the following schema +// and query: +// type Query { f: I } +// interface I { g: G } +// type T implements I { g: G, h: H } +// type U implements I { g: G, h: H } +// type G { g1: String, g2: String } +// type H { h1: String, h2: String, h3: String, h4: String } +// +// query Q { +// f { +// g { g1 g2 } +// ... on T { h { h1 h2 } } +// ... on U { h { h3 h4 } } +// } +// } +// The field g must have type QFIG (not QFTG and QFHG), so that QFI's method +// GetG() can return a consistent type. But the fields h must have types QFTH +// and QFUH (not QFIH), because the two are different: the former has fields h1 +// and h2, whereas the latter has fields h3 and h4. So, in summary, since `g` +// is selected in a context of type I, it uses that (interface) type in its +// type-name, and `h` is selected in contexts of types T and U, they use those +// (implementation) types in their type-names. +// +// We do shorten the names in one case: if the name of a field ends with +// the name of its type, we omit the type name, avoiding types like +// MyQueryUserUser when querying a field of type user and value user. Note we +// do not do this for field names, both because it's less common, and because +// in `query Q { user { user { id } } }` we do need both QUser and QUserUser -- +// they have different fields. +// +// Note that there are (at least) two potential collisions from this algorithm: +// - When generating Go types for GraphQL interface types, we generate both +// ...MyFieldMyInterfaceType and ...MyFieldMyImplType. If an interface's +// name is a suffix of its implementation's name, and both are suffixes of a +// field of that type, we'll shorten both, resulting in a collision. +// - Given a query like +// query Q { +// ab { ... } # type: C +// a { ... } # type: BC +// } +// we generate QABC to represent both fields. +// Both cases seem fairly rare in practice; eventually we'll likely allow users +// the ability to specify their own names, which they could use to avoid this +// (see https://github.com/Khan/genqlient/issues/12). +// TODO(benkraft): We should probably at least try to detect it and bail. +// +// To implement all of the above, as we traverse the operation (and schema) in +// convert.go, we keep track of a list of parts to prefix to our type-names. +// The list always ends with a field, not a type; and we extend it when +// traversing fields, to allow for correct handling of the interface case +// discussed above. This file implements the actual maintenance of that +// prefix, and the code to compute the actual type-name from it. +// +// Note that input objects and enums are handled separately (inline in +// convertDefinition) since the same considerations don't apply and their names +// are thus quite simple. We also specially-handle the type of the toplevel +// response object (inline in convertOperation). + +import ( + "strings" + + "github.com/vektah/gqlparser/v2/ast" +) + +// Yes, a linked list! We could use a stack -- it would probably be marginally +// more efficient -- but then the caller would have to know more about how to +// manage it safely. Using a list, and treating it as immutable, makes it +// easy. +type prefixList struct { + last string // the list goes back-to-front, so this is the *last* prefix + rest *prefixList +} + +func joinPrefixList(prefix *prefixList) string { + var reversed []string + for ; prefix != nil; prefix = prefix.rest { + reversed = append(reversed, prefix.last) + } + l := len(reversed) + for i := 0; i < l/2; i++ { + reversed[i], reversed[l-1-i] = reversed[l-1-i], reversed[i] + } + return strings.Join(reversed, "") +} + +// Given a prefix-list, and the next type-name, compute the prefix-list with +// that type-name added (if applicable). The returned value is not a valid +// prefix-list, since it ends with a type, not a field (see top-of-file +// comment), but it's used to construct both the type-names from the input and +// the next prefix-list. +func typeNameParts(prefix *prefixList, typeName string) *prefixList { + // GraphQL types are conventionally UpperCamelCase, but it's not required; + // our names will look best if they are. + typeName = upperFirst(typeName) + // If the prefix has just one part, that's the operation-name. There's no + // need to add "Query" or "Mutation". (Zero should never happen.) + if prefix == nil || prefix.rest == nil || + // If the last prefix field ends with this type's name, omit the + // type-name (see the "shortened" case in the top-of-file comment). + strings.HasSuffix(prefix.last, typeName) { + return prefix + } + return &prefixList{typeName, prefix} +} + +// Given a prefix-list, and a field, compute the next prefix-list, which will +// be used for that field's selections. +func nextPrefix(prefix *prefixList, field *ast.Field) *prefixList { + // Add the type. + prefix = typeNameParts(prefix, field.ObjectDefinition.Name) + // Add the field (there's no shortening here, see top-of-file comment). + prefix = &prefixList{upperFirst(field.Alias), prefix} + return prefix +} + +// Given a prefix-list, and the GraphQL of the current type, compute the name +// we should give it in Go. +func makeTypeName(prefix *prefixList, typeName string) string { + return joinPrefixList(typeNameParts(prefix, typeName)) +} diff --git a/generate/names_test.go b/generate/names_test.go new file mode 100644 index 00000000..bb87a539 --- /dev/null +++ b/generate/names_test.go @@ -0,0 +1,62 @@ +package generate + +import ( + "testing" + + "github.com/vektah/gqlparser/v2/ast" +) + +func fakeField(containingTypeName, fieldName string) *ast.Field { + // (just the fields we need, probably not usable outside this file) + return &ast.Field{ + Alias: fieldName, + ObjectDefinition: &ast.Definition{Name: containingTypeName}, + } +} + +func TestTypeNames(t *testing.T) { + tests := []struct { + expectedTypeName string + fields []*ast.Field + leafTypeName string + }{{ + "OperationFieldType", + []*ast.Field{fakeField("Query", "field")}, + "Type", + }, { + "OperationUser", + []*ast.Field{fakeField("Query", "user")}, + "User", + }, { + "OperationFavoriteUser", + []*ast.Field{fakeField("Query", "favoriteUser")}, + "User", + }, { + "OperationField1Type1Field2Type2", + []*ast.Field{fakeField("Query", "field1"), fakeField("Type1", "field2")}, + "Type2", + }, { + "OperationUpperFieldLowerType", + // This is legal GraphQL! + []*ast.Field{fakeField("Query", "UpperField")}, + "lowerType", + }, { + "OperationUpperLowerUpperLower", + []*ast.Field{fakeField("Query", "Upper"), fakeField("lower", "Upper")}, + "lower", + }} + for _, test := range tests { + test := test + t.Run(test.expectedTypeName, func(t *testing.T) { + prefix := &prefixList{last: "Operation"} + for _, field := range test.fields { + prefix = nextPrefix(prefix, field) + } + actualTypeName := makeTypeName(prefix, test.leafTypeName) + if actualTypeName != test.expectedTypeName { + t.Errorf("name mismatch:\ngot: %s\nwant: %s", + actualTypeName, test.expectedTypeName) + } + }) + } +} diff --git a/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go index b223929d..389a0a46 100644 --- a/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go @@ -12,8 +12,14 @@ import ( // ComplexInlineFragmentsConflictingStuffArticle includes the requested fields of the GraphQL type Article. type ComplexInlineFragmentsConflictingStuffArticle struct { - Typename string `json:"__typename"` - Thumbnail ComplexInlineFragmentsConflictingStuffThumbnail `json:"thumbnail"` + Typename string `json:"__typename"` + Thumbnail ComplexInlineFragmentsConflictingStuffArticleThumbnailStuffThumbnail `json:"thumbnail"` +} + +// ComplexInlineFragmentsConflictingStuffArticleThumbnailStuffThumbnail includes the requested fields of the GraphQL type StuffThumbnail. +type ComplexInlineFragmentsConflictingStuffArticleThumbnailStuffThumbnail struct { + Id testutil.ID `json:"id"` + ThumbnailUrl string `json:"thumbnailUrl"` } // ComplexInlineFragmentsConflictingStuffContent includes the requested fields of the GraphQL interface Content. @@ -79,12 +85,6 @@ func __unmarshalComplexInlineFragmentsConflictingStuffContent(v *ComplexInlineFr } } -// ComplexInlineFragmentsConflictingStuffThumbnail includes the requested fields of the GraphQL type Thumbnail. -type ComplexInlineFragmentsConflictingStuffThumbnail struct { - Id testutil.ID `json:"id"` - TimestampSec int `json:"timestampSec"` -} - // ComplexInlineFragmentsConflictingStuffTopic includes the requested fields of the GraphQL type Topic. type ComplexInlineFragmentsConflictingStuffTopic struct { Typename string `json:"__typename"` @@ -92,73 +92,56 @@ type ComplexInlineFragmentsConflictingStuffTopic struct { // ComplexInlineFragmentsConflictingStuffVideo includes the requested fields of the GraphQL type Video. type ComplexInlineFragmentsConflictingStuffVideo struct { - Typename string `json:"__typename"` - Thumbnail ComplexInlineFragmentsConflictingStuffThumbnail `json:"thumbnail"` + Typename string `json:"__typename"` + Thumbnail ComplexInlineFragmentsConflictingStuffVideoThumbnail `json:"thumbnail"` } -// ComplexInlineFragmentsNestedStuffArticle includes the requested fields of the GraphQL type Article. -type ComplexInlineFragmentsNestedStuffArticle struct { - Typename string `json:"__typename"` +// ComplexInlineFragmentsConflictingStuffVideoThumbnail includes the requested fields of the GraphQL type Thumbnail. +type ComplexInlineFragmentsConflictingStuffVideoThumbnail struct { + Id testutil.ID `json:"id"` + TimestampSec int `json:"timestampSec"` } -// ComplexInlineFragmentsNestedStuffChildrenArticle includes the requested fields of the GraphQL type Article. -type ComplexInlineFragmentsNestedStuffChildrenArticle struct { +// ComplexInlineFragmentsNestedStuffArticle includes the requested fields of the GraphQL type Article. +type ComplexInlineFragmentsNestedStuffArticle struct { Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` - Text string `json:"text"` - Parent ComplexInlineFragmentsNestedStuffChildrenParentTopic `json:"parent"` } -// ComplexInlineFragmentsNestedStuffChildrenContent includes the requested fields of the GraphQL interface Content. +// ComplexInlineFragmentsNestedStuffContent includes the requested fields of the GraphQL interface Content. // -// ComplexInlineFragmentsNestedStuffChildrenContent is implemented by the following types: -// ComplexInlineFragmentsNestedStuffChildrenArticle -// ComplexInlineFragmentsNestedStuffChildrenVideo -// ComplexInlineFragmentsNestedStuffChildrenTopic +// ComplexInlineFragmentsNestedStuffContent is implemented by the following types: +// ComplexInlineFragmentsNestedStuffArticle +// ComplexInlineFragmentsNestedStuffVideo +// ComplexInlineFragmentsNestedStuffTopic // // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type ComplexInlineFragmentsNestedStuffChildrenContent interface { - implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenContent() +type ComplexInlineFragmentsNestedStuffContent interface { + implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() // 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 *ComplexInlineFragmentsNestedStuffChildrenArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenArticle) GetTypename() string { return v.Typename } - -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenArticle) GetId() testutil.ID { return v.Id } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. +func (v *ComplexInlineFragmentsNestedStuffArticle) GetTypename() string { return v.Typename } -func (v *ComplexInlineFragmentsNestedStuffChildrenVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenVideo) GetTypename() string { return v.Typename } - -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenVideo) GetId() testutil.ID { return v.Id } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. +func (v *ComplexInlineFragmentsNestedStuffVideo) GetTypename() string { return v.Typename } -func (v *ComplexInlineFragmentsNestedStuffChildrenTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenTopic) GetTypename() string { return v.Typename } - -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenTopic) GetId() testutil.ID { return v.Id } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. +func (v *ComplexInlineFragmentsNestedStuffTopic) GetTypename() string { return v.Typename } -func __unmarshalComplexInlineFragmentsNestedStuffChildrenContent(v *ComplexInlineFragmentsNestedStuffChildrenContent, m json.RawMessage) error { +func __unmarshalComplexInlineFragmentsNestedStuffContent(v *ComplexInlineFragmentsNestedStuffContent, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -173,40 +156,82 @@ func __unmarshalComplexInlineFragmentsNestedStuffChildrenContent(v *ComplexInlin switch tn.TypeName { case "Article": - *v = new(ComplexInlineFragmentsNestedStuffChildrenArticle) + *v = new(ComplexInlineFragmentsNestedStuffArticle) return json.Unmarshal(m, *v) case "Video": - *v = new(ComplexInlineFragmentsNestedStuffChildrenVideo) + *v = new(ComplexInlineFragmentsNestedStuffVideo) return json.Unmarshal(m, *v) case "Topic": - *v = new(ComplexInlineFragmentsNestedStuffChildrenTopic) + *v = new(ComplexInlineFragmentsNestedStuffTopic) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for ComplexInlineFragmentsNestedStuffChildrenContent: "%v"`, tn.TypeName) + `Unexpected concrete type for ComplexInlineFragmentsNestedStuffContent: "%v"`, tn.TypeName) } } -// ComplexInlineFragmentsNestedStuffChildrenParentTopic includes the requested fields of the GraphQL type Topic. -type ComplexInlineFragmentsNestedStuffChildrenParentTopic struct { - Name string `json:"name"` - Parent ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic `json:"parent"` +// ComplexInlineFragmentsNestedStuffTopic includes the requested fields of the GraphQL type Topic. +type ComplexInlineFragmentsNestedStuffTopic struct { + Typename string `json:"__typename"` + Children []ComplexInlineFragmentsNestedStuffTopicChildrenContent `json:"-"` } -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic includes the requested fields of the GraphQL type Topic. -type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic struct { - Children []ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent `json:"-"` +func (v *ComplexInlineFragmentsNestedStuffTopic) UnmarshalJSON(b []byte) error { + + type ComplexInlineFragmentsNestedStuffTopicWrapper ComplexInlineFragmentsNestedStuffTopic + + var firstPass struct { + *ComplexInlineFragmentsNestedStuffTopicWrapper + Children []json.RawMessage `json:"children"` + } + firstPass.ComplexInlineFragmentsNestedStuffTopicWrapper = (*ComplexInlineFragmentsNestedStuffTopicWrapper)(v) + + err := json.Unmarshal(b, &firstPass) + if err != nil { + return err + } + + { + target := &v.Children + raw := firstPass.Children + *target = make( + []ComplexInlineFragmentsNestedStuffTopicChildrenContent, + len(raw)) + for i, raw := range raw { + target := &(*target)[i] + err = __unmarshalComplexInlineFragmentsNestedStuffTopicChildrenContent( + target, raw) + if err != nil { + return err + } + } + } + return nil } -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic) UnmarshalJSON(b []byte) error { +// ComplexInlineFragmentsNestedStuffTopicChildrenArticle includes the requested fields of the GraphQL type Article. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticle struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` + Text string `json:"text"` + Parent ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentTopic `json:"parent"` +} - type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicWrapper ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopic includes the requested fields of the GraphQL type Topic. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopic struct { + Children []ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent `json:"-"` +} + +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopic) UnmarshalJSON(b []byte) error { + + type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicWrapper ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopic var firstPass struct { - *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicWrapper + *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicWrapper Children []json.RawMessage `json:"children"` } - firstPass.ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicWrapper = (*ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicWrapper)(v) + firstPass.ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicWrapper = (*ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicWrapper)(v) err := json.Unmarshal(b, &firstPass) if err != nil { @@ -217,11 +242,11 @@ func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic) Unmars target := &v.Children raw := firstPass.Children *target = make( - []ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent, + []ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent, len(raw)) for i, raw := range raw { target := &(*target)[i] - err = __unmarshalComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent( + err = __unmarshalComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent( target, raw) if err != nil { return err @@ -231,26 +256,26 @@ func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopic) Unmars return nil } -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. -type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle struct { +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` Name string `json:"name"` } -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent includes the requested fields of the GraphQL interface Content. // -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent is implemented by the following types: -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent is implemented by the following types: +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic // // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent interface { - implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent() +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent interface { + implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent() // 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. @@ -262,61 +287,61 @@ type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenCont GetName() string } -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle) GetTypename() string { +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle) GetId() testutil.ID { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle) GetId() testutil.ID { return v.Id } -// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle) GetName() string { +// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle) GetName() string { return v.Name } -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo) GetTypename() string { +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo) GetId() testutil.ID { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo) GetId() testutil.ID { return v.Id } -// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo) GetName() string { +// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo) GetName() string { return v.Name } -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent() { +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic) GetTypename() string { +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic) GetId() testutil.ID { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic) GetId() testutil.ID { return v.Id } -// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent. -func (v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic) GetName() string { +// GetName is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic) GetName() string { return v.Name } -func __unmarshalComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent(v *ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent, m json.RawMessage) error { +func __unmarshalComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent(v *ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -331,85 +356,93 @@ func __unmarshalComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicC switch tn.TypeName { case "Article": - *v = new(ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenArticle) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenArticle) return json.Unmarshal(m, *v) case "Video": - *v = new(ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo) return json.Unmarshal(m, *v) case "Topic": - *v = new(ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenContent: "%v"`, tn.TypeName) + `Unexpected concrete type for ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenContent: "%v"`, tn.TypeName) } } -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenTopic struct { +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenTopic struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` Name string `json:"name"` } -// ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type ComplexInlineFragmentsNestedStuffChildrenParentTopicParentTopicChildrenVideo struct { +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopicChildrenVideo struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` Name string `json:"name"` } -// ComplexInlineFragmentsNestedStuffChildrenTopic includes the requested fields of the GraphQL type Topic. -type ComplexInlineFragmentsNestedStuffChildrenTopic struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` -} - -// ComplexInlineFragmentsNestedStuffChildrenVideo includes the requested fields of the GraphQL type Video. -type ComplexInlineFragmentsNestedStuffChildrenVideo struct { - Typename string `json:"__typename"` - // ID is the identifier of the content. - Id testutil.ID `json:"id"` +// ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentTopic includes the requested fields of the GraphQL type Topic. +type ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentTopic struct { + Name string `json:"name"` + Parent ComplexInlineFragmentsNestedStuffTopicChildrenArticleParentContentParentTopic `json:"parent"` } -// ComplexInlineFragmentsNestedStuffContent includes the requested fields of the GraphQL interface Content. +// ComplexInlineFragmentsNestedStuffTopicChildrenContent includes the requested fields of the GraphQL interface Content. // -// ComplexInlineFragmentsNestedStuffContent is implemented by the following types: -// ComplexInlineFragmentsNestedStuffArticle -// ComplexInlineFragmentsNestedStuffVideo -// ComplexInlineFragmentsNestedStuffTopic +// ComplexInlineFragmentsNestedStuffTopicChildrenContent is implemented by the following types: +// ComplexInlineFragmentsNestedStuffTopicChildrenArticle +// ComplexInlineFragmentsNestedStuffTopicChildrenVideo +// ComplexInlineFragmentsNestedStuffTopicChildrenTopic // // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type ComplexInlineFragmentsNestedStuffContent interface { - implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() +type ComplexInlineFragmentsNestedStuffTopicChildrenContent interface { + implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenContent() // 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 *ComplexInlineFragmentsNestedStuffArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticle) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. -func (v *ComplexInlineFragmentsNestedStuffArticle) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticle) GetTypename() string { + return v.Typename +} -func (v *ComplexInlineFragmentsNestedStuffVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenArticle) GetId() testutil.ID { return v.Id } + +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenVideo) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. -func (v *ComplexInlineFragmentsNestedStuffVideo) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenVideo) GetTypename() string { return v.Typename } -func (v *ComplexInlineFragmentsNestedStuffTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffContent() { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenVideo) GetId() testutil.ID { return v.Id } + +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenTopic) implementsGraphQLInterfaceComplexInlineFragmentsNestedStuffTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffContent. -func (v *ComplexInlineFragmentsNestedStuffTopic) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenTopic) GetTypename() string { return v.Typename } -func __unmarshalComplexInlineFragmentsNestedStuffContent(v *ComplexInlineFragmentsNestedStuffContent, m json.RawMessage) error { +// GetId is a part of, and documented with, the interface ComplexInlineFragmentsNestedStuffTopicChildrenContent. +func (v *ComplexInlineFragmentsNestedStuffTopicChildrenTopic) GetId() testutil.ID { return v.Id } + +func __unmarshalComplexInlineFragmentsNestedStuffTopicChildrenContent(v *ComplexInlineFragmentsNestedStuffTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -424,57 +457,32 @@ func __unmarshalComplexInlineFragmentsNestedStuffContent(v *ComplexInlineFragmen switch tn.TypeName { case "Article": - *v = new(ComplexInlineFragmentsNestedStuffArticle) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenArticle) return json.Unmarshal(m, *v) case "Video": - *v = new(ComplexInlineFragmentsNestedStuffVideo) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenVideo) return json.Unmarshal(m, *v) case "Topic": - *v = new(ComplexInlineFragmentsNestedStuffTopic) + *v = new(ComplexInlineFragmentsNestedStuffTopicChildrenTopic) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for ComplexInlineFragmentsNestedStuffContent: "%v"`, tn.TypeName) + `Unexpected concrete type for ComplexInlineFragmentsNestedStuffTopicChildrenContent: "%v"`, tn.TypeName) } } -// ComplexInlineFragmentsNestedStuffTopic includes the requested fields of the GraphQL type Topic. -type ComplexInlineFragmentsNestedStuffTopic struct { - Typename string `json:"__typename"` - Children []ComplexInlineFragmentsNestedStuffChildrenContent `json:"-"` +// ComplexInlineFragmentsNestedStuffTopicChildrenTopic includes the requested fields of the GraphQL type Topic. +type ComplexInlineFragmentsNestedStuffTopicChildrenTopic struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` } -func (v *ComplexInlineFragmentsNestedStuffTopic) UnmarshalJSON(b []byte) error { - - type ComplexInlineFragmentsNestedStuffTopicWrapper ComplexInlineFragmentsNestedStuffTopic - - var firstPass struct { - *ComplexInlineFragmentsNestedStuffTopicWrapper - Children []json.RawMessage `json:"children"` - } - firstPass.ComplexInlineFragmentsNestedStuffTopicWrapper = (*ComplexInlineFragmentsNestedStuffTopicWrapper)(v) - - err := json.Unmarshal(b, &firstPass) - if err != nil { - return err - } - - { - target := &v.Children - raw := firstPass.Children - *target = make( - []ComplexInlineFragmentsNestedStuffChildrenContent, - len(raw)) - for i, raw := range raw { - target := &(*target)[i] - err = __unmarshalComplexInlineFragmentsNestedStuffChildrenContent( - target, raw) - if err != nil { - return err - } - } - } - return nil +// ComplexInlineFragmentsNestedStuffTopicChildrenVideo includes the requested fields of the GraphQL type Video. +type ComplexInlineFragmentsNestedStuffTopicChildrenVideo struct { + Typename string `json:"__typename"` + // ID is the identifier of the content. + Id testutil.ID `json:"id"` } // ComplexInlineFragmentsNestedStuffVideo includes the requested fields of the GraphQL type Video. diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go index 336bf1d3..97cd3b85 100644 --- a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go @@ -59,8 +59,8 @@ 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 InterfaceNestingRootTopicChildrenParentTopic `json:"parent"` + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenContentParentTopic `json:"parent"` } // InterfaceNestingRootTopicChildrenContent includes the requested fields of the GraphQL interface Content. @@ -83,7 +83,7 @@ type InterfaceNestingRootTopicChildrenContent interface { // ID is the identifier of the content. GetId() testutil.ID // GetParent returns the interface-field "parent" from its implementation. - GetParent() InterfaceNestingRootTopicChildrenParentTopic + GetParent() InterfaceNestingRootTopicChildrenContentParentTopic } func (v *InterfaceNestingRootTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContent() { @@ -96,7 +96,7 @@ func (v *InterfaceNestingRootTopicChildrenArticle) GetTypename() string { return func (v *InterfaceNestingRootTopicChildrenArticle) GetId() testutil.ID { return v.Id } // GetParent is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenArticle) GetParent() InterfaceNestingRootTopicChildrenParentTopic { +func (v *InterfaceNestingRootTopicChildrenArticle) GetParent() InterfaceNestingRootTopicChildrenContentParentTopic { return v.Parent } @@ -110,7 +110,7 @@ func (v *InterfaceNestingRootTopicChildrenVideo) GetTypename() string { return v func (v *InterfaceNestingRootTopicChildrenVideo) GetId() testutil.ID { return v.Id } // GetParent is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenVideo) GetParent() InterfaceNestingRootTopicChildrenParentTopic { +func (v *InterfaceNestingRootTopicChildrenVideo) GetParent() InterfaceNestingRootTopicChildrenContentParentTopic { return v.Parent } @@ -124,7 +124,7 @@ func (v *InterfaceNestingRootTopicChildrenTopic) GetTypename() string { return v 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 { +func (v *InterfaceNestingRootTopicChildrenTopic) GetParent() InterfaceNestingRootTopicChildrenContentParentTopic { return v.Parent } @@ -157,22 +157,22 @@ func __unmarshalInterfaceNestingRootTopicChildrenContent(v *InterfaceNestingRoot } } -// InterfaceNestingRootTopicChildrenParentTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenParentTopic struct { +// InterfaceNestingRootTopicChildrenContentParentTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNestingRootTopicChildrenContentParentTopic struct { // ID is documented in the Content interface. - Id testutil.ID `json:"id"` - Children []InterfaceNestingRootTopicChildrenParentTopicChildrenContent `json:"-"` + Id testutil.ID `json:"id"` + Children []InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent `json:"-"` } -func (v *InterfaceNestingRootTopicChildrenParentTopic) UnmarshalJSON(b []byte) error { +func (v *InterfaceNestingRootTopicChildrenContentParentTopic) UnmarshalJSON(b []byte) error { - type InterfaceNestingRootTopicChildrenParentTopicWrapper InterfaceNestingRootTopicChildrenParentTopic + type InterfaceNestingRootTopicChildrenContentParentTopicWrapper InterfaceNestingRootTopicChildrenContentParentTopic var firstPass struct { - *InterfaceNestingRootTopicChildrenParentTopicWrapper + *InterfaceNestingRootTopicChildrenContentParentTopicWrapper Children []json.RawMessage `json:"children"` } - firstPass.InterfaceNestingRootTopicChildrenParentTopicWrapper = (*InterfaceNestingRootTopicChildrenParentTopicWrapper)(v) + firstPass.InterfaceNestingRootTopicChildrenContentParentTopicWrapper = (*InterfaceNestingRootTopicChildrenContentParentTopicWrapper)(v) err := json.Unmarshal(b, &firstPass) if err != nil { @@ -183,11 +183,11 @@ func (v *InterfaceNestingRootTopicChildrenParentTopic) UnmarshalJSON(b []byte) e target := &v.Children raw := firstPass.Children *target = make( - []InterfaceNestingRootTopicChildrenParentTopicChildrenContent, + []InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent, len(raw)) for i, raw := range raw { target := &(*target)[i] - err = __unmarshalInterfaceNestingRootTopicChildrenParentTopicChildrenContent( + err = __unmarshalInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent( target, raw) if err != nil { return err @@ -197,25 +197,25 @@ func (v *InterfaceNestingRootTopicChildrenParentTopic) UnmarshalJSON(b []byte) e return nil } -// InterfaceNestingRootTopicChildrenParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. -type InterfaceNestingRootTopicChildrenParentTopicChildrenArticle struct { +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle includes the requested fields of the GraphQL type Article. +type InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` } -// InterfaceNestingRootTopicChildrenParentTopicChildrenContent includes the requested fields of the GraphQL interface Content. +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent includes the requested fields of the GraphQL interface Content. // -// InterfaceNestingRootTopicChildrenParentTopicChildrenContent is implemented by the following types: -// InterfaceNestingRootTopicChildrenParentTopicChildrenArticle -// InterfaceNestingRootTopicChildrenParentTopicChildrenVideo -// InterfaceNestingRootTopicChildrenParentTopicChildrenTopic +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent is implemented by the following types: +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic // // The GraphQL type's documentation follows. // // Content is implemented by various types like Article, Video, and Topic. -type InterfaceNestingRootTopicChildrenParentTopicChildrenContent interface { - implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() +type InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent interface { + implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent() // 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. @@ -225,42 +225,46 @@ type InterfaceNestingRootTopicChildrenParentTopicChildrenContent interface { GetId() testutil.ID } -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) GetTypename() string { +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) GetId() testutil.ID { +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle) GetId() testutil.ID { return v.Id } -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) GetTypename() string { +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) GetId() testutil.ID { return v.Id } +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo) GetId() testutil.ID { + return v.Id +} -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenParentTopicChildrenContent() { +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic) implementsGraphQLInterfaceInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent() { } -// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) GetTypename() string { +// GetTypename is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenParentTopicChildrenContent. -func (v *InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) GetId() testutil.ID { return v.Id } +// GetId is a part of, and documented with, the interface InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent. +func (v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic) GetId() testutil.ID { + return v.Id +} -func __unmarshalInterfaceNestingRootTopicChildrenParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenParentTopicChildrenContent, m json.RawMessage) error { +func __unmarshalInterfaceNestingRootTopicChildrenContentParentTopicChildrenContent(v *InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -275,29 +279,29 @@ func __unmarshalInterfaceNestingRootTopicChildrenParentTopicChildrenContent(v *I switch tn.TypeName { case "Article": - *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenArticle) + *v = new(InterfaceNestingRootTopicChildrenContentParentTopicChildrenArticle) return json.Unmarshal(m, *v) case "Video": - *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenVideo) + *v = new(InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo) return json.Unmarshal(m, *v) case "Topic": - *v = new(InterfaceNestingRootTopicChildrenParentTopicChildrenTopic) + *v = new(InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for InterfaceNestingRootTopicChildrenParentTopicChildrenContent: "%v"`, tn.TypeName) + `Unexpected concrete type for InterfaceNestingRootTopicChildrenContentParentTopicChildrenContent: "%v"`, tn.TypeName) } } -// InterfaceNestingRootTopicChildrenParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. -type InterfaceNestingRootTopicChildrenParentTopicChildrenTopic struct { +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic includes the requested fields of the GraphQL type Topic. +type InterfaceNestingRootTopicChildrenContentParentTopicChildrenTopic struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` } -// InterfaceNestingRootTopicChildrenParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. -type InterfaceNestingRootTopicChildrenParentTopicChildrenVideo struct { +// InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo includes the requested fields of the GraphQL type Video. +type InterfaceNestingRootTopicChildrenContentParentTopicChildrenVideo struct { Typename string `json:"__typename"` // ID is the identifier of the content. Id testutil.ID `json:"id"` @@ -307,16 +311,16 @@ type InterfaceNestingRootTopicChildrenParentTopicChildrenVideo struct { type InterfaceNestingRootTopicChildrenTopic struct { Typename string `json:"__typename"` // ID is the identifier of the content. - Id testutil.ID `json:"id"` - Parent InterfaceNestingRootTopicChildrenParentTopic `json:"parent"` + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenContentParentTopic `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"` + Id testutil.ID `json:"id"` + Parent InterfaceNestingRootTopicChildrenContentParentTopic `json:"parent"` } func InterfaceNesting( diff --git a/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go b/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go index f5c5b39f..dd94a60e 100644 --- a/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go @@ -21,6 +21,21 @@ const ( RoleTeacher Role = "TEACHER" ) +// UserQueryInput is the argument to Query.users. +// +// Ideally this would support anything and everything! +// Or maybe ideally it wouldn't. +// Really I'm just talking to make this documentation longer. +type UserQueryInput struct { + Email string `json:"email"` + Name string `json:"name"` + // id looks the user up by ID. It's a great way to look up users. + Id testutil.ID `json:"id"` + Role Role `json:"role"` + Names []string `json:"names"` + HasPokemon testutil.Pokemon `json:"hasPokemon"` +} + // unexportedResponse is returned by unexported on success. type unexportedResponse struct { // user looks up a user by some stuff. @@ -41,24 +56,9 @@ type unexportedUser struct { Id testutil.ID `json:"id"` } -// UserQueryInput is the argument to Query.users. -// -// Ideally this would support anything and everything! -// Or maybe ideally it wouldn't. -// Really I'm just talking to make this documentation longer. -type userQueryInput struct { - Email string `json:"email"` - Name string `json:"name"` - // id looks the user up by ID. It's a great way to look up users. - Id testutil.ID `json:"id"` - Role Role `json:"role"` - Names []string `json:"names"` - HasPokemon testutil.Pokemon `json:"hasPokemon"` -} - func unexported( client graphql.Client, - query userQueryInput, + query UserQueryInput, ) (*unexportedResponse, error) { variables := map[string]interface{}{ "query": query, diff --git a/generate/util.go b/generate/util.go index 9e4ff54d..ed745819 100644 --- a/generate/util.go +++ b/generate/util.go @@ -28,21 +28,6 @@ func upperFirst(s string) string { return changeFirst(strings.TrimLeft(s, "_"), unicode.ToUpper) } -func matchFirst(s, tmpl string) string { - c, n := utf8.DecodeRuneInString(s) - t, _ := utf8.DecodeRuneInString(tmpl) - if c == utf8.RuneError || n == utf8.RuneError { // empty or invalid - return s - } - - if unicode.IsUpper(t) { - c = unicode.ToUpper(c) - } else { - c = unicode.ToLower(c) - } - return string(c) + s[n:] -} - func goConstName(s string) string { if strings.TrimLeft(s, "_") == "" { return s diff --git a/generate/util_test.go b/generate/util_test.go index ba594360..886b7297 100644 --- a/generate/util_test.go +++ b/generate/util_test.go @@ -52,28 +52,6 @@ func TestUpperFirst(t *testing.T) { testStringFunc(t, upperFirst, tests) } -func TestMatchFirst(t *testing.T) { - tests := []struct { - name, in, out, match string - }{ - {"Empty", "", "", ""}, - {"LowerToUpper", "lower", "Lower", "Upper"}, - {"UpperToUpper", "Upper", "Upper", "Upper"}, - {"LowerToLower", "lower", "lower", "lower"}, - {"UpperToLower", "Upper", "upper", "lower"}, - } - - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - got := matchFirst(test.in, test.match) - if got != test.out { - t.Errorf("got %#v want %#v", got, test.out) - } - }) - } -} - func TestGoConstName(t *testing.T) { tests := []test{ {"Empty", "", ""}, diff --git a/internal/integration/generated.go b/internal/integration/generated.go index 8cf83333..e9d7f582 100644 --- a/internal/integration/generated.go +++ b/internal/integration/generated.go @@ -19,12 +19,12 @@ const ( // queryWithFragmentsBeingsAnimal includes the requested fields of the GraphQL type Animal. type queryWithFragmentsBeingsAnimal struct { - Typename string `json:"__typename"` - Id string `json:"id"` - Name string `json:"name"` - Hair queryWithFragmentsBeingsHair `json:"hair"` - Species Species `json:"species"` - Owner queryWithFragmentsBeingsOwnerBeing `json:"-"` + Typename string `json:"__typename"` + Id string `json:"id"` + Name string `json:"name"` + Hair queryWithFragmentsBeingsAnimalHairBeingsHair `json:"hair"` + Species Species `json:"species"` + Owner queryWithFragmentsBeingsAnimalOwnerBeing `json:"-"` } func (v *queryWithFragmentsBeingsAnimal) UnmarshalJSON(b []byte) error { @@ -45,7 +45,7 @@ func (v *queryWithFragmentsBeingsAnimal) UnmarshalJSON(b []byte) error { { target := &v.Owner raw := firstPass.Owner - err = __unmarshalqueryWithFragmentsBeingsOwnerBeing( + err = __unmarshalqueryWithFragmentsBeingsAnimalOwnerBeing( target, raw) if err != nil { return err @@ -54,17 +54,29 @@ func (v *queryWithFragmentsBeingsAnimal) UnmarshalJSON(b []byte) error { return nil } -// queryWithFragmentsBeingsBeing includes the requested fields of the GraphQL interface Being. +// queryWithFragmentsBeingsAnimalHairBeingsHair includes the requested fields of the GraphQL type BeingsHair. +type queryWithFragmentsBeingsAnimalHairBeingsHair struct { + HasHair bool `json:"hasHair"` +} + +// queryWithFragmentsBeingsAnimalOwnerAnimal includes the requested fields of the GraphQL type Animal. +type queryWithFragmentsBeingsAnimalOwnerAnimal struct { + Typename string `json:"__typename"` + Id string `json:"id"` + Name string `json:"name"` +} + +// queryWithFragmentsBeingsAnimalOwnerBeing includes the requested fields of the GraphQL interface Being. // -// queryWithFragmentsBeingsBeing is implemented by the following types: -// queryWithFragmentsBeingsUser -// queryWithFragmentsBeingsAnimal +// queryWithFragmentsBeingsAnimalOwnerBeing is implemented by the following types: +// queryWithFragmentsBeingsAnimalOwnerUser +// queryWithFragmentsBeingsAnimalOwnerAnimal // // The GraphQL type's documentation follows. // // -type queryWithFragmentsBeingsBeing interface { - implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() +type queryWithFragmentsBeingsAnimalOwnerBeing interface { + implementsGraphQLInterfacequeryWithFragmentsBeingsAnimalOwnerBeing() // 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. @@ -73,29 +85,31 @@ type queryWithFragmentsBeingsBeing interface { GetName() string } -func (v *queryWithFragmentsBeingsUser) implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() {} +func (v *queryWithFragmentsBeingsAnimalOwnerUser) implementsGraphQLInterfacequeryWithFragmentsBeingsAnimalOwnerBeing() { +} -// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsUser) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerUser) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsUser) GetId() string { return v.Id } +// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerUser) GetId() string { return v.Id } -// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsUser) GetName() string { return v.Name } +// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerUser) GetName() string { return v.Name } -func (v *queryWithFragmentsBeingsAnimal) implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() {} +func (v *queryWithFragmentsBeingsAnimalOwnerAnimal) implementsGraphQLInterfacequeryWithFragmentsBeingsAnimalOwnerBeing() { +} -// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsAnimal) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerAnimal) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsAnimal) GetId() string { return v.Id } +// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerAnimal) GetId() string { return v.Id } -// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. -func (v *queryWithFragmentsBeingsAnimal) GetName() string { return v.Name } +// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsAnimalOwnerBeing. +func (v *queryWithFragmentsBeingsAnimalOwnerAnimal) GetName() string { return v.Name } -func __unmarshalqueryWithFragmentsBeingsBeing(v *queryWithFragmentsBeingsBeing, m json.RawMessage) error { +func __unmarshalqueryWithFragmentsBeingsAnimalOwnerBeing(v *queryWithFragmentsBeingsAnimalOwnerBeing, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -110,40 +124,36 @@ func __unmarshalqueryWithFragmentsBeingsBeing(v *queryWithFragmentsBeingsBeing, switch tn.TypeName { case "User": - *v = new(queryWithFragmentsBeingsUser) + *v = new(queryWithFragmentsBeingsAnimalOwnerUser) return json.Unmarshal(m, *v) case "Animal": - *v = new(queryWithFragmentsBeingsAnimal) + *v = new(queryWithFragmentsBeingsAnimalOwnerAnimal) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for queryWithFragmentsBeingsBeing: "%v"`, tn.TypeName) + `Unexpected concrete type for queryWithFragmentsBeingsAnimalOwnerBeing: "%v"`, tn.TypeName) } } -// queryWithFragmentsBeingsHair includes the requested fields of the GraphQL type BeingsHair. -type queryWithFragmentsBeingsHair struct { - HasHair bool `json:"hasHair"` -} - -// queryWithFragmentsBeingsOwnerAnimal includes the requested fields of the GraphQL type Animal. -type queryWithFragmentsBeingsOwnerAnimal struct { - Typename string `json:"__typename"` - Id string `json:"id"` - Name string `json:"name"` +// queryWithFragmentsBeingsAnimalOwnerUser includes the requested fields of the GraphQL type User. +type queryWithFragmentsBeingsAnimalOwnerUser struct { + Typename string `json:"__typename"` + Id string `json:"id"` + Name string `json:"name"` + LuckyNumber int `json:"luckyNumber"` } -// queryWithFragmentsBeingsOwnerBeing includes the requested fields of the GraphQL interface Being. +// queryWithFragmentsBeingsBeing includes the requested fields of the GraphQL interface Being. // -// queryWithFragmentsBeingsOwnerBeing is implemented by the following types: -// queryWithFragmentsBeingsOwnerUser -// queryWithFragmentsBeingsOwnerAnimal +// queryWithFragmentsBeingsBeing is implemented by the following types: +// queryWithFragmentsBeingsUser +// queryWithFragmentsBeingsAnimal // // The GraphQL type's documentation follows. // // -type queryWithFragmentsBeingsOwnerBeing interface { - implementsGraphQLInterfacequeryWithFragmentsBeingsOwnerBeing() +type queryWithFragmentsBeingsBeing interface { + implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() // 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. @@ -152,31 +162,29 @@ type queryWithFragmentsBeingsOwnerBeing interface { GetName() string } -func (v *queryWithFragmentsBeingsOwnerUser) implementsGraphQLInterfacequeryWithFragmentsBeingsOwnerBeing() { -} +func (v *queryWithFragmentsBeingsUser) implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() {} -// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerUser) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsUser) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerUser) GetId() string { return v.Id } +// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsUser) GetId() string { return v.Id } -// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerUser) GetName() string { return v.Name } +// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsUser) GetName() string { return v.Name } -func (v *queryWithFragmentsBeingsOwnerAnimal) implementsGraphQLInterfacequeryWithFragmentsBeingsOwnerBeing() { -} +func (v *queryWithFragmentsBeingsAnimal) implementsGraphQLInterfacequeryWithFragmentsBeingsBeing() {} -// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerAnimal) GetTypename() string { return v.Typename } +// GetTypename is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsAnimal) GetTypename() string { return v.Typename } -// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerAnimal) GetId() string { return v.Id } +// GetId is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsAnimal) GetId() string { return v.Id } -// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsOwnerBeing. -func (v *queryWithFragmentsBeingsOwnerAnimal) GetName() string { return v.Name } +// GetName is a part of, and documented with, the interface queryWithFragmentsBeingsBeing. +func (v *queryWithFragmentsBeingsAnimal) GetName() string { return v.Name } -func __unmarshalqueryWithFragmentsBeingsOwnerBeing(v *queryWithFragmentsBeingsOwnerBeing, m json.RawMessage) error { +func __unmarshalqueryWithFragmentsBeingsBeing(v *queryWithFragmentsBeingsBeing, m json.RawMessage) error { if string(m) == "null" { return nil } @@ -191,32 +199,29 @@ func __unmarshalqueryWithFragmentsBeingsOwnerBeing(v *queryWithFragmentsBeingsOw switch tn.TypeName { case "User": - *v = new(queryWithFragmentsBeingsOwnerUser) + *v = new(queryWithFragmentsBeingsUser) return json.Unmarshal(m, *v) case "Animal": - *v = new(queryWithFragmentsBeingsOwnerAnimal) + *v = new(queryWithFragmentsBeingsAnimal) return json.Unmarshal(m, *v) default: return fmt.Errorf( - `Unexpected concrete type for queryWithFragmentsBeingsOwnerBeing: "%v"`, tn.TypeName) + `Unexpected concrete type for queryWithFragmentsBeingsBeing: "%v"`, tn.TypeName) } } -// queryWithFragmentsBeingsOwnerUser includes the requested fields of the GraphQL type User. -type queryWithFragmentsBeingsOwnerUser struct { - Typename string `json:"__typename"` - Id string `json:"id"` - Name string `json:"name"` - LuckyNumber int `json:"luckyNumber"` -} - // queryWithFragmentsBeingsUser includes the requested fields of the GraphQL type User. type queryWithFragmentsBeingsUser struct { - Typename string `json:"__typename"` - Id string `json:"id"` - Name string `json:"name"` - LuckyNumber int `json:"luckyNumber"` - Hair queryWithFragmentsBeingsHair `json:"hair"` + Typename string `json:"__typename"` + Id string `json:"id"` + Name string `json:"name"` + LuckyNumber int `json:"luckyNumber"` + Hair queryWithFragmentsBeingsUserHair `json:"hair"` +} + +// queryWithFragmentsBeingsUserHair includes the requested fields of the GraphQL type Hair. +type queryWithFragmentsBeingsUserHair struct { + Color string `json:"color"` } // queryWithFragmentsResponse is returned by queryWithFragments on success. diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go index de3578b5..a201c124 100644 --- a/internal/integration/integration_test.go +++ b/internal/integration/integration_test.go @@ -253,10 +253,7 @@ func TestFragments(t *testing.T) { require.Truef(t, ok, "got %T, not User", resp.Beings[0]) assert.Equal(t, "1", user.Id) assert.Equal(t, "Yours Truly", user.Name) - // TODO(benkraft): Uncomment once we fix the interface-field type-naming - // bug that's causing this to get the wrong type (because we end up - // generating two conflicting types). - // assert.Equal(t, "Black", user.Hair.Color) + assert.Equal(t, "Black", user.Hair.Color) assert.Equal(t, 17, user.LuckyNumber) // Animal has, in total, the fields: @@ -282,7 +279,7 @@ func TestFragments(t *testing.T) { assert.Equal(t, "Yours Truly", animal.Owner.GetName()) // (luckyNumber we have to cast for, again) - owner, ok := animal.Owner.(*queryWithFragmentsBeingsOwnerUser) + owner, ok := animal.Owner.(*queryWithFragmentsBeingsAnimalOwnerUser) require.Truef(t, ok, "got %T, not User", animal.Owner) assert.Equal(t, "1", owner.Id) assert.Equal(t, "Yours Truly", owner.Name)