diff --git a/internal/common/values.go b/internal/common/values.go index bb981aaa1fd..fd00d00b7c9 100644 --- a/internal/common/values.go +++ b/internal/common/values.go @@ -8,11 +8,6 @@ import ( "github.com/neelance/graphql-go/internal/lexer" ) -type InputMap struct { - Fields map[string]*InputValue - FieldOrder []string -} - type InputValue struct { Name string Type Type @@ -20,6 +15,17 @@ type InputValue struct { Desc string } +type InputValueList []*InputValue + +func (l InputValueList) Get(name string) *InputValue { + for _, v := range l { + if v.Name == name { + return v + } + } + return nil +} + type ValueWithLoc struct { Value interface{} Loc *errors.Location diff --git a/internal/exec/exec.go b/internal/exec/exec.go index 2533a8702d5..fabd8fb092e 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -269,12 +269,12 @@ func (b *execBuilder) makeFieldExec(typeName string, f *schema.Field, m reflect. } var argsPacker *structPacker - if len(f.Args.Fields) > 0 { + if len(f.Args) > 0 { if len(in) == 0 { return nil, fmt.Errorf("must have parameter for field arguments") } var err error - argsPacker, err = b.makeStructPacker(&f.Args, in[0]) + argsPacker, err = b.makeStructPacker(f.Args, in[0]) if err != nil { return nil, err } diff --git a/internal/exec/packer.go b/internal/exec/packer.go index cad510706e8..fc4af2adaaf 100644 --- a/internal/exec/packer.go +++ b/internal/exec/packer.go @@ -84,7 +84,7 @@ func (b *execBuilder) makeNonNullPacker(schemaType common.Type, reflectType refl }, nil case *schema.InputObject: - e, err := b.makeStructPacker(&t.InputMap, reflectType) + e, err := b.makeStructPacker(t.Values, reflectType) if err != nil { return nil, err } @@ -110,27 +110,27 @@ func (b *execBuilder) makeNonNullPacker(schemaType common.Type, reflectType refl } } -func (b *execBuilder) makeStructPacker(obj *common.InputMap, typ reflect.Type) (*structPacker, error) { +func (b *execBuilder) makeStructPacker(values common.InputValueList, typ reflect.Type) (*structPacker, error) { if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct { return nil, fmt.Errorf("expected pointer to struct, got %s", typ) } structType := typ.Elem() var fields []*structPackerField - for _, f := range obj.Fields { - fe := &structPackerField{field: f} + for _, v := range values { + fe := &structPackerField{field: v} - sf, ok := structType.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, f.Name) }) + sf, ok := structType.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, v.Name) }) if !ok { - return nil, fmt.Errorf("missing argument %q", f.Name) + return nil, fmt.Errorf("missing argument %q", v.Name) } if sf.PkgPath != "" { return nil, fmt.Errorf("field %q must be exported", sf.Name) } fe.fieldIndex = sf.Index - ft := f.Type - if f.Default != nil { + ft := v.Type + if v.Default != nil { ft, _ = unwrapNonNull(ft) ft = &common.NonNull{OfType: ft} } diff --git a/internal/query/query.go b/internal/query/query.go index cb332ae4f8f..80d3ee207e5 100644 --- a/internal/query/query.go +++ b/internal/query/query.go @@ -18,7 +18,7 @@ type Document struct { type Operation struct { Type OperationType Name string - Vars common.InputMap + Vars common.InputValueList SelSet *SelectionSet } @@ -173,12 +173,9 @@ func parseOperation(l *lexer.Lexer, opType OperationType) *Operation { } if l.Peek() == '(' { l.ConsumeToken('(') - op.Vars.Fields = make(map[string]*common.InputValue) for l.Peek() != ')' { l.ConsumeToken('$') - v := common.ParseInputValue(l) - op.Vars.Fields[v.Name] = v - op.Vars.FieldOrder = append(op.Vars.FieldOrder, v.Name) + op.Vars = append(op.Vars, common.ParseInputValue(l)) } l.ConsumeToken(')') } diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 0b6ab7dc8f4..69460a06aed 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -73,9 +73,9 @@ type EnumValue struct { } type InputObject struct { - Name string - Desc string - common.InputMap + Name string + Desc string + Values common.InputValueList } type FieldList []*Field @@ -127,7 +127,7 @@ func (t *InputObject) Description() string { return t.Desc } type Field struct { Name string - Args common.InputMap + Args common.InputValueList Type common.Type Directives map[string]common.ArgumentList Desc string @@ -245,7 +245,7 @@ func resolveNamedType(s *Schema, t NamedType) error { } } case *InputObject: - if err := resolveInputObject(s, &t.InputMap); err != nil { + if err := resolveInputObject(s, t.Values); err != nil { return err } } @@ -261,7 +261,7 @@ func resolveField(s *Schema, f *Field) error { if err := resolveDirectives(s, f.Directives); err != nil { return err } - return resolveInputObject(s, &f.Args) + return resolveInputObject(s, f.Args) } func resolveDirectives(s *Schema, directives map[string]common.ArgumentList) error { @@ -285,13 +285,13 @@ func resolveDirectives(s *Schema, directives map[string]common.ArgumentList) err return nil } -func resolveInputObject(s *Schema, io *common.InputMap) error { - for _, f := range io.Fields { - t, err := common.ResolveType(f.Type, s.Resolve) +func resolveInputObject(s *Schema, values common.InputValueList) error { + for _, v := range values { + t, err := common.ResolveType(v.Type, s.Resolve) if err != nil { return err } - f.Type = t + v.Type = t } return nil } @@ -386,13 +386,10 @@ func parseUnionDecl(l *lexer.Lexer) *Union { func parseInputDecl(l *lexer.Lexer) *InputObject { i := &InputObject{} - i.Fields = make(map[string]*common.InputValue) i.Name = l.ConsumeIdent() l.ConsumeToken('{') for l.Peek() != '}' { - v := common.ParseInputValue(l) - i.Fields[v.Name] = v - i.FieldOrder = append(i.FieldOrder, v.Name) + i.Values = append(i.Values, common.ParseInputValue(l)) } l.ConsumeToken('}') return i @@ -446,12 +443,9 @@ func parseFields(l *lexer.Lexer) FieldList { f.Desc = l.DescComment() f.Name = l.ConsumeIdent() if l.Peek() == '(' { - f.Args.Fields = make(map[string]*common.InputValue) l.ConsumeToken('(') for l.Peek() != ')' { - v := common.ParseInputValue(l) - f.Args.Fields[v.Name] = v - f.Args.FieldOrder = append(f.Args.FieldOrder, v.Name) + f.Args = append(f.Args, common.ParseInputValue(l)) } l.ConsumeToken(')') } diff --git a/introspection/introspection.go b/introspection/introspection.go index 9b89ed7c23a..f73aa1156ac 100644 --- a/introspection/introspection.go +++ b/introspection/introspection.go @@ -174,9 +174,9 @@ func (r *Type) InputFields() *[]*InputValue { return nil } - l := make([]*InputValue, len(t.FieldOrder)) - for i, name := range t.FieldOrder { - l[i] = &InputValue{t.Fields[name]} + l := make([]*InputValue, len(t.Values)) + for i, v := range t.Values { + l[i] = &InputValue{v} } return &l } @@ -208,9 +208,9 @@ func (r *Field) Description() *string { } func (r *Field) Args() []*InputValue { - l := make([]*InputValue, len(r.field.Args.FieldOrder)) - for i, name := range r.field.Args.FieldOrder { - l[i] = &InputValue{r.field.Args.Fields[name]} + l := make([]*InputValue, len(r.field.Args)) + for i, v := range r.field.Args { + l[i] = &InputValue{v} } return l }