| 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 "encoding/base64" | 8 "encoding/base64" |
| 9 "errors" | 9 "errors" |
| 10 "fmt" | 10 "fmt" |
| (...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 } | 614 } |
| 615 panic(fmt.Errorf("Unknown property type: %s", p.Type().String())) | 615 panic(fmt.Errorf("Unknown property type: %s", p.Type().String())) |
| 616 } | 616 } |
| 617 | 617 |
| 618 // MetaGetter is a subinterface of PropertyLoadSaver, but is also used to | 618 // MetaGetter is a subinterface of PropertyLoadSaver, but is also used to |
| 619 // abstract the meta argument for RawInterface.GetMulti. | 619 // abstract the meta argument for RawInterface.GetMulti. |
| 620 type MetaGetter interface { | 620 type MetaGetter interface { |
| 621 // GetMeta will get information about the field which has the struct tag
in | 621 // GetMeta will get information about the field which has the struct tag
in |
| 622 // the form of `gae:"$<key>[,<default>]?"`. | 622 // the form of `gae:"$<key>[,<default>]?"`. |
| 623 // | 623 // |
| 624 // It returns the value, if any, and true iff the value was retrieved. |
| 625 // |
| 624 // Supported metadata types are: | 626 // Supported metadata types are: |
| 625 // int64 - may have default (ascii encoded base-10) | 627 // int64 - may have default (ascii encoded base-10) |
| 626 // string - may have default | 628 // string - may have default |
| 627 // Toggle - MUST have default ("true" or "false") | 629 // Toggle - MUST have default ("true" or "false") |
| 628 // *Key - NO default allowed | 630 // *Key - NO default allowed |
| 629 // | 631 // |
| 630 // Struct fields of type Toggle (which is an Auto/On/Off) require you to | 632 // Struct fields of type Toggle (which is an Auto/On/Off) require you to |
| 631 // specify a value of 'true' or 'false' for the default value of the str
uct | 633 // specify a value of 'true' or 'false' for the default value of the str
uct |
| 632 // tag, and GetMeta will return the combined value as a regular boolean
true | 634 // tag, and GetMeta will return the combined value as a regular boolean
true |
| 633 // or false value. | 635 // or false value. |
| 634 // Example: | 636 // Example: |
| 635 // type MyStruct struct { | 637 // type MyStruct struct { |
| 636 // CoolField int64 `gae:"$id,1"` | 638 // CoolField int64 `gae:"$id,1"` |
| 637 // } | 639 // } |
| 638 // val, err := helper.GetPLS(&MyStruct{}).GetMeta("id") | 640 // val, err := helper.GetPLS(&MyStruct{}).GetMeta("id") |
| 639 // // val == 1 | 641 // // val == 1 |
| 640 // // err == nil | 642 // // err == nil |
| 641 // | 643 // |
| 642 // val, err := helper.GetPLS(&MyStruct{10}).GetMeta("id") | 644 // val, err := helper.GetPLS(&MyStruct{10}).GetMeta("id") |
| 643 // // val == 10 | 645 // // val == 10 |
| 644 // // err == nil | 646 // // err == nil |
| 645 // | 647 // |
| 646 // type MyStruct struct { | 648 // type MyStruct struct { |
| 647 // TFlag Toggle `gae:"$flag1,true"` // defaults to true | 649 // TFlag Toggle `gae:"$flag1,true"` // defaults to true |
| 648 // FFlag Toggle `gae:"$flag2,false"` // defaults to false | 650 // FFlag Toggle `gae:"$flag2,false"` // defaults to false |
| 649 // // BadFlag Toggle `gae:"$flag3"` // ILLEGAL | 651 // // BadFlag Toggle `gae:"$flag3"` // ILLEGAL |
| 650 // } | 652 // } |
| 651 » GetMeta(key string) (interface{}, error) | 653 » GetMeta(key string) (interface{}, bool) |
| 652 | |
| 653 » // GetMetaDefault is GetMeta, but with a default. | |
| 654 » // | |
| 655 » // If the metadata key is not available, or its type doesn't equal the | |
| 656 » // homogenized type of dflt, then dflt will be returned. | |
| 657 » // | |
| 658 » // Type homogenization: | |
| 659 » // signed integer types -> int64 | |
| 660 » // bool -> Toggle fields (bool) | |
| 661 » // | |
| 662 » // Example: | |
| 663 » // pls.GetMetaDefault("foo", 100).(int64) | |
| 664 » GetMetaDefault(key string, dflt interface{}) interface{} | |
| 665 } | 654 } |
| 666 | 655 |
| 667 // PropertyLoadSaver may be implemented by a user type, and Interface will | 656 // PropertyLoadSaver may be implemented by a user type, and Interface will |
| 668 // use this interface to serialize the type instead of trying to automatically | 657 // use this interface to serialize the type instead of trying to automatically |
| 669 // create a serialization codec for it with helper.GetPLS. | 658 // create a serialization codec for it with helper.GetPLS. |
| 670 type PropertyLoadSaver interface { | 659 type PropertyLoadSaver interface { |
| 671 // Load takes the values from the given map and attempts to save them in
to | 660 // Load takes the values from the given map and attempts to save them in
to |
| 672 // the underlying object (usually a struct or a PropertyMap). If a fatal | 661 // the underlying object (usually a struct or a PropertyMap). If a fatal |
| 673 // error occurs, it's returned via error. If non-fatal conversion errors | 662 // error occurs, it's returned via error. If non-fatal conversion errors |
| 674 // occur, error will be a MultiError containing one or more ErrFieldMism
atch | 663 // occur, error will be a MultiError containing one or more ErrFieldMism
atch |
| 675 // objects. | 664 // objects. |
| 676 Load(PropertyMap) error | 665 Load(PropertyMap) error |
| 677 | 666 |
| 678 // Save returns the current property as a PropertyMap. if withMeta is tr
ue, | 667 // Save returns the current property as a PropertyMap. if withMeta is tr
ue, |
| 679 // then the PropertyMap contains all the metadata (e.g. '$meta' fields) | 668 // then the PropertyMap contains all the metadata (e.g. '$meta' fields) |
| 680 // which was held by this PropertyLoadSaver. | 669 // which was held by this PropertyLoadSaver. |
| 681 Save(withMeta bool) (PropertyMap, error) | 670 Save(withMeta bool) (PropertyMap, error) |
| 682 | |
| 683 // Problem indicates that this PLS has a fatal problem. Usually this is | |
| 684 // set when the underlying struct has recursion, invalid field types, ne
sted | |
| 685 // slices, etc. | |
| 686 Problem() error | |
| 687 } | 671 } |
| 688 | 672 |
| 689 // MetaGetterSetter is the subset of PropertyLoadSaver which pertains to | 673 // MetaGetterSetter is the subset of PropertyLoadSaver which pertains to |
| 690 // getting and saving metadata. | 674 // getting and saving metadata. |
| 691 // | 675 // |
| 692 // A *struct may implement this interface to provide metadata which is | 676 // A *struct may implement this interface to provide metadata which is |
| 693 // supplimental to the variety described by GetPLS. For example, this could be | 677 // supplimental to the variety described by GetPLS. For example, this could be |
| 694 // used to implement a parsed-out $kind or $id. | 678 // used to implement a parsed-out $kind or $id. |
| 695 type MetaGetterSetter interface { | 679 type MetaGetterSetter interface { |
| 696 MetaGetter | 680 MetaGetter |
| 697 | 681 |
| 698 // GetAllMeta returns a PropertyMap with all of the metadata in this | 682 // GetAllMeta returns a PropertyMap with all of the metadata in this |
| 699 // MetaGetterSetter. If a metadata field has an error during serializati
on, | 683 // MetaGetterSetter. If a metadata field has an error during serializati
on, |
| 700 // it is skipped. | 684 // it is skipped. |
| 701 // | 685 // |
| 702 // If a *struct is implementing this, then it only needs to return the | 686 // If a *struct is implementing this, then it only needs to return the |
| 703 // metadata fields which would be returned by its GetMeta implementation
, and | 687 // metadata fields which would be returned by its GetMeta implementation
, and |
| 704 // the `GetPLS` implementation will add any statically-defined metadata | 688 // the `GetPLS` implementation will add any statically-defined metadata |
| 705 // fields. So if GetMeta provides $id, but there's a simple tagged field
for | 689 // fields. So if GetMeta provides $id, but there's a simple tagged field
for |
| 706 // $kind, this method is only expected to return a PropertyMap with "$id
". | 690 // $kind, this method is only expected to return a PropertyMap with "$id
". |
| 707 GetAllMeta() PropertyMap | 691 GetAllMeta() PropertyMap |
| 708 | 692 |
| 709 // SetMeta allows you to set the current value of the meta-keyed field. | 693 // SetMeta allows you to set the current value of the meta-keyed field. |
| 710 » SetMeta(key string, val interface{}) error | 694 » // It returns true iff the field was set. |
| 695 » SetMeta(key string, val interface{}) bool |
| 711 } | 696 } |
| 712 | 697 |
| 713 // PropertyMap represents the contents of a datastore entity in a generic way. | 698 // PropertyMap represents the contents of a datastore entity in a generic way. |
| 714 // It maps from property name to a list of property values which correspond to | 699 // It maps from property name to a list of property values which correspond to |
| 715 // that property name. It is the spiritual successor to PropertyList from the | 700 // that property name. It is the spiritual successor to PropertyList from the |
| 716 // original SDK. | 701 // original SDK. |
| 717 // | 702 // |
| 718 // PropertyMap may contain "meta" values, which are keyed with a '$' prefix. | 703 // PropertyMap may contain "meta" values, which are keyed with a '$' prefix. |
| 719 // Technically the datastore allows arbitrary property names, but all of the | 704 // Technically the datastore allows arbitrary property names, but all of the |
| 720 // SDKs go out of their way to try to make all property names valid programming | 705 // SDKs go out of their way to try to make all property names valid programming |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 ret := make(PropertyMap, len(pm)) | 739 ret := make(PropertyMap, len(pm)) |
| 755 for k, v := range pm { | 740 for k, v := range pm { |
| 756 if withMeta || !isMetaKey(k) { | 741 if withMeta || !isMetaKey(k) { |
| 757 ret[k] = append(ret[k], v...) | 742 ret[k] = append(ret[k], v...) |
| 758 } | 743 } |
| 759 } | 744 } |
| 760 return ret, nil | 745 return ret, nil |
| 761 } | 746 } |
| 762 | 747 |
| 763 // GetMeta implements PropertyLoadSaver.GetMeta, and returns the current value | 748 // GetMeta implements PropertyLoadSaver.GetMeta, and returns the current value |
| 764 // associated with the metadata key. It may return ErrMetaFieldUnset if the | 749 // associated with the metadata key. |
| 765 // key doesn't exist. | 750 func (pm PropertyMap) GetMeta(key string) (interface{}, bool) { |
| 766 func (pm PropertyMap) GetMeta(key string) (interface{}, error) { | |
| 767 v, ok := pm["$"+key] | 751 v, ok := pm["$"+key] |
| 768 if !ok || len(v) == 0 { | 752 if !ok || len(v) == 0 { |
| 769 » » return nil, ErrMetaFieldUnset | 753 » » return nil, false |
| 770 } | 754 } |
| 771 » if len(v) > 1 { | 755 » return v[0].Value(), true |
| 772 » » return nil, errors.New("gae: too many values for Meta key") | |
| 773 » } | |
| 774 » return v[0].Value(), nil | |
| 775 } | 756 } |
| 776 | 757 |
| 777 // GetAllMeta implements PropertyLoadSaver.GetAllMeta. | 758 // GetAllMeta implements PropertyLoadSaver.GetAllMeta. |
| 778 func (pm PropertyMap) GetAllMeta() PropertyMap { | 759 func (pm PropertyMap) GetAllMeta() PropertyMap { |
| 779 ret := make(PropertyMap, 8) | 760 ret := make(PropertyMap, 8) |
| 780 for k, v := range pm { | 761 for k, v := range pm { |
| 781 if isMetaKey(k) { | 762 if isMetaKey(k) { |
| 782 newV := make([]Property, len(v)) | 763 newV := make([]Property, len(v)) |
| 783 copy(newV, v) | 764 copy(newV, v) |
| 784 ret[k] = newV | 765 ret[k] = newV |
| 785 } | 766 } |
| 786 } | 767 } |
| 787 return ret | 768 return ret |
| 788 } | 769 } |
| 789 | 770 |
| 790 // GetMetaDefault is the implementation of PropertyLoadSaver.GetMetaDefault. | |
| 791 func (pm PropertyMap) GetMetaDefault(key string, dflt interface{}) interface{} { | |
| 792 return GetMetaDefaultImpl(pm.GetMeta, key, dflt) | |
| 793 } | |
| 794 | |
| 795 // SetMeta implements PropertyLoadSaver.SetMeta. It will only return an error | 771 // SetMeta implements PropertyLoadSaver.SetMeta. It will only return an error |
| 796 // if `val` has an invalid type (e.g. not one supported by Property). | 772 // if `val` has an invalid type (e.g. not one supported by Property). |
| 797 func (pm PropertyMap) SetMeta(key string, val interface{}) error { | 773 func (pm PropertyMap) SetMeta(key string, val interface{}) bool { |
| 798 prop := Property{} | 774 prop := Property{} |
| 799 if err := prop.SetValue(val, NoIndex); err != nil { | 775 if err := prop.SetValue(val, NoIndex); err != nil { |
| 800 » » return err | 776 » » return false |
| 801 } | 777 } |
| 802 pm["$"+key] = []Property{prop} | 778 pm["$"+key] = []Property{prop} |
| 803 » return nil | 779 » return true |
| 804 } | 780 } |
| 805 | 781 |
| 806 // Problem implements PropertyLoadSaver.Problem. It ALWAYS returns nil. | 782 // Problem implements PropertyLoadSaver.Problem. It ALWAYS returns nil. |
| 807 func (pm PropertyMap) Problem() error { | 783 func (pm PropertyMap) Problem() error { |
| 808 return nil | 784 return nil |
| 809 } | 785 } |
| 810 | 786 |
| 811 // EstimateSize estimates the size that it would take to encode this PropertyMap | 787 // EstimateSize estimates the size that it would take to encode this PropertyMap |
| 812 // in the production Appengine datastore. The calculation excludes metadata | 788 // in the production Appengine datastore. The calculation excludes metadata |
| 813 // fields in the map. | 789 // fields in the map. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 826 } | 802 } |
| 827 return ret | 803 return ret |
| 828 } | 804 } |
| 829 | 805 |
| 830 func isMetaKey(k string) bool { | 806 func isMetaKey(k string) bool { |
| 831 // empty counts as a metakey since it's not a valid data key, but it's | 807 // empty counts as a metakey since it's not a valid data key, but it's |
| 832 // not really a valid metakey either. | 808 // not really a valid metakey either. |
| 833 return k == "" || k[0] == '$' | 809 return k == "" || k[0] == '$' |
| 834 } | 810 } |
| 835 | 811 |
| 836 // GetMetaDefaultImpl is the implementation of PropertyLoadSaver.GetMetaDefault. | 812 // GetMetaDefault is a helper for GetMeta, allowing a default value. |
| 837 // | 813 // |
| 838 // It takes the normal GetMeta function, the key and the default, and returns | 814 // If the metadata key is not available, or its type doesn't equal the |
| 839 // the value according to PropertyLoadSaver.GetMetaDefault. | 815 // homogenized type of dflt, then dflt will be returned. |
| 840 func GetMetaDefaultImpl(gm func(string) (interface{}, error), key string, dflt i
nterface{}) interface{} { | 816 // |
| 817 // Type homogenization: |
| 818 // signed integer types -> int64 |
| 819 // bool -> Toggle fields (bool) |
| 820 // |
| 821 // Example: |
| 822 // pls.GetMetaDefault("foo", 100).(int64) |
| 823 func GetMetaDefault(getter MetaGetter, key string, dflt interface{}) interface{}
{ |
| 841 dflt = UpconvertUnderlyingType(dflt) | 824 dflt = UpconvertUnderlyingType(dflt) |
| 842 » cur, err := gm(key) | 825 » cur, ok := getter.GetMeta(key) |
| 843 » if err != nil { | 826 » if !ok || (dflt != nil && reflect.TypeOf(cur) != reflect.TypeOf(dflt)) { |
| 844 » » return dflt | |
| 845 » } | |
| 846 » if dflt != nil && reflect.TypeOf(cur) != reflect.TypeOf(dflt) { | |
| 847 return dflt | 827 return dflt |
| 848 } | 828 } |
| 849 return cur | 829 return cur |
| 850 } | 830 } |
| OLD | NEW |