Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: service/datastore/properties.go

Issue 1270113002: Re-add metadata passthrough on Get operations (Closed) Base URL: https://github.com/luci/gae.git@fix_other_interfaces
Patch Set: cleanup Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « service/datastore/pls_test.go ('k') | service/datastore/properties_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package datastore 5 package datastore
6 6
7 import ( 7 import (
8 "errors" 8 "errors"
9 "fmt" 9 "fmt"
10 "math" 10 "math"
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 } 217 }
218 return PTGeoPoint, err 218 return PTGeoPoint, err
219 default: 219 default:
220 return PTUnknown, fmt.Errorf("gae: Property has bad type %T", v) 220 return PTUnknown, fmt.Errorf("gae: Property has bad type %T", v)
221 } 221 }
222 } 222 }
223 223
224 // UpconvertUnderlyingType takes an object o, and attempts to convert it to 224 // UpconvertUnderlyingType takes an object o, and attempts to convert it to
225 // its native datastore-compatible type. e.g. int16 will convert to int64, and 225 // its native datastore-compatible type. e.g. int16 will convert to int64, and
226 // `type Foo string` will convert to `string`. 226 // `type Foo string` will convert to `string`.
227 func UpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, reflec t.Type) { 227 func UpconvertUnderlyingType(o interface{}) interface{} {
228 » if o == nil {
229 » » return o
230 » }
231
228 v := reflect.ValueOf(o) 232 v := reflect.ValueOf(o)
229 » switch t.Kind() { 233 » t := v.Type()
234 » switch v.Kind() {
230 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64: 235 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64:
231 o = v.Int() 236 o = v.Int()
232 t = typeOfInt64
233 case reflect.Bool: 237 case reflect.Bool:
234 o = v.Bool() 238 o = v.Bool()
235 t = typeOfBool
236 case reflect.String: 239 case reflect.String:
237 if t != typeOfBSKey { 240 if t != typeOfBSKey {
238 o = v.String() 241 o = v.String()
239 t = typeOfString
240 } 242 }
241 case reflect.Float32, reflect.Float64: 243 case reflect.Float32, reflect.Float64:
242 o = v.Float() 244 o = v.Float()
243 t = typeOfFloat64
244 case reflect.Slice: 245 case reflect.Slice:
245 if t != typeOfByteString && t.Elem().Kind() == reflect.Uint8 { 246 if t != typeOfByteString && t.Elem().Kind() == reflect.Uint8 {
246 o = v.Bytes() 247 o = v.Bytes()
247 t = typeOfByteSlice
248 } 248 }
249 case reflect.Struct: 249 case reflect.Struct:
250 if t == typeOfTime { 250 if t == typeOfTime {
251 // time in a Property can only hold microseconds 251 // time in a Property can only hold microseconds
252 o = v.Interface().(time.Time).Round(time.Microsecond) 252 o = v.Interface().(time.Time).Round(time.Microsecond)
253 } 253 }
254 } 254 }
255 » return o, t 255 » return o
256 } 256 }
257 257
258 // Value returns the current value held by this property. It's guaranteed to 258 // Value returns the current value held by this property. It's guaranteed to
259 // be a valid value type (i.e. `p.SetValue(p.Value(), true)` will never return 259 // be a valid value type (i.e. `p.SetValue(p.Value(), true)` will never return
260 // an error). 260 // an error).
261 func (p *Property) Value() interface{} { return p.value } 261 func (p *Property) Value() interface{} { return p.value }
262 262
263 // IndexSetting says weather or not the datastore should create indicies for 263 // IndexSetting says weather or not the datastore should create indicies for
264 // this value. 264 // this value.
265 func (p *Property) IndexSetting() IndexSetting { return p.indexSetting } 265 func (p *Property) IndexSetting() IndexSetting { return p.indexSetting }
(...skipping 23 matching lines...) Expand all
289 // underlying type to be on that list. For example, a Value of "type 289 // underlying type to be on that list. For example, a Value of "type
290 // myInt64 int64" is invalid. Smaller-width integers and floats are also 290 // myInt64 int64" is invalid. Smaller-width integers and floats are also
291 // invalid. Again, this is more restrictive than the set of valid struct 291 // invalid. Again, this is more restrictive than the set of valid struct
292 // field types. 292 // field types.
293 // 293 //
294 // A value may also be the nil interface value; this is equivalent to 294 // A value may also be the nil interface value; this is equivalent to
295 // Python's None but not directly representable by a Go struct. Loading 295 // Python's None but not directly representable by a Go struct. Loading
296 // a nil-valued property into a struct will set that field to the zero 296 // a nil-valued property into a struct will set that field to the zero
297 // value. 297 // value.
298 func (p *Property) SetValue(value interface{}, is IndexSetting) (err error) { 298 func (p *Property) SetValue(value interface{}, is IndexSetting) (err error) {
299 t := reflect.Type(nil)
300 pt := PTNull 299 pt := PTNull
301 if value != nil { 300 if value != nil {
302 » » t = reflect.TypeOf(value) 301 » » value = UpconvertUnderlyingType(value)
303 » » value, t = UpconvertUnderlyingType(value, t)
304 if pt, err = PropertyTypeOf(value, true); err != nil { 302 if pt, err = PropertyTypeOf(value, true); err != nil {
305 return 303 return
306 } 304 }
307 } 305 }
308 p.propType = pt 306 p.propType = pt
309 p.value = value 307 p.value = value
310 p.indexSetting = is 308 p.indexSetting = is
311 » if t == typeOfByteSlice { 309 » if _, ok := value.([]byte); ok {
312 p.indexSetting = NoIndex 310 p.indexSetting = NoIndex
313 } 311 }
314 return 312 return
315 } 313 }
316 314
317 // PropertyLoadSaver may be implemented by a user type, and Interface will 315 // MetaGetter is a subinterface of PropertyLoadSaver, but is also used to
318 // use this interface to serialize the type instead of trying to automatically 316 // abstract the meta argument for RawInterface.GetMulti.
319 // create a serialization codec for it with helper.GetPLS. 317 type MetaGetter interface {
320 type PropertyLoadSaver interface {
321 » // Load takes the values from the given map and attempts to save them in to
322 » // the underlying object (usually a struct or a PropertyMap). If a fatal
323 » // error occurs, it's returned via error. If non-fatal conversion errors
324 » // occur, error will be a MultiError containing one or more ErrFieldMism atch
325 » // objects.
326 » Load(PropertyMap) error
327
328 » // Save returns the current property as a PropertyMap. if withMeta is tr ue,
329 » // then the PropertyMap contains all the metadata (e.g. '$meta' fields)
330 » // which was held by this PropertyLoadSaver.
331 » Save(withMeta bool) (PropertyMap, error)
332
333 // GetMeta will get information about the field which has the struct tag in 318 // GetMeta will get information about the field which has the struct tag in
334 // the form of `gae:"$<key>[,<default>]?"`. 319 // the form of `gae:"$<key>[,<default>]?"`.
335 // 320 //
336 // Supported metadata types are: 321 // Supported metadata types are:
337 // int64 - may have default (ascii encoded base-10) 322 // int64 - may have default (ascii encoded base-10)
338 // string - may have default 323 // string - may have default
339 // Toggle - MUST have default ("true" or "false") 324 // Toggle - MUST have default ("true" or "false")
340 // Key - NO default allowed 325 // Key - NO default allowed
341 // 326 //
342 // Struct fields of type Toggle (which is an Auto/On/Off) require you to 327 // Struct fields of type Toggle (which is an Auto/On/Off) require you to
(...skipping 12 matching lines...) Expand all
355 // // val == 10 340 // // val == 10
356 // // err == nil 341 // // err == nil
357 // 342 //
358 // type MyStruct struct { 343 // type MyStruct struct {
359 // TFlag Toggle `gae:"$flag1,true"` // defaults to true 344 // TFlag Toggle `gae:"$flag1,true"` // defaults to true
360 // FFlag Toggle `gae:"$flag2,false"` // defaults to false 345 // FFlag Toggle `gae:"$flag2,false"` // defaults to false
361 // // BadFlag Toggle `gae:"$flag3"` // ILLEGAL 346 // // BadFlag Toggle `gae:"$flag3"` // ILLEGAL
362 // } 347 // }
363 GetMeta(key string) (interface{}, error) 348 GetMeta(key string) (interface{}, error)
364 349
350 // GetMetaDefault is GetMeta, but with a default.
351 //
352 // If the metadata key is not available, or its type doesn't equal the
353 // homogenized type of dflt, then dflt will be returned.
354 //
355 // Type homogenization:
356 // signed integer types -> int64
357 // bool -> Toggle fields (bool)
358 //
359 // Example:
360 // pls.GetMetaDefault("foo", 100).(int64)
361 GetMetaDefault(key string, dflt interface{}) interface{}
362 }
363
364 // PropertyLoadSaver may be implemented by a user type, and Interface will
365 // use this interface to serialize the type instead of trying to automatically
366 // create a serialization codec for it with helper.GetPLS.
367 type PropertyLoadSaver interface {
368 // Load takes the values from the given map and attempts to save them in to
369 // the underlying object (usually a struct or a PropertyMap). If a fatal
370 // error occurs, it's returned via error. If non-fatal conversion errors
371 // occur, error will be a MultiError containing one or more ErrFieldMism atch
372 // objects.
373 Load(PropertyMap) error
374
375 // Save returns the current property as a PropertyMap. if withMeta is tr ue,
376 // then the PropertyMap contains all the metadata (e.g. '$meta' fields)
377 // which was held by this PropertyLoadSaver.
378 Save(withMeta bool) (PropertyMap, error)
379
380 MetaGetter
381
365 // SetMeta allows you to set the current value of the meta-keyed field. 382 // SetMeta allows you to set the current value of the meta-keyed field.
366 SetMeta(key string, val interface{}) error 383 SetMeta(key string, val interface{}) error
367 384
368 // Problem indicates that this PLS has a fatal problem. Usually this is 385 // Problem indicates that this PLS has a fatal problem. Usually this is
369 // set when the underlying struct has recursion, invalid field types, ne sted 386 // set when the underlying struct has recursion, invalid field types, ne sted
370 // slices, etc. 387 // slices, etc.
371 Problem() error 388 Problem() error
372 } 389 }
373 390
374 // PropertyMap represents the contents of a datastore entity in a generic way. 391 // PropertyMap represents the contents of a datastore entity in a generic way.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 v, ok := pm["$"+key] 445 v, ok := pm["$"+key]
429 if !ok || len(v) == 0 { 446 if !ok || len(v) == 0 {
430 return nil, ErrMetaFieldUnset 447 return nil, ErrMetaFieldUnset
431 } 448 }
432 if len(v) > 1 { 449 if len(v) > 1 {
433 return nil, errors.New("gae: too many values for Meta key") 450 return nil, errors.New("gae: too many values for Meta key")
434 } 451 }
435 return v[0].Value(), nil 452 return v[0].Value(), nil
436 } 453 }
437 454
455 func (pm PropertyMap) GetMetaDefault(key string, dflt interface{}) interface{} {
456 return GetMetaDefaultImpl(pm.GetMeta, key, dflt)
457 }
458
438 // SetMeta implements PropertyLoadSaver.SetMeta. It will only return an error 459 // SetMeta implements PropertyLoadSaver.SetMeta. It will only return an error
439 // if `val` has an invalid type (e.g. not one supported by Property). 460 // if `val` has an invalid type (e.g. not one supported by Property).
440 func (pm PropertyMap) SetMeta(key string, val interface{}) error { 461 func (pm PropertyMap) SetMeta(key string, val interface{}) error {
441 prop := Property{} 462 prop := Property{}
442 if err := prop.SetValue(val, NoIndex); err != nil { 463 if err := prop.SetValue(val, NoIndex); err != nil {
443 return err 464 return err
444 } 465 }
445 pm["$"+key] = []Property{prop} 466 pm["$"+key] = []Property{prop}
446 return nil 467 return nil
447 } 468 }
448 469
449 // Problem implements PropertyLoadSaver.Problem. It ALWAYS returns nil. 470 // Problem implements PropertyLoadSaver.Problem. It ALWAYS returns nil.
450 func (pm PropertyMap) Problem() error { 471 func (pm PropertyMap) Problem() error {
451 return nil 472 return nil
452 } 473 }
474
475 // GetMetaDefaultImpl is the implementation of PropertyLoadSaver.GetMetaDefault.
476 //
477 // It takes the normal GetMeta function, the key and the default, and returns
478 // the value according to PropertyLoadSaver.GetMetaDefault.
479 func GetMetaDefaultImpl(gm func(string) (interface{}, error), key string, dflt i nterface{}) interface{} {
480 dflt = UpconvertUnderlyingType(dflt)
481 cur, err := gm(key)
482 if err != nil {
483 return dflt
484 }
485 if dflt != nil && reflect.TypeOf(cur) != reflect.TypeOf(dflt) {
486 return dflt
487 }
488 return cur
489 }
OLDNEW
« no previous file with comments | « service/datastore/pls_test.go ('k') | service/datastore/properties_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698