cadvisor/vendor/github.com/SeanDolphin/bqschema/toSchema.go
Vishnu kannan de4af1288b moving deps to vendor subdirectory
Signed-off-by: Vishnu kannan <vishnuk@google.com>
2016-07-11 12:19:43 -07:00

152 lines
3.3 KiB
Go

package bqschema
import (
"errors"
"reflect"
"strings"
"time"
"google.golang.org/api/bigquery/v2"
)
var (
ArrayOfArray = errors.New("Array of Arrays not allowed")
UnknownType = errors.New("Unknown type")
NotStruct = errors.New("Can not convert non structs")
)
func ToSchema(src interface{}) (*bigquery.TableSchema, error) {
value := reflect.ValueOf(src)
t := value.Type()
schema := &bigquery.TableSchema{}
if t.Kind() == reflect.Struct {
schema.Fields = make([]*bigquery.TableFieldSchema, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
if sf.PkgPath != "" { // unexported
continue
}
v := pointerGuard(value.Field(i))
var name string
jsonTag := sf.Tag.Get("json")
switch jsonTag {
case "-":
continue
case "":
name = sf.Name
default:
name = strings.Split(jsonTag, ",")[0]
}
tfs := &bigquery.TableFieldSchema{
Mode: "required",
Name: name,
Type: "",
}
schema.Fields = append(schema.Fields, tfs)
kind := v.Kind()
t, isSimple := simpleType(kind)
if isSimple {
tfs.Type = t
} else {
switch kind {
case reflect.Struct:
tfs.Mode = "nullable"
if t, fields, err := structConversion(v.Interface()); err == nil {
tfs.Type = t
if t == "string" {
tfs.Mode = "required"
}
tfs.Fields = fields
} else {
return schema, err
}
case reflect.Array, reflect.Slice:
tfs.Mode = "repeated"
subKind := pointerGuard(v.Type().Elem()).Kind()
t, isSimple := simpleType(subKind)
if isSimple {
schema.Fields[i].Type = t
} else if subKind == reflect.Struct {
subStruct := reflect.Zero(pointerGuard(v.Type().Elem()).Type()).Interface()
if t, fields, err := structConversion(subStruct); err == nil {
schema.Fields[i].Type = t
schema.Fields[i].Fields = fields
} else {
return schema, err
}
} else {
return schema, ArrayOfArray
}
default:
return schema, UnknownType
}
}
}
} else {
return schema, NotStruct
}
return schema, nil
}
func MustToSchema(src interface{}) *bigquery.TableSchema {
schema, err := ToSchema(src)
if err != nil {
panic(err)
}
return schema
}
func simpleType(kind reflect.Kind) (string, bool) {
isSimple := true
t := ""
switch kind {
case reflect.Bool:
t = "boolean"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
t = "integer"
case reflect.Float32, reflect.Float64:
t = "float"
case reflect.String:
t = "string"
default:
isSimple = false
}
return t, isSimple
}
func structConversion(src interface{}) (string, []*bigquery.TableFieldSchema, error) {
v := reflect.ValueOf(src)
if v.Type().Name() == "Key" && strings.Contains(v.Type().PkgPath(), "appengine") {
return "string", nil, nil
} else if v.Type().ConvertibleTo(reflect.TypeOf(time.Time{})) {
return "timestamp", nil, nil
} else {
schema, err := ToSchema(src)
return "record", schema.Fields, err
}
}
func pointerGuard(i interface{}) reflect.Value {
var v reflect.Value
var ok bool
v, ok = i.(reflect.Value)
if !ok {
if t, ok := i.(reflect.Type); ok {
v = reflect.Indirect(reflect.New(t))
}
}
if v.Kind() == reflect.Ptr {
v = reflect.Indirect(reflect.New(v.Type().Elem()))
}
return v
}