diff options
Diffstat (limited to 'vendor/github.com/graphql-go/graphql/util.go')
-rw-r--r-- | vendor/github.com/graphql-go/graphql/util.go | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/vendor/github.com/graphql-go/graphql/util.go b/vendor/github.com/graphql-go/graphql/util.go new file mode 100644 index 00000000..dd4f370e --- /dev/null +++ b/vendor/github.com/graphql-go/graphql/util.go @@ -0,0 +1,180 @@ +package graphql + +import ( + "fmt" + "reflect" + "strings" +) + +const TAG = "json" + +// can't take recursive slice type +// e.g +// type Person struct{ +// Friends []Person +// } +// it will throw panic stack-overflow +func BindFields(obj interface{}) Fields { + v := reflect.ValueOf(obj) + fields := make(map[string]*Field) + + for i := 0; i < v.NumField(); i++ { + typeField := v.Type().Field(i) + + tag := extractTag(typeField.Tag) + if tag == "-" { + continue + } + + var graphType Output + if typeField.Type.Kind() == reflect.Struct { + + structFields := BindFields(v.Field(i).Interface()) + if tag == "" { + fields = appendFields(fields, structFields) + continue + } else { + graphType = NewObject(ObjectConfig{ + Name: tag, + Fields: structFields, + }) + } + } + + if tag == "" { + continue + } + + if graphType == nil { + graphType = getGraphType(typeField.Type) + } + fields[tag] = &Field{ + Type: graphType, + Resolve: func(p ResolveParams) (interface{}, error) { + return extractValue(tag, p.Source), nil + }, + } + } + return fields +} + +func getGraphType(tipe reflect.Type) Output { + kind := tipe.Kind() + switch kind { + case reflect.String: + return String + case reflect.Int: + fallthrough + case reflect.Int8: + fallthrough + case reflect.Int32: + fallthrough + case reflect.Int64: + return Int + case reflect.Float32: + fallthrough + case reflect.Float64: + return Float + case reflect.Bool: + return Boolean + case reflect.Slice: + return getGraphList(tipe) + } + return String +} + +func getGraphList(tipe reflect.Type) *List { + if tipe.Kind() == reflect.Slice { + switch tipe.Elem().Kind() { + case reflect.Int: + fallthrough + case reflect.Int8: + fallthrough + case reflect.Int32: + fallthrough + case reflect.Int64: + return NewList(Int) + case reflect.Bool: + return NewList(Boolean) + case reflect.Float32: + fallthrough + case reflect.Float64: + return NewList(Float) + case reflect.String: + return NewList(String) + } + } + // finaly bind object + t := reflect.New(tipe.Elem()) + name := strings.Replace(fmt.Sprint(tipe.Elem()), ".", "_", -1) + obj := NewObject(ObjectConfig{ + Name: name, + Fields: BindFields(t.Elem().Interface()), + }) + return NewList(obj) +} + +func appendFields(dest, origin Fields) Fields { + for key, value := range origin { + dest[key] = value + } + return dest +} + +func extractValue(originTag string, obj interface{}) interface{} { + val := reflect.ValueOf(obj) + + for j := 0; j < val.NumField(); j++ { + typeField := val.Type().Field(j) + if typeField.Type.Kind() == reflect.Struct { + res := extractValue(originTag, val.Field(j).Interface()) + if res != nil { + return res + } + } + + if originTag == extractTag(typeField.Tag) { + return val.Field(j).Interface() + } + } + return nil +} + +func extractTag(tag reflect.StructTag) string { + t := tag.Get(TAG) + if t != "" { + t = strings.Split(t, ",")[0] + } + return t +} + +// lazy way of binding args +func BindArg(obj interface{}, tags ...string) FieldConfigArgument { + v := reflect.ValueOf(obj) + var config = make(FieldConfigArgument) + for i := 0; i < v.NumField(); i++ { + typeField := v.Type().Field(i) + + mytag := extractTag(typeField.Tag) + if inArray(tags, mytag) { + config[mytag] = &ArgumentConfig{ + Type: getGraphType(typeField.Type), + } + } + } + return config +} + +func inArray(slice interface{}, item interface{}) bool { + s := reflect.ValueOf(slice) + if s.Kind() != reflect.Slice { + panic("inArray() given a non-slice type") + } + + for i := 0; i < s.Len(); i++ { + if reflect.DeepEqual(item, s.Index(i).Interface()) { + return true + } + } + return false +} |