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 |