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 e1f106cb..3faa2906 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) - - 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, @@ -143,14 +105,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, queryOptions) + namePrefix, def, typ.Position, selectionSet, queryOptions) if options.GetPointer() { // Whatever we get, wrap it in a pointer. (Because of the way the @@ -168,7 +130,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, @@ -186,6 +148,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 { @@ -203,6 +167,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, @@ -222,7 +192,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 } @@ -238,6 +208,8 @@ func (g *generator) convertDefinition( return goType, nil case ast.Interface, ast.Union: + name := makeTypeName(namePrefix, def.Name) + if !g.Config.AllowBrokenFeatures { return nil, errorf(pos, "not implemented: %v", def.Kind) } @@ -269,14 +241,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, queryOptions) + namePrefix, implDef, pos, selectionSet, queryOptions) if err != nil { return nil, err } @@ -292,6 +264,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, @@ -324,7 +300,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, @@ -443,7 +419,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, @@ -465,7 +441,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) { @@ -476,24 +452,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 c07b8149..9d075c2e 100644 --- a/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go +++ b/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go @@ -21,6 +21,20 @@ 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"` +} + // unexportedResponse is returned by unexported on success. type unexportedResponse struct { // user looks up a user by some stuff. @@ -41,23 +55,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"` -} - 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)