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 "reflect" | 8 "reflect" |
9 ) | 9 ) |
10 | 10 |
11 // GetPLS resolves obj into a PropertyLoadSaver. | 11 // GetPLS resolves obj into default struct PropertyLoadSaver and |
12 // MetaGetterSetter implementation. | |
12 // | 13 // |
13 // obj must be a non-nil pointer to a struct of some sort. | 14 // obj must be a non-nil pointer to a struct of some sort. |
14 // | 15 // |
15 // By default, exported fields will be serialized to/from the datastore. If the | 16 // By default, exported fields will be serialized to/from the datastore. If the |
16 // field is not exported, it will be skipped by the serialization routines. | 17 // field is not exported, it will be skipped by the serialization routines. |
17 // | 18 // |
18 // If a field is of a non-supported type (see Property for the list of supported | 19 // If a field is of a non-supported type (see Property for the list of supported |
19 // property types), the resulting PropertyLoadSaver will have a non-nil | 20 // property types), the resulting PropertyLoadSaver will have a non-nil |
20 // Problem(). Other problems include duplicate field names (due to tagging), | 21 // Problem(). Other problems include duplicate field names (due to tagging), |
21 // recursively defined structs, nested structures with multiple slices (e.g. | 22 // recursively defined structs, nested structures with multiple slices (e.g. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 // // 'Lines' will serialized to the datastore in the field 'Lines' | 87 // // 'Lines' will serialized to the datastore in the field 'Lines' |
87 // Lines []string | 88 // Lines []string |
88 // } | 89 // } |
89 // | 90 // |
90 // A pointer-to-struct may also implement MetaGetterSetter to provide more | 91 // A pointer-to-struct may also implement MetaGetterSetter to provide more |
91 // sophistocated metadata values. Explicitly defined fields (as shown above) | 92 // sophistocated metadata values. Explicitly defined fields (as shown above) |
92 // always take precedence over fields manipulated by the MetaGetterSetter | 93 // always take precedence over fields manipulated by the MetaGetterSetter |
93 // methods. So if your GetMeta handles "kind", but you explicitly have a | 94 // methods. So if your GetMeta handles "kind", but you explicitly have a |
94 // $kind field, the $kind field will take precedence and your GetMeta | 95 // $kind field, the $kind field will take precedence and your GetMeta |
95 // implementation will not be called for "kind". | 96 // implementation will not be called for "kind". |
96 func GetPLS(obj interface{}) PropertyLoadSaver { | 97 // |
98 // A struct overloading any of the PropertyLoadSaver or MetaGetterSetter | |
99 // interfaces may evoke the default struct behavior by using GetPLS on itself. | |
100 // For example: | |
101 // | |
102 // struct Special { | |
103 // Name string | |
104 // | |
105 // foo string | |
106 // } | |
107 // | |
108 // func (s *Special) Load(props PropertyMap) error { | |
109 // if foo, ok := props["foo"]; ok && len(foo) == 1 { | |
110 // s.foo = foo | |
111 // delete(props, "foo") | |
112 // } | |
113 // return GetPLS(props) | |
iannucci
2015/10/30 22:02:54
I think this should be `GetPLS(s).Load(props)`
| |
114 // } | |
115 // | |
116 // func (s *Special) Save(withMeta bool) (PropertyMap, error) { | |
117 // props, err := GetPLS(withMeta) | |
iannucci
2015/10/30 22:02:54
GetPLS(s).Save(withMeta)
| |
118 // if err != nil { | |
119 // return nil, err | |
120 // } | |
121 // props["foo"] = []Property{MkProperty(s.foo)} | |
122 // return props, nil | |
123 // } | |
124 // | |
125 // func (s *Special) Problem() error { | |
126 // return GetPLS(s).Problem() | |
127 // } | |
128 func GetPLS(obj interface{}) interface { | |
129 » PropertyLoadSaver | |
130 » MetaGetterSetter | |
131 } { | |
97 v := reflect.ValueOf(obj) | 132 v := reflect.ValueOf(obj) |
98 if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { | 133 if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { |
99 return &structPLS{c: &structCodec{problem: ErrInvalidEntityType} } | 134 return &structPLS{c: &structCodec{problem: ErrInvalidEntityType} } |
100 } | 135 } |
101 if v.IsNil() { | 136 if v.IsNil() { |
102 return &structPLS{c: &structCodec{problem: ErrInvalidEntityType} } | 137 return &structPLS{c: &structCodec{problem: ErrInvalidEntityType} } |
103 } | 138 } |
104 v = v.Elem() | 139 v = v.Elem() |
105 c := getCodec(v.Type()) | 140 c := getCodec(v.Type()) |
106 return &structPLS{v, c} | 141 return &structPLS{v, c} |
107 } | 142 } |
108 | 143 |
144 func getMGS(obj interface{}) MetaGetterSetter { | |
145 if mgs, ok := obj.(MetaGetterSetter); ok { | |
146 return mgs | |
147 } | |
148 return GetPLS(obj) | |
149 } | |
150 | |
109 func getCodec(structType reflect.Type) *structCodec { | 151 func getCodec(structType reflect.Type) *structCodec { |
110 structCodecsMutex.RLock() | 152 structCodecsMutex.RLock() |
111 c, ok := structCodecs[structType] | 153 c, ok := structCodecs[structType] |
112 structCodecsMutex.RUnlock() | 154 structCodecsMutex.RUnlock() |
113 if ok { | 155 if ok { |
114 return c | 156 return c |
115 } | 157 } |
116 | 158 |
117 structCodecsMutex.Lock() | 159 structCodecsMutex.Lock() |
118 defer structCodecsMutex.Unlock() | 160 defer structCodecsMutex.Unlock() |
119 return getStructCodecLocked(structType) | 161 return getStructCodecLocked(structType) |
120 } | 162 } |
OLD | NEW |