diff --git a/internal/common/common.go b/internal/common/common.go new file mode 100644 index 00000000000..3d7fc3c65b5 --- /dev/null +++ b/internal/common/common.go @@ -0,0 +1,43 @@ +package common + +import "github.com/neelance/graphql-go/internal/lexer" + +type Type interface { + IsType() +} + +type List struct { + OfType Type +} + +type NonNull struct { + OfType Type +} + +type TypeName struct { + Name string +} + +func (*List) IsType() {} +func (*NonNull) IsType() {} +func (*TypeName) IsType() {} + +func ParseType(l *lexer.Lexer) Type { + t := parseNullType(l) + if l.Peek() == '!' { + l.ConsumeToken('!') + return &NonNull{OfType: t} + } + return t +} + +func parseNullType(l *lexer.Lexer) Type { + if l.Peek() == '[' { + l.ConsumeToken('[') + ofType := ParseType(l) + l.ConsumeToken(']') + return &List{OfType: ofType} + } + + return &TypeName{Name: l.ConsumeIdent()} +} diff --git a/internal/exec/exec.go b/internal/exec/exec.go index ff3b595445d..cc1b51b0ab6 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -10,6 +10,7 @@ import ( "sync" "github.com/neelance/graphql-go/errors" + "github.com/neelance/graphql-go/internal/common" "github.com/neelance/graphql-go/internal/query" "github.com/neelance/graphql-go/internal/schema" ) @@ -47,7 +48,7 @@ func Make(s *schema.Schema, resolver interface{}) (*Exec, error) { } type typeRefMapKey struct { - s schema.Type + s common.Type r reflect.Type } @@ -56,7 +57,7 @@ type typeRef struct { exec iExec } -func makeWithType(s *schema.Schema, t schema.Type, resolver interface{}) (iExec, error) { +func makeWithType(s *schema.Schema, t common.Type, resolver interface{}) (iExec, error) { m := make(map[typeRefMapKey]*typeRef) var e iExec if err := makeExec(&e, s, t, reflect.TypeOf(resolver), m); err != nil { @@ -72,7 +73,7 @@ func makeWithType(s *schema.Schema, t schema.Type, resolver interface{}) (iExec, return e, nil } -func makeExec(target *iExec, s *schema.Schema, t schema.Type, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRef) error { +func makeExec(target *iExec, s *schema.Schema, t common.Type, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRef) error { k := typeRefMapKey{t, resolverType} ref, ok := typeRefMap[k] if !ok { @@ -96,9 +97,9 @@ var scalarTypes = map[string]reflect.Type{ "ID": reflect.TypeOf(""), } -func makeExec2(s *schema.Schema, t schema.Type, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRef) (iExec, error) { +func makeExec2(s *schema.Schema, t common.Type, resolverType reflect.Type, typeRefMap map[typeRefMapKey]*typeRef) (iExec, error) { nonNull := false - if nn, ok := t.(*schema.NonNull); ok { + if nn, ok := t.(*common.NonNull); ok { nonNull = true t = nn.OfType } @@ -164,7 +165,7 @@ func makeExec2(s *schema.Schema, t schema.Type, resolverType reflect.Type, typeR case *schema.Enum: return &scalarExec{}, nil - case *schema.List: + case *common.List: if !nonNull { resolverType = resolverType.Elem() } @@ -506,7 +507,7 @@ type fieldExec struct { type argExec struct { name string - typ schema.Type + typ common.Type fieldIndex []int defaultVal reflect.Value } @@ -575,8 +576,8 @@ func execValue(r *request, v query.Value) interface{} { } } -func checkType(st schema.Type, rt reflect.Type) bool { - if nn, ok := st.(*schema.NonNull); ok { +func checkType(st common.Type, rt reflect.Type) bool { + if nn, ok := st.(*common.NonNull); ok { st = nn.OfType } diff --git a/internal/exec/introspection.go b/internal/exec/introspection.go index e13912742ff..9f620e5b248 100644 --- a/internal/exec/introspection.go +++ b/internal/exec/introspection.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/neelance/graphql-go/errors" + "github.com/neelance/graphql-go/internal/common" "github.com/neelance/graphql-go/internal/query" "github.com/neelance/graphql-go/internal/schema" ) @@ -249,7 +250,7 @@ func (r *schemaResolver) Directives() []*directiveResolver { } type typeResolver struct { - typ schema.Type + typ common.Type } func (r *typeResolver) Kind() string { @@ -266,9 +267,9 @@ func (r *typeResolver) Kind() string { return "ENUM" case *schema.InputObject: return "INPUT_OBJECT" - case *schema.List: + case *common.List: return "LIST" - case *schema.NonNull: + case *common.NonNull: return "NON_NULL" default: panic("unreachable") @@ -378,9 +379,9 @@ func (r *typeResolver) InputFields() *[]*inputValueResolver { func (r *typeResolver) OfType() *typeResolver { switch t := r.typ.(type) { - case *schema.List: + case *common.List: return &typeResolver{t.OfType} - case *schema.NonNull: + case *common.NonNull: return &typeResolver{t.OfType} default: return nil diff --git a/internal/query/query.go b/internal/query/query.go index af2b1836eb6..85873f33882 100644 --- a/internal/query/query.go +++ b/internal/query/query.go @@ -6,8 +6,8 @@ import ( "text/scanner" "github.com/neelance/graphql-go/errors" + "github.com/neelance/graphql-go/internal/common" "github.com/neelance/graphql-go/internal/lexer" - "github.com/neelance/graphql-go/internal/schema" ) type Document struct { @@ -31,7 +31,7 @@ const ( type VariableDef struct { Name string - Type schema.Type + Type common.Type } type NamedFragment struct { @@ -170,7 +170,7 @@ func parseVariableDef(l *lexer.Lexer) *VariableDef { l.ConsumeToken('$') v.Name = l.ConsumeIdent() l.ConsumeToken(':') - v.Type = schema.ParseType(l) + v.Type = common.ParseType(l) return v } diff --git a/internal/schema/schema.go b/internal/schema/schema.go index 2748e02ca7d..f1851a93640 100644 --- a/internal/schema/schema.go +++ b/internal/schema/schema.go @@ -6,22 +6,19 @@ import ( "text/scanner" "github.com/neelance/graphql-go/errors" + "github.com/neelance/graphql-go/internal/common" "github.com/neelance/graphql-go/internal/lexer" ) type Schema struct { - EntryPoints map[string]Type - Types map[string]Type + EntryPoints map[string]common.Type + Types map[string]common.Type entryPointNames map[string]string objects []*Object unions []*Union } -type Type interface { - isType() -} - type Scalar struct { Name string } @@ -60,38 +57,23 @@ type InputObject struct { InputFieldOrder []string } -type List struct { - OfType Type -} - -type NonNull struct { - OfType Type -} - -type typeRef struct { - name string -} - -func (*Scalar) isType() {} -func (*Object) isType() {} -func (*Interface) isType() {} -func (*Union) isType() {} -func (*Enum) isType() {} -func (*InputObject) isType() {} -func (*List) isType() {} -func (*NonNull) isType() {} -func (*typeRef) isType() {} +func (*Scalar) IsType() {} +func (*Object) IsType() {} +func (*Interface) IsType() {} +func (*Union) IsType() {} +func (*Enum) IsType() {} +func (*InputObject) IsType() {} type Field struct { Name string Args map[string]*InputValue ArgOrder []string - Type Type + Type common.Type } type InputValue struct { Name string - Type Type + Type common.Type Default interface{} } @@ -115,7 +97,7 @@ func Parse(schemaString string) (s *Schema, err *errors.GraphQLError) { } } - s.EntryPoints = make(map[string]Type) + s.EntryPoints = make(map[string]common.Type) for key, name := range s.entryPointNames { t, ok := s.Types[name] if !ok { @@ -160,7 +142,7 @@ func Parse(schemaString string) (s *Schema, err *errors.GraphQLError) { return s, nil } -func resolveType(s *Schema, t Type) *errors.GraphQLError { +func resolveType(s *Schema, t common.Type) *errors.GraphQLError { var err *errors.GraphQLError switch t := t.(type) { case *Scalar: @@ -183,18 +165,18 @@ func resolveType(s *Schema, t Type) *errors.GraphQLError { // nothing case *InputObject: for _, f := range t.InputFields { - f.Type, err = resolveTypeRef(s, f.Type) + f.Type, err = resolveTypeName(s, f.Type) if err != nil { return err } } - case *List: - t.OfType, err = resolveTypeRef(s, t.OfType) + case *common.List: + t.OfType, err = resolveTypeName(s, t.OfType) if err != nil { return err } - case *NonNull: - t.OfType, err = resolveTypeRef(s, t.OfType) + case *common.NonNull: + t.OfType, err = resolveTypeName(s, t.OfType) if err != nil { return err } @@ -206,12 +188,12 @@ func resolveType(s *Schema, t Type) *errors.GraphQLError { func resolveField(s *Schema, f *Field) *errors.GraphQLError { var err *errors.GraphQLError - f.Type, err = resolveTypeRef(s, f.Type) + f.Type, err = resolveTypeName(s, f.Type) if err != nil { return err } for _, arg := range f.Args { - arg.Type, err = resolveTypeRef(s, arg.Type) + arg.Type, err = resolveTypeName(s, arg.Type) if err != nil { return err } @@ -219,11 +201,11 @@ func resolveField(s *Schema, f *Field) *errors.GraphQLError { return nil } -func resolveTypeRef(s *Schema, t Type) (Type, *errors.GraphQLError) { - if ref, ok := t.(*typeRef); ok { - refT, ok := s.Types[ref.name] +func resolveTypeName(s *Schema, t common.Type) (common.Type, *errors.GraphQLError) { + if name, ok := t.(*common.TypeName); ok { + refT, ok := s.Types[name.Name] if !ok { - return nil, errors.Errorf("type %q not found", ref.name) + return nil, errors.Errorf("type %q not found", name.Name) } return refT, nil } @@ -234,7 +216,7 @@ func resolveTypeRef(s *Schema, t Type) (Type, *errors.GraphQLError) { func parseSchema(l *lexer.Lexer) *Schema { s := &Schema{ entryPointNames: make(map[string]string), - Types: map[string]Type{ + Types: map[string]common.Type{ "Int": &Scalar{Name: "Int"}, "Float": &Scalar{Name: "Float"}, "String": &Scalar{Name: "String"}, @@ -361,7 +343,7 @@ func parseFields(l *lexer.Lexer) (map[string]*Field, []string) { l.ConsumeToken(')') } l.ConsumeToken(':') - f.Type = ParseType(l) + f.Type = common.ParseType(l) fields[f.Name] = f fieldOrder = append(fieldOrder, f.Name) } @@ -372,7 +354,7 @@ func parseInputValue(l *lexer.Lexer) *InputValue { p := &InputValue{} p.Name = l.ConsumeIdent() l.ConsumeToken(':') - p.Type = ParseType(l) + p.Type = common.ParseType(l) if l.Peek() == '=' { l.ConsumeToken('=') p.Default = parseValue(l) @@ -380,26 +362,6 @@ func parseInputValue(l *lexer.Lexer) *InputValue { return p } -func ParseType(l *lexer.Lexer) Type { - t := parseNullType(l) - if l.Peek() == '!' { - l.ConsumeToken('!') - return &NonNull{OfType: t} - } - return t -} - -func parseNullType(l *lexer.Lexer) Type { - if l.Peek() == '[' { - l.ConsumeToken('[') - ofType := ParseType(l) - l.ConsumeToken(']') - return &List{OfType: ofType} - } - - return &typeRef{name: l.ConsumeIdent()} -} - func parseValue(l *lexer.Lexer) interface{} { switch l.Peek() { case scanner.Int: