diff options
author | Michael Muré <batolettre@gmail.com> | 2018-09-14 12:40:31 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2018-09-14 12:41:59 +0200 |
commit | b478cd1bcb4756b20f7f4b15fcf81f23e1a60a02 (patch) | |
tree | 8ce232dcab3dd00708f8ba66c334472457e5980d /vendor/github.com/vektah/gqlparser/validator/vars.go | |
parent | a3fc9abb921f5ce7084d6ab7473442d0b72b1d78 (diff) | |
download | git-bug-b478cd1bcb4756b20f7f4b15fcf81f23e1a60a02.tar.gz |
graphql: update gqlgen to 0.5.1
fix #6
Diffstat (limited to 'vendor/github.com/vektah/gqlparser/validator/vars.go')
-rw-r--r-- | vendor/github.com/vektah/gqlparser/validator/vars.go | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/github.com/vektah/gqlparser/validator/vars.go b/vendor/github.com/vektah/gqlparser/validator/vars.go new file mode 100644 index 00000000..0743f5cc --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/validator/vars.go @@ -0,0 +1,195 @@ +package validator + +import ( + "reflect" + + "fmt" + + "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/gqlerror" +) + +var UnexpectedType = fmt.Errorf("Unexpected Type") + +// VariableValues coerces and validates variable values +func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, *gqlerror.Error) { + coercedVars := map[string]interface{}{} + + validator := varValidator{ + path: []interface{}{"variable"}, + schema: schema, + } + + for _, v := range op.VariableDefinitions { + validator.path = append(validator.path, v.Variable) + + if !v.Definition.IsInputType() { + return nil, gqlerror.ErrorPathf(validator.path, "must an input type") + } + + val, hasValue := variables[v.Variable] + if !hasValue { + if v.DefaultValue != nil { + var err error + val, err = v.DefaultValue.Value(nil) + if err != nil { + return nil, gqlerror.WrapPath(validator.path, err) + } + hasValue = true + } else if v.Type.NonNull { + return nil, gqlerror.ErrorPathf(validator.path, "must be defined") + } + } + + if hasValue { + if val == nil { + if v.Type.NonNull { + return nil, gqlerror.ErrorPathf(validator.path, "cannot be null") + } + coercedVars[v.Variable] = nil + } else { + rv := reflect.ValueOf(val) + if rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface { + rv = rv.Elem() + } + + if err := validator.validateVarType(v.Type, rv); err != nil { + return nil, err + } + + coercedVars[v.Variable] = val + } + } + + validator.path = validator.path[0 : len(validator.path)-1] + } + + return coercedVars, nil +} + +type varValidator struct { + path []interface{} + schema *ast.Schema +} + +func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerror.Error { + if typ.Elem != nil { + if val.Kind() != reflect.Slice { + return gqlerror.ErrorPathf(v.path, "must be an array") + } + + for i := 0; i < val.Len(); i++ { + v.path = append(v.path, i) + field := val.Index(i) + + if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { + if typ.Elem.NonNull && field.IsNil() { + return gqlerror.ErrorPathf(v.path, "cannot be null") + } + field = field.Elem() + } + + if err := v.validateVarType(typ.Elem, field); err != nil { + return err + } + + v.path = v.path[0 : len(v.path)-1] + } + + return nil + } + + def := v.schema.Types[typ.NamedType] + if def == nil { + panic(fmt.Errorf("missing def for %s", typ.NamedType)) + } + + switch def.Kind { + case ast.Enum: + kind := val.Type().Kind() + if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String { + return nil + } + return gqlerror.ErrorPathf(v.path, "enums must be ints or strings") + case ast.Scalar: + kind := val.Type().Kind() + switch typ.NamedType { + case "Int": + if kind == reflect.String || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 { + return nil + } + case "Float": + if kind == reflect.String || kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 { + return nil + } + case "String": + if kind == reflect.String { + return nil + } + + case "Boolean": + if kind == reflect.Bool { + return nil + } + + case "ID": + if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String { + return nil + } + default: + // assume custom scalars are ok + return nil + } + return gqlerror.ErrorPathf(v.path, "cannot use %s as %s", kind.String(), typ.NamedType) + case ast.InputObject: + if val.Kind() != reflect.Map { + return gqlerror.ErrorPathf(v.path, "must be a %s", def.Name) + } + + // check for unknown fields + for _, name := range val.MapKeys() { + val.MapIndex(name) + fieldDef := def.Fields.ForName(name.String()) + v.path = append(v.path, name) + + if fieldDef == nil { + return gqlerror.ErrorPathf(v.path, "unknown field") + } + v.path = v.path[0 : len(v.path)-1] + } + + for _, fieldDef := range def.Fields { + v.path = append(v.path, fieldDef.Name) + + field := val.MapIndex(reflect.ValueOf(fieldDef.Name)) + if !field.IsValid() { + if fieldDef.Type.NonNull { + return gqlerror.ErrorPathf(v.path, "must be defined") + } + continue + } + + if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { + if fieldDef.Type.NonNull && field.IsNil() { + return gqlerror.ErrorPathf(v.path, "cannot be null") + } + //allow null object field and skip it + if !fieldDef.Type.NonNull && field.IsNil() { + continue + } + field = field.Elem() + } + + err := v.validateVarType(fieldDef.Type, field) + if err != nil { + return err + } + + v.path = v.path[0 : len(v.path)-1] + } + default: + panic(fmt.Errorf("unsupported type %s", def.Kind)) + } + + return nil +} |