| 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 |