diff options
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/load.go')
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/load.go | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/vendor/google.golang.org/appengine/datastore/load.go b/vendor/google.golang.org/appengine/datastore/load.go new file mode 100644 index 0000000..38a6365 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/load.go | |||
@@ -0,0 +1,429 @@ | |||
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 | "strings" | ||
11 | "time" | ||
12 | |||
13 | "github.com/golang/protobuf/proto" | ||
14 | "google.golang.org/appengine" | ||
15 | pb "google.golang.org/appengine/internal/datastore" | ||
16 | ) | ||
17 | |||
18 | var ( | ||
19 | typeOfBlobKey = reflect.TypeOf(appengine.BlobKey("")) | ||
20 | typeOfByteSlice = reflect.TypeOf([]byte(nil)) | ||
21 | typeOfByteString = reflect.TypeOf(ByteString(nil)) | ||
22 | typeOfGeoPoint = reflect.TypeOf(appengine.GeoPoint{}) | ||
23 | typeOfTime = reflect.TypeOf(time.Time{}) | ||
24 | typeOfKeyPtr = reflect.TypeOf(&Key{}) | ||
25 | typeOfEntityPtr = reflect.TypeOf(&Entity{}) | ||
26 | ) | ||
27 | |||
28 | // typeMismatchReason returns a string explaining why the property p could not | ||
29 | // be stored in an entity field of type v.Type(). | ||
30 | func typeMismatchReason(pValue interface{}, v reflect.Value) string { | ||
31 | entityType := "empty" | ||
32 | switch pValue.(type) { | ||
33 | case int64: | ||
34 | entityType = "int" | ||
35 | case bool: | ||
36 | entityType = "bool" | ||
37 | case string: | ||
38 | entityType = "string" | ||
39 | case float64: | ||
40 | entityType = "float" | ||
41 | case *Key: | ||
42 | entityType = "*datastore.Key" | ||
43 | case time.Time: | ||
44 | entityType = "time.Time" | ||
45 | case appengine.BlobKey: | ||
46 | entityType = "appengine.BlobKey" | ||
47 | case appengine.GeoPoint: | ||
48 | entityType = "appengine.GeoPoint" | ||
49 | case ByteString: | ||
50 | entityType = "datastore.ByteString" | ||
51 | case []byte: | ||
52 | entityType = "[]byte" | ||
53 | } | ||
54 | return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) | ||
55 | } | ||
56 | |||
57 | type propertyLoader struct { | ||
58 | // m holds the number of times a substruct field like "Foo.Bar.Baz" has | ||
59 | // been seen so far. The map is constructed lazily. | ||
60 | m map[string]int | ||
61 | } | ||
62 | |||
63 | func (l *propertyLoader) load(codec *structCodec, structValue reflect.Value, p Property, requireSlice bool) string { | ||
64 | var v reflect.Value | ||
65 | var sliceIndex int | ||
66 | |||
67 | name := p.Name | ||
68 | |||
69 | // If name ends with a '.', the last field is anonymous. | ||
70 | // In this case, strings.Split will give us "" as the | ||
71 | // last element of our fields slice, which will match the "" | ||
72 | // field name in the substruct codec. | ||
73 | fields := strings.Split(name, ".") | ||
74 | |||
75 | for len(fields) > 0 { | ||
76 | var decoder fieldCodec | ||
77 | var ok bool | ||
78 | |||
79 | // Cut off the last field (delimited by ".") and find its parent | ||
80 | // in the codec. | ||
81 | // eg. for name "A.B.C.D", split off "A.B.C" and try to | ||
82 | // find a field in the codec with this name. | ||
83 | // Loop again with "A.B", etc. | ||
84 | for i := len(fields); i > 0; i-- { | ||
85 | parent := strings.Join(fields[:i], ".") | ||
86 | decoder, ok = codec.fields[parent] | ||
87 | if ok { | ||
88 | fields = fields[i:] | ||
89 | break | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // If we never found a matching field in the codec, return | ||
94 | // error message. | ||
95 | if !ok { | ||
96 | return "no such struct field" | ||
97 | } | ||
98 | |||
99 | v = initField(structValue, decoder.path) | ||
100 | if !v.IsValid() { | ||
101 | return "no such struct field" | ||
102 | } | ||
103 | if !v.CanSet() { | ||
104 | return "cannot set struct field" | ||
105 | } | ||
106 | |||
107 | if decoder.structCodec != nil { | ||
108 | codec = decoder.structCodec | ||
109 | structValue = v | ||
110 | } | ||
111 | |||
112 | if v.Kind() == reflect.Slice && v.Type() != typeOfByteSlice { | ||
113 | if l.m == nil { | ||
114 | l.m = make(map[string]int) | ||
115 | } | ||
116 | sliceIndex = l.m[p.Name] | ||
117 | l.m[p.Name] = sliceIndex + 1 | ||
118 | for v.Len() <= sliceIndex { | ||
119 | v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem())) | ||
120 | } | ||
121 | structValue = v.Index(sliceIndex) | ||
122 | requireSlice = false | ||
123 | } | ||
124 | } | ||
125 | |||
126 | var slice reflect.Value | ||
127 | if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { | ||
128 | slice = v | ||
129 | v = reflect.New(v.Type().Elem()).Elem() | ||
130 | } else if requireSlice { | ||
131 | return "multiple-valued property requires a slice field type" | ||
132 | } | ||
133 | |||
134 | // Convert indexValues to a Go value with a meaning derived from the | ||
135 | // destination type. | ||
136 | pValue := p.Value | ||
137 | if iv, ok := pValue.(indexValue); ok { | ||
138 | meaning := pb.Property_NO_MEANING | ||
139 | switch v.Type() { | ||
140 | case typeOfBlobKey: | ||
141 | meaning = pb.Property_BLOBKEY | ||
142 | case typeOfByteSlice: | ||
143 | meaning = pb.Property_BLOB | ||
144 | case typeOfByteString: | ||
145 | meaning = pb.Property_BYTESTRING | ||
146 | case typeOfGeoPoint: | ||
147 | meaning = pb.Property_GEORSS_POINT | ||
148 | case typeOfTime: | ||
149 | meaning = pb.Property_GD_WHEN | ||
150 | case typeOfEntityPtr: | ||
151 | meaning = pb.Property_ENTITY_PROTO | ||
152 | } | ||
153 | var err error | ||
154 | pValue, err = propValue(iv.value, meaning) | ||
155 | if err != nil { | ||
156 | return err.Error() | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if errReason := setVal(v, pValue); errReason != "" { | ||
161 | // Set the slice back to its zero value. | ||
162 | if slice.IsValid() { | ||
163 | slice.Set(reflect.Zero(slice.Type())) | ||
164 | } | ||
165 | return errReason | ||
166 | } | ||
167 | |||
168 | if slice.IsValid() { | ||
169 | slice.Index(sliceIndex).Set(v) | ||
170 | } | ||
171 | |||
172 | return "" | ||
173 | } | ||
174 | |||
175 | // setVal sets v to the value pValue. | ||
176 | func setVal(v reflect.Value, pValue interface{}) string { | ||
177 | switch v.Kind() { | ||
178 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
179 | x, ok := pValue.(int64) | ||
180 | if !ok && pValue != nil { | ||
181 | return typeMismatchReason(pValue, v) | ||
182 | } | ||
183 | if v.OverflowInt(x) { | ||
184 | return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) | ||
185 | } | ||
186 | v.SetInt(x) | ||
187 | case reflect.Bool: | ||
188 | x, ok := pValue.(bool) | ||
189 | if !ok && pValue != nil { | ||
190 | return typeMismatchReason(pValue, v) | ||
191 | } | ||
192 | v.SetBool(x) | ||
193 | case reflect.String: | ||
194 | switch x := pValue.(type) { | ||
195 | case appengine.BlobKey: | ||
196 | v.SetString(string(x)) | ||
197 | case ByteString: | ||
198 | v.SetString(string(x)) | ||
199 | case string: | ||
200 | v.SetString(x) | ||
201 | default: | ||
202 | if pValue != nil { | ||
203 | return typeMismatchReason(pValue, v) | ||
204 | } | ||
205 | } | ||
206 | case reflect.Float32, reflect.Float64: | ||
207 | x, ok := pValue.(float64) | ||
208 | if !ok && pValue != nil { | ||
209 | return typeMismatchReason(pValue, v) | ||
210 | } | ||
211 | if v.OverflowFloat(x) { | ||
212 | return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) | ||
213 | } | ||
214 | v.SetFloat(x) | ||
215 | case reflect.Ptr: | ||
216 | x, ok := pValue.(*Key) | ||
217 | if !ok && pValue != nil { | ||
218 | return typeMismatchReason(pValue, v) | ||
219 | } | ||
220 | if _, ok := v.Interface().(*Key); !ok { | ||
221 | return typeMismatchReason(pValue, v) | ||
222 | } | ||
223 | v.Set(reflect.ValueOf(x)) | ||
224 | case reflect.Struct: | ||
225 | switch v.Type() { | ||
226 | case typeOfTime: | ||
227 | x, ok := pValue.(time.Time) | ||
228 | if !ok && pValue != nil { | ||
229 | return typeMismatchReason(pValue, v) | ||
230 | } | ||
231 | v.Set(reflect.ValueOf(x)) | ||
232 | case typeOfGeoPoint: | ||
233 | x, ok := pValue.(appengine.GeoPoint) | ||
234 | if !ok && pValue != nil { | ||
235 | return typeMismatchReason(pValue, v) | ||
236 | } | ||
237 | v.Set(reflect.ValueOf(x)) | ||
238 | default: | ||
239 | ent, ok := pValue.(*Entity) | ||
240 | if !ok { | ||
241 | return typeMismatchReason(pValue, v) | ||
242 | } | ||
243 | |||
244 | // Recursively load nested struct | ||
245 | pls, err := newStructPLS(v.Addr().Interface()) | ||
246 | if err != nil { | ||
247 | return err.Error() | ||
248 | } | ||
249 | |||
250 | // if ent has a Key value and our struct has a Key field, | ||
251 | // load the Entity's Key value into the Key field on the struct. | ||
252 | if ent.Key != nil && pls.codec.keyField != -1 { | ||
253 | |||
254 | pls.v.Field(pls.codec.keyField).Set(reflect.ValueOf(ent.Key)) | ||
255 | } | ||
256 | |||
257 | err = pls.Load(ent.Properties) | ||
258 | if err != nil { | ||
259 | return err.Error() | ||
260 | } | ||
261 | } | ||
262 | case reflect.Slice: | ||
263 | x, ok := pValue.([]byte) | ||
264 | if !ok { | ||
265 | if y, yok := pValue.(ByteString); yok { | ||
266 | x, ok = []byte(y), true | ||
267 | } | ||
268 | } | ||
269 | if !ok && pValue != nil { | ||
270 | return typeMismatchReason(pValue, v) | ||
271 | } | ||
272 | if v.Type().Elem().Kind() != reflect.Uint8 { | ||
273 | return typeMismatchReason(pValue, v) | ||
274 | } | ||
275 | v.SetBytes(x) | ||
276 | default: | ||
277 | return typeMismatchReason(pValue, v) | ||
278 | } | ||
279 | return "" | ||
280 | } | ||
281 | |||
282 | // initField is similar to reflect's Value.FieldByIndex, in that it | ||
283 | // returns the nested struct field corresponding to index, but it | ||
284 | // initialises any nil pointers encountered when traversing the structure. | ||
285 | func initField(val reflect.Value, index []int) reflect.Value { | ||
286 | for _, i := range index[:len(index)-1] { | ||
287 | val = val.Field(i) | ||
288 | if val.Kind() == reflect.Ptr { | ||
289 | if val.IsNil() { | ||
290 | val.Set(reflect.New(val.Type().Elem())) | ||
291 | } | ||
292 | val = val.Elem() | ||
293 | } | ||
294 | } | ||
295 | return val.Field(index[len(index)-1]) | ||
296 | } | ||
297 | |||
298 | // loadEntity loads an EntityProto into PropertyLoadSaver or struct pointer. | ||
299 | func loadEntity(dst interface{}, src *pb.EntityProto) (err error) { | ||
300 | ent, err := protoToEntity(src) | ||
301 | if err != nil { | ||
302 | return err | ||
303 | } | ||
304 | if e, ok := dst.(PropertyLoadSaver); ok { | ||
305 | return e.Load(ent.Properties) | ||
306 | } | ||
307 | return LoadStruct(dst, ent.Properties) | ||
308 | } | ||
309 | |||
310 | func (s structPLS) Load(props []Property) error { | ||
311 | var fieldName, reason string | ||
312 | var l propertyLoader | ||
313 | for _, p := range props { | ||
314 | if errStr := l.load(s.codec, s.v, p, p.Multiple); errStr != "" { | ||
315 | // We don't return early, as we try to load as many properties as possible. | ||
316 | // It is valid to load an entity into a struct that cannot fully represent it. | ||
317 | // That case returns an error, but the caller is free to ignore it. | ||
318 | fieldName, reason = p.Name, errStr | ||
319 | } | ||
320 | } | ||
321 | if reason != "" { | ||
322 | return &ErrFieldMismatch{ | ||
323 | StructType: s.v.Type(), | ||
324 | FieldName: fieldName, | ||
325 | Reason: reason, | ||
326 | } | ||
327 | } | ||
328 | return nil | ||
329 | } | ||
330 | |||
331 | func protoToEntity(src *pb.EntityProto) (*Entity, error) { | ||
332 | props, rawProps := src.Property, src.RawProperty | ||
333 | outProps := make([]Property, 0, len(props)+len(rawProps)) | ||
334 | for { | ||
335 | var ( | ||
336 | x *pb.Property | ||
337 | noIndex bool | ||
338 | ) | ||
339 | if len(props) > 0 { | ||
340 | x, props = props[0], props[1:] | ||
341 | } else if len(rawProps) > 0 { | ||
342 | x, rawProps = rawProps[0], rawProps[1:] | ||
343 | noIndex = true | ||
344 | } else { | ||
345 | break | ||
346 | } | ||
347 | |||
348 | var value interface{} | ||
349 | if x.Meaning != nil && *x.Meaning == pb.Property_INDEX_VALUE { | ||
350 | value = indexValue{x.Value} | ||
351 | } else { | ||
352 | var err error | ||
353 | value, err = propValue(x.Value, x.GetMeaning()) | ||
354 | if err != nil { | ||
355 | return nil, err | ||
356 | } | ||
357 | } | ||
358 | outProps = append(outProps, Property{ | ||
359 | Name: x.GetName(), | ||
360 | Value: value, | ||
361 | NoIndex: noIndex, | ||
362 | Multiple: x.GetMultiple(), | ||
363 | }) | ||
364 | } | ||
365 | |||
366 | var key *Key | ||
367 | if src.Key != nil { | ||
368 | // Ignore any error, since nested entity values | ||
369 | // are allowed to have an invalid key. | ||
370 | key, _ = protoToKey(src.Key) | ||
371 | } | ||
372 | return &Entity{key, outProps}, nil | ||
373 | } | ||
374 | |||
375 | // propValue returns a Go value that combines the raw PropertyValue with a | ||
376 | // meaning. For example, an Int64Value with GD_WHEN becomes a time.Time. | ||
377 | func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) { | ||
378 | switch { | ||
379 | case v.Int64Value != nil: | ||
380 | if m == pb.Property_GD_WHEN { | ||
381 | return fromUnixMicro(*v.Int64Value), nil | ||
382 | } else { | ||
383 | return *v.Int64Value, nil | ||
384 | } | ||
385 | case v.BooleanValue != nil: | ||
386 | return *v.BooleanValue, nil | ||
387 | case v.StringValue != nil: | ||
388 | if m == pb.Property_BLOB { | ||
389 | return []byte(*v.StringValue), nil | ||
390 | } else if m == pb.Property_BLOBKEY { | ||
391 | return appengine.BlobKey(*v.StringValue), nil | ||
392 | } else if m == pb.Property_BYTESTRING { | ||
393 | return ByteString(*v.StringValue), nil | ||
394 | } else if m == pb.Property_ENTITY_PROTO { | ||
395 | var ent pb.EntityProto | ||
396 | err := proto.Unmarshal([]byte(*v.StringValue), &ent) | ||
397 | if err != nil { | ||
398 | return nil, err | ||
399 | } | ||
400 | return protoToEntity(&ent) | ||
401 | } else { | ||
402 | return *v.StringValue, nil | ||
403 | } | ||
404 | case v.DoubleValue != nil: | ||
405 | return *v.DoubleValue, nil | ||
406 | case v.Referencevalue != nil: | ||
407 | key, err := referenceValueToKey(v.Referencevalue) | ||
408 | if err != nil { | ||
409 | return nil, err | ||
410 | } | ||
411 | return key, nil | ||
412 | case v.Pointvalue != nil: | ||
413 | // NOTE: Strangely, latitude maps to X, longitude to Y. | ||
414 | return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil | ||
415 | } | ||
416 | return nil, nil | ||
417 | } | ||
418 | |||
419 | // indexValue is a Property value that is created when entities are loaded from | ||
420 | // an index, such as from a projection query. | ||
421 | // | ||
422 | // Such Property values do not contain all of the metadata required to be | ||
423 | // faithfully represented as a Go value, and are instead represented as an | ||
424 | // opaque indexValue. Load the properties into a concrete struct type (e.g. by | ||
425 | // passing a struct pointer to Iterator.Next) to reconstruct actual Go values | ||
426 | // of type int, string, time.Time, etc. | ||
427 | type indexValue struct { | ||
428 | value *pb.PropertyValue | ||
429 | } | ||