github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/datastore/load.go (about) 1 // Copyright 2011 Google Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 package datastore 6 7 import ( 8 "fmt" 9 "reflect" 10 "time" 11 12 "google.golang.org/appengine" 13 pb "google.golang.org/appengine/internal/datastore" 14 ) 15 16 var ( 17 typeOfBlobKey = reflect.TypeOf(appengine.BlobKey("")) 18 typeOfByteSlice = reflect.TypeOf([]byte(nil)) 19 typeOfByteString = reflect.TypeOf(ByteString(nil)) 20 typeOfGeoPoint = reflect.TypeOf(appengine.GeoPoint{}) 21 typeOfTime = reflect.TypeOf(time.Time{}) 22 ) 23 24 // typeMismatchReason returns a string explaining why the property p could not 25 // be stored in an entity field of type v.Type(). 26 func typeMismatchReason(p Property, v reflect.Value) string { 27 entityType := "empty" 28 switch p.Value.(type) { 29 case int64: 30 entityType = "int" 31 case bool: 32 entityType = "bool" 33 case string: 34 entityType = "string" 35 case float64: 36 entityType = "float" 37 case *Key: 38 entityType = "*datastore.Key" 39 case time.Time: 40 entityType = "time.Time" 41 case appengine.BlobKey: 42 entityType = "appengine.BlobKey" 43 case appengine.GeoPoint: 44 entityType = "appengine.GeoPoint" 45 case ByteString: 46 entityType = "datastore.ByteString" 47 case []byte: 48 entityType = "[]byte" 49 } 50 return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) 51 } 52 53 type propertyLoader struct { 54 // m holds the number of times a substruct field like "Foo.Bar.Baz" has 55 // been seen so far. The map is constructed lazily. 56 m map[string]int 57 } 58 59 func (l *propertyLoader) load(codec *structCodec, structValue reflect.Value, p Property, requireSlice bool) string { 60 var v reflect.Value 61 // Traverse a struct's struct-typed fields. 62 for name := p.Name; ; { 63 decoder, ok := codec.byName[name] 64 if !ok { 65 return "no such struct field" 66 } 67 v = structValue.Field(decoder.index) 68 if !v.IsValid() { 69 return "no such struct field" 70 } 71 if !v.CanSet() { 72 return "cannot set struct field" 73 } 74 75 if decoder.substructCodec == nil { 76 break 77 } 78 79 if v.Kind() == reflect.Slice { 80 if l.m == nil { 81 l.m = make(map[string]int) 82 } 83 index := l.m[p.Name] 84 l.m[p.Name] = index + 1 85 for v.Len() <= index { 86 v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem())) 87 } 88 structValue = v.Index(index) 89 requireSlice = false 90 } else { 91 structValue = v 92 } 93 // Strip the "I." from "I.X". 94 name = name[len(codec.byIndex[decoder.index].name):] 95 codec = decoder.substructCodec 96 } 97 98 var slice reflect.Value 99 if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { 100 slice = v 101 v = reflect.New(v.Type().Elem()).Elem() 102 } else if requireSlice { 103 return "multiple-valued property requires a slice field type" 104 } 105 106 // Convert indexValues to a Go value with a meaning derived from the 107 // destination type. 108 pValue := p.Value 109 if iv, ok := pValue.(indexValue); ok { 110 meaning := pb.Property_NO_MEANING 111 switch v.Type() { 112 case typeOfBlobKey: 113 meaning = pb.Property_BLOBKEY 114 case typeOfByteSlice: 115 meaning = pb.Property_BLOB 116 case typeOfByteString: 117 meaning = pb.Property_BYTESTRING 118 case typeOfGeoPoint: 119 meaning = pb.Property_GEORSS_POINT 120 case typeOfTime: 121 meaning = pb.Property_GD_WHEN 122 } 123 var err error 124 pValue, err = propValue(iv.value, meaning) 125 if err != nil { 126 return err.Error() 127 } 128 } 129 130 switch v.Kind() { 131 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 132 x, ok := pValue.(int64) 133 if !ok && pValue != nil { 134 return typeMismatchReason(p, v) 135 } 136 if v.OverflowInt(x) { 137 return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) 138 } 139 v.SetInt(x) 140 case reflect.Bool: 141 x, ok := pValue.(bool) 142 if !ok && pValue != nil { 143 return typeMismatchReason(p, v) 144 } 145 v.SetBool(x) 146 case reflect.String: 147 switch x := pValue.(type) { 148 case appengine.BlobKey: 149 v.SetString(string(x)) 150 case ByteString: 151 v.SetString(string(x)) 152 case string: 153 v.SetString(x) 154 default: 155 if pValue != nil { 156 return typeMismatchReason(p, v) 157 } 158 } 159 case reflect.Float32, reflect.Float64: 160 x, ok := pValue.(float64) 161 if !ok && pValue != nil { 162 return typeMismatchReason(p, v) 163 } 164 if v.OverflowFloat(x) { 165 return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) 166 } 167 v.SetFloat(x) 168 case reflect.Ptr: 169 x, ok := pValue.(*Key) 170 if !ok && pValue != nil { 171 return typeMismatchReason(p, v) 172 } 173 if _, ok := v.Interface().(*Key); !ok { 174 return typeMismatchReason(p, v) 175 } 176 v.Set(reflect.ValueOf(x)) 177 case reflect.Struct: 178 switch v.Type() { 179 case typeOfTime: 180 x, ok := pValue.(time.Time) 181 if !ok && pValue != nil { 182 return typeMismatchReason(p, v) 183 } 184 v.Set(reflect.ValueOf(x)) 185 case typeOfGeoPoint: 186 x, ok := pValue.(appengine.GeoPoint) 187 if !ok && pValue != nil { 188 return typeMismatchReason(p, v) 189 } 190 v.Set(reflect.ValueOf(x)) 191 default: 192 return typeMismatchReason(p, v) 193 } 194 case reflect.Slice: 195 x, ok := pValue.([]byte) 196 if !ok { 197 if y, yok := pValue.(ByteString); yok { 198 x, ok = []byte(y), true 199 } 200 } 201 if !ok && pValue != nil { 202 return typeMismatchReason(p, v) 203 } 204 if v.Type().Elem().Kind() != reflect.Uint8 { 205 return typeMismatchReason(p, v) 206 } 207 v.SetBytes(x) 208 default: 209 return typeMismatchReason(p, v) 210 } 211 if slice.IsValid() { 212 slice.Set(reflect.Append(slice, v)) 213 } 214 return "" 215 } 216 217 // loadEntity loads an EntityProto into PropertyLoadSaver or struct pointer. 218 func loadEntity(dst interface{}, src *pb.EntityProto) (err error) { 219 props, err := protoToProperties(src) 220 if err != nil { 221 return err 222 } 223 if e, ok := dst.(PropertyLoadSaver); ok { 224 return e.Load(props) 225 } 226 return LoadStruct(dst, props) 227 } 228 229 func (s structPLS) Load(props []Property) error { 230 var fieldName, reason string 231 var l propertyLoader 232 for _, p := range props { 233 if errStr := l.load(s.codec, s.v, p, p.Multiple); errStr != "" { 234 // We don't return early, as we try to load as many properties as possible. 235 // It is valid to load an entity into a struct that cannot fully represent it. 236 // That case returns an error, but the caller is free to ignore it. 237 fieldName, reason = p.Name, errStr 238 } 239 } 240 if reason != "" { 241 return &ErrFieldMismatch{ 242 StructType: s.v.Type(), 243 FieldName: fieldName, 244 Reason: reason, 245 } 246 } 247 return nil 248 } 249 250 func protoToProperties(src *pb.EntityProto) ([]Property, error) { 251 props, rawProps := src.Property, src.RawProperty 252 out := make([]Property, 0, len(props)+len(rawProps)) 253 for { 254 var ( 255 x *pb.Property 256 noIndex bool 257 ) 258 if len(props) > 0 { 259 x, props = props[0], props[1:] 260 } else if len(rawProps) > 0 { 261 x, rawProps = rawProps[0], rawProps[1:] 262 noIndex = true 263 } else { 264 break 265 } 266 267 var value interface{} 268 if x.Meaning != nil && *x.Meaning == pb.Property_INDEX_VALUE { 269 value = indexValue{x.Value} 270 } else { 271 var err error 272 value, err = propValue(x.Value, x.GetMeaning()) 273 if err != nil { 274 return nil, err 275 } 276 } 277 out = append(out, Property{ 278 Name: x.GetName(), 279 Value: value, 280 NoIndex: noIndex, 281 Multiple: x.GetMultiple(), 282 }) 283 } 284 return out, nil 285 } 286 287 // propValue returns a Go value that combines the raw PropertyValue with a 288 // meaning. For example, an Int64Value with GD_WHEN becomes a time.Time. 289 func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) { 290 switch { 291 case v.Int64Value != nil: 292 if m == pb.Property_GD_WHEN { 293 return fromUnixMicro(*v.Int64Value), nil 294 } else { 295 return *v.Int64Value, nil 296 } 297 case v.BooleanValue != nil: 298 return *v.BooleanValue, nil 299 case v.StringValue != nil: 300 if m == pb.Property_BLOB { 301 return []byte(*v.StringValue), nil 302 } else if m == pb.Property_BLOBKEY { 303 return appengine.BlobKey(*v.StringValue), nil 304 } else if m == pb.Property_BYTESTRING { 305 return ByteString(*v.StringValue), nil 306 } else { 307 return *v.StringValue, nil 308 } 309 case v.DoubleValue != nil: 310 return *v.DoubleValue, nil 311 case v.Referencevalue != nil: 312 key, err := referenceValueToKey(v.Referencevalue) 313 if err != nil { 314 return nil, err 315 } 316 return key, nil 317 case v.Pointvalue != nil: 318 // NOTE: Strangely, latitude maps to X, longitude to Y. 319 return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil 320 } 321 return nil, nil 322 } 323 324 // indexValue is a Property value that is created when entities are loaded from 325 // an index, such as from a projection query. 326 // 327 // Such Property values do not contain all of the metadata required to be 328 // faithfully represented as a Go value, and are instead represented as an 329 // opaque indexValue. Load the properties into a concrete struct type (e.g. by 330 // passing a struct pointer to Iterator.Next) to reconstruct actual Go values 331 // of type int, string, time.Time, etc. 332 type indexValue struct { 333 value *pb.PropertyValue 334 }