|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521 |
- // Copyright 2014 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package datastore
-
- import (
- "fmt"
- "reflect"
- "strings"
- "time"
-
- "cloud.google.com/go/internal/fields"
- pb "google.golang.org/genproto/googleapis/datastore/v1"
- )
-
- var (
- typeOfByteSlice = reflect.TypeOf([]byte(nil))
- typeOfTime = reflect.TypeOf(time.Time{})
- typeOfGeoPoint = reflect.TypeOf(GeoPoint{})
- typeOfKeyPtr = reflect.TypeOf(&Key{})
- )
-
- // typeMismatchReason returns a string explaining why the property p could not
- // be stored in an entity field of type v.Type().
- func typeMismatchReason(p Property, v reflect.Value) string {
- entityType := "empty"
- switch p.Value.(type) {
- case int64:
- entityType = "int"
- case bool:
- entityType = "bool"
- case string:
- entityType = "string"
- case float64:
- entityType = "float"
- case *Key:
- entityType = "*datastore.Key"
- case *Entity:
- entityType = "*datastore.Entity"
- case GeoPoint:
- entityType = "GeoPoint"
- case time.Time:
- entityType = "time.Time"
- case []byte:
- entityType = "[]byte"
- }
-
- return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type())
- }
-
- func overflowReason(x interface{}, v reflect.Value) string {
- return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type())
- }
-
- type propertyLoader struct {
- // m holds the number of times a substruct field like "Foo.Bar.Baz" has
- // been seen so far. The map is constructed lazily.
- m map[string]int
- }
-
- func (l *propertyLoader) load(codec fields.List, structValue reflect.Value, p Property, prev map[string]struct{}) string {
- sl, ok := p.Value.([]interface{})
- if !ok {
- return l.loadOneElement(codec, structValue, p, prev)
- }
- for _, val := range sl {
- p.Value = val
- if errStr := l.loadOneElement(codec, structValue, p, prev); errStr != "" {
- return errStr
- }
- }
- return ""
- }
-
- // loadOneElement loads the value of Property p into structValue based on the provided
- // codec. codec is used to find the field in structValue into which p should be loaded.
- // prev is the set of property names already seen for structValue.
- func (l *propertyLoader) loadOneElement(codec fields.List, structValue reflect.Value, p Property, prev map[string]struct{}) string {
- var sliceOk bool
- var sliceIndex int
- var v reflect.Value
-
- name := p.Name
- fieldNames := strings.Split(name, ".")
-
- for len(fieldNames) > 0 {
- var field *fields.Field
-
- // Start by trying to find a field with name. If none found,
- // cut off the last field (delimited by ".") and find its parent
- // in the codec.
- // eg. for name "A.B.C.D", split off "A.B.C" and try to
- // find a field in the codec with this name.
- // Loop again with "A.B", etc.
- for i := len(fieldNames); i > 0; i-- {
- parent := strings.Join(fieldNames[:i], ".")
- field = codec.Match(parent)
- if field != nil {
- fieldNames = fieldNames[i:]
- break
- }
- }
-
- // If we never found a matching field in the codec, return
- // error message.
- if field == nil {
- return "no such struct field"
- }
-
- v = initField(structValue, field.Index)
- if !v.IsValid() {
- return "no such struct field"
- }
- if !v.CanSet() {
- return "cannot set struct field"
- }
-
- // If field implements PLS, we delegate loading to the PLS's Load early,
- // and stop iterating through fields.
- ok, err := plsFieldLoad(v, p, fieldNames)
- if err != nil {
- return err.Error()
- }
- if ok {
- return ""
- }
-
- if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
- codec, err = structCache.Fields(field.Type.Elem())
- if err != nil {
- return err.Error()
- }
-
- // Init value if its nil
- if v.IsNil() {
- v.Set(reflect.New(field.Type.Elem()))
- }
- structValue = v.Elem()
- }
-
- if field.Type.Kind() == reflect.Struct {
- codec, err = structCache.Fields(field.Type)
- if err != nil {
- return err.Error()
- }
- structValue = v
- }
-
- // If the element is a slice, we need to accommodate it.
- if v.Kind() == reflect.Slice && v.Type() != typeOfByteSlice {
- if l.m == nil {
- l.m = make(map[string]int)
- }
- sliceIndex = l.m[p.Name]
- l.m[p.Name] = sliceIndex + 1
- for v.Len() <= sliceIndex {
- v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem()))
- }
- structValue = v.Index(sliceIndex)
-
- // If structValue implements PLS, we delegate loading to the PLS's
- // Load early, and stop iterating through fields.
- ok, err := plsFieldLoad(structValue, p, fieldNames)
- if err != nil {
- return err.Error()
- }
- if ok {
- return ""
- }
-
- if structValue.Type().Kind() == reflect.Struct {
- codec, err = structCache.Fields(structValue.Type())
- if err != nil {
- return err.Error()
- }
- }
- sliceOk = true
- }
- }
-
- var slice reflect.Value
- if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
- slice = v
- v = reflect.New(v.Type().Elem()).Elem()
- } else if _, ok := prev[p.Name]; ok && !sliceOk {
- // Zero the field back out that was set previously, turns out
- // it's a slice and we don't know what to do with it
- v.Set(reflect.Zero(v.Type()))
- return "multiple-valued property requires a slice field type"
- }
-
- prev[p.Name] = struct{}{}
-
- if errReason := setVal(v, p); errReason != "" {
- // Set the slice back to its zero value.
- if slice.IsValid() {
- slice.Set(reflect.Zero(slice.Type()))
- }
- return errReason
- }
-
- if slice.IsValid() {
- slice.Index(sliceIndex).Set(v)
- }
-
- return ""
- }
-
- // plsFieldLoad first tries to converts v's value to a PLS, then v's addressed
- // value to a PLS. If neither succeeds, plsFieldLoad returns false for first return
- // value. Otherwise, the first return value will be true.
- // If v is successfully converted to a PLS, plsFieldLoad will then try to Load
- // the property p into v (by way of the PLS's Load method).
- //
- // If the field v has been flattened, the Property's name must be altered
- // before calling Load to reflect the field v.
- // For example, if our original field name was "A.B.C.D",
- // and at this point in iteration we had initialized the field
- // corresponding to "A" and have moved into the struct, so that now
- // v corresponds to the field named "B", then we want to let the
- // PLS handle this field (B)'s subfields ("C", "D"),
- // so we send the property to the PLS's Load, renamed to "C.D".
- //
- // If subfields are present, the field v has been flattened.
- func plsFieldLoad(v reflect.Value, p Property, subfields []string) (ok bool, err error) {
- vpls, err := plsForLoad(v)
- if err != nil {
- return false, err
- }
-
- if vpls == nil {
- return false, nil
- }
-
- // If Entity, load properties as well as key.
- if e, ok := p.Value.(*Entity); ok {
- err = loadEntity(vpls, e)
- return true, err
- }
-
- // If flattened, we must alter the property's name to reflect
- // the field v.
- if len(subfields) > 0 {
- p.Name = strings.Join(subfields, ".")
- }
-
- return true, vpls.Load([]Property{p})
- }
-
- // setVal sets 'v' to the value of the Property 'p'.
- func setVal(v reflect.Value, p Property) (s string) {
- pValue := p.Value
- switch v.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- x, ok := pValue.(int64)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- if v.OverflowInt(x) {
- return overflowReason(x, v)
- }
- v.SetInt(x)
- case reflect.Bool:
- x, ok := pValue.(bool)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- v.SetBool(x)
- case reflect.String:
- x, ok := pValue.(string)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- v.SetString(x)
- case reflect.Float32, reflect.Float64:
- x, ok := pValue.(float64)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- if v.OverflowFloat(x) {
- return overflowReason(x, v)
- }
- v.SetFloat(x)
- case reflect.Ptr:
- // v must be a pointer to either a Key, an Entity, or one of the supported basic types.
- if v.Type() != typeOfKeyPtr && v.Type().Elem().Kind() != reflect.Struct && !isValidPointerType(v.Type().Elem()) {
- return typeMismatchReason(p, v)
- }
-
- if pValue == nil {
- // If v is populated already, set it to nil.
- if !v.IsNil() {
- v.Set(reflect.New(v.Type()).Elem())
- }
- return ""
- }
-
- if x, ok := p.Value.(*Key); ok {
- if _, ok := v.Interface().(*Key); !ok {
- return typeMismatchReason(p, v)
- }
- v.Set(reflect.ValueOf(x))
- return ""
- }
- if v.IsNil() {
- v.Set(reflect.New(v.Type().Elem()))
- }
- switch x := pValue.(type) {
- case *Entity:
- err := loadEntity(v.Interface(), x)
- if err != nil {
- return err.Error()
- }
- case int64:
- if v.Elem().OverflowInt(x) {
- return overflowReason(x, v.Elem())
- }
- v.Elem().SetInt(x)
- case float64:
- if v.Elem().OverflowFloat(x) {
- return overflowReason(x, v.Elem())
- }
- v.Elem().SetFloat(x)
- case bool:
- v.Elem().SetBool(x)
- case string:
- v.Elem().SetString(x)
- case GeoPoint, time.Time:
- v.Elem().Set(reflect.ValueOf(x))
- default:
- return typeMismatchReason(p, v)
- }
- case reflect.Struct:
- switch v.Type() {
- case typeOfTime:
- x, ok := pValue.(time.Time)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- v.Set(reflect.ValueOf(x))
- case typeOfGeoPoint:
- x, ok := pValue.(GeoPoint)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- v.Set(reflect.ValueOf(x))
- default:
- ent, ok := pValue.(*Entity)
- if !ok {
- return typeMismatchReason(p, v)
- }
- err := loadEntity(v.Addr().Interface(), ent)
- if err != nil {
- return err.Error()
- }
- }
- case reflect.Slice:
- x, ok := pValue.([]byte)
- if !ok && pValue != nil {
- return typeMismatchReason(p, v)
- }
- if v.Type().Elem().Kind() != reflect.Uint8 {
- return typeMismatchReason(p, v)
- }
- v.SetBytes(x)
- default:
- return typeMismatchReason(p, v)
- }
- return ""
- }
-
- // initField is similar to reflect's Value.FieldByIndex, in that it
- // returns the nested struct field corresponding to index, but it
- // initialises any nil pointers encountered when traversing the structure.
- func initField(val reflect.Value, index []int) reflect.Value {
- for _, i := range index[:len(index)-1] {
- val = val.Field(i)
- if val.Kind() == reflect.Ptr {
- if val.IsNil() {
- val.Set(reflect.New(val.Type().Elem()))
- }
- val = val.Elem()
- }
- }
- return val.Field(index[len(index)-1])
- }
-
- // loadEntityProto loads an EntityProto into PropertyLoadSaver or struct pointer.
- func loadEntityProto(dst interface{}, src *pb.Entity) error {
- ent, err := protoToEntity(src)
- if err != nil {
- return err
- }
- return loadEntity(dst, ent)
- }
-
- func loadEntity(dst interface{}, ent *Entity) error {
- if pls, ok := dst.(PropertyLoadSaver); ok {
- err := pls.Load(ent.Properties)
- if err != nil {
- return err
- }
- if e, ok := dst.(KeyLoader); ok {
- err = e.LoadKey(ent.Key)
- }
- return err
- }
- return loadEntityToStruct(dst, ent)
- }
-
- func loadEntityToStruct(dst interface{}, ent *Entity) error {
- pls, err := newStructPLS(dst)
- if err != nil {
- return err
- }
-
- // Try and load key.
- keyField := pls.codec.Match(keyFieldName)
- if keyField != nil && ent.Key != nil {
- pls.v.FieldByIndex(keyField.Index).Set(reflect.ValueOf(ent.Key))
- }
-
- // Load properties.
- return pls.Load(ent.Properties)
- }
-
- func (s structPLS) Load(props []Property) error {
- var fieldName, errReason string
- var l propertyLoader
-
- prev := make(map[string]struct{})
- for _, p := range props {
- if errStr := l.load(s.codec, s.v, p, prev); errStr != "" {
- // We don't return early, as we try to load as many properties as possible.
- // It is valid to load an entity into a struct that cannot fully represent it.
- // That case returns an error, but the caller is free to ignore it.
- fieldName, errReason = p.Name, errStr
- }
- }
- if errReason != "" {
- return &ErrFieldMismatch{
- StructType: s.v.Type(),
- FieldName: fieldName,
- Reason: errReason,
- }
- }
- return nil
- }
-
- func protoToEntity(src *pb.Entity) (*Entity, error) {
- props := make([]Property, 0, len(src.Properties))
- for name, val := range src.Properties {
- v, err := propToValue(val)
- if err != nil {
- return nil, err
- }
- props = append(props, Property{
- Name: name,
- Value: v,
- NoIndex: val.ExcludeFromIndexes,
- })
- }
- var key *Key
- if src.Key != nil {
- // Ignore any error, since nested entity values
- // are allowed to have an invalid key.
- key, _ = protoToKey(src.Key)
- }
-
- return &Entity{key, props}, nil
- }
-
- // propToValue returns a Go value that represents the PropertyValue. For
- // example, a TimestampValue becomes a time.Time.
- func propToValue(v *pb.Value) (interface{}, error) {
- switch v := v.ValueType.(type) {
- case *pb.Value_NullValue:
- return nil, nil
- case *pb.Value_BooleanValue:
- return v.BooleanValue, nil
- case *pb.Value_IntegerValue:
- return v.IntegerValue, nil
- case *pb.Value_DoubleValue:
- return v.DoubleValue, nil
- case *pb.Value_TimestampValue:
- return time.Unix(v.TimestampValue.Seconds, int64(v.TimestampValue.Nanos)), nil
- case *pb.Value_KeyValue:
- return protoToKey(v.KeyValue)
- case *pb.Value_StringValue:
- return v.StringValue, nil
- case *pb.Value_BlobValue:
- return []byte(v.BlobValue), nil
- case *pb.Value_GeoPointValue:
- return GeoPoint{Lat: v.GeoPointValue.Latitude, Lng: v.GeoPointValue.Longitude}, nil
- case *pb.Value_EntityValue:
- return protoToEntity(v.EntityValue)
- case *pb.Value_ArrayValue:
- arr := make([]interface{}, 0, len(v.ArrayValue.Values))
- for _, v := range v.ArrayValue.Values {
- vv, err := propToValue(v)
- if err != nil {
- return nil, err
- }
- arr = append(arr, vv)
- }
- return arr, nil
- default:
- return nil, nil
- }
- }
|