OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |