Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: service/datastore/multiarg.go

Issue 2048933004: Refactor multiarg, split MGS/PLS. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: Rebarse? Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « service/datastore/interface.go ('k') | service/datastore/pls.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package datastore 5 package datastore
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "reflect" 9 "reflect"
10 10
11 "github.com/luci/luci-go/common/errors" 11 "github.com/luci/luci-go/common/errors"
12 ) 12 )
13 13
14 type multiArgType struct { 14 type multiArgType struct {
15 » getKey func(aid, ns string, slot reflect.Value) (*Key, error) 15 » getMGS func(slot reflect.Value) MetaGetterSetter
16 » getPM func(slot reflect.Value) (PropertyMap, error) 16 » getPLS func(slot reflect.Value) PropertyLoadSaver
17 » getMetaPM func(slot reflect.Value) PropertyMap 17 » newElem func() reflect.Value
18 » setPM func(slot reflect.Value, pm PropertyMap) error 18 }
19 » setKey func(slot reflect.Value, k *Key) 19
20 » newElem func() reflect.Value 20 func (mat *multiArgType) getKey(aid, ns string, slot reflect.Value) (*Key, error ) {
21 » return newKeyObjErr(aid, ns, mat.getMGS(slot))
22 }
23
24 func (mat *multiArgType) getPM(slot reflect.Value) (PropertyMap, error) {
25 » return mat.getPLS(slot).Save(true)
26 }
27
28 func (mat *multiArgType) getMetaPM(slot reflect.Value) PropertyMap {
29 » return mat.getMGS(slot).GetAllMeta()
30 }
31
32 func (mat *multiArgType) setPM(slot reflect.Value, pm PropertyMap) error {
33 » return mat.getPLS(slot).Load(pm)
34 }
35
36 func (mat *multiArgType) setKey(slot reflect.Value, k *Key) {
37 » PopulateKey(mat.getMGS(slot), k)
21 } 38 }
22 39
23 // parseArg checks that et is of type S, *S, I, P or *P, for some 40 // parseArg checks that et is of type S, *S, I, P or *P, for some
24 // struct type S, for some interface type I, or some non-interface non-pointer 41 // struct type S, for some interface type I, or some non-interface non-pointer
25 // type P such that P or *P implements PropertyLoadSaver. 42 // type P such that P or *P implements PropertyLoadSaver.
26 // 43 //
27 // If et is a chan type that implements PropertyLoadSaver, new elements will be 44 // If et is a chan type that implements PropertyLoadSaver, new elements will be
28 // allocated with a buffer of 0. 45 // allocated with a buffer of 0.
29 // 46 //
30 // If keysOnly is true, a read-only key extraction multiArgType will be 47 // If keysOnly is true, a read-only key extraction multiArgType will be
31 // returned if et is a *Key. 48 // returned if et is a *Key.
32 func parseArg(et reflect.Type, keysOnly bool) *multiArgType { 49 func parseArg(et reflect.Type, keysOnly bool) *multiArgType {
50 var mat multiArgType
51
33 if keysOnly && et == typeOfKey { 52 if keysOnly && et == typeOfKey {
34 » » return multiArgTypeKeyExtraction() 53 » » mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &keyExtractionMGS{key: slot.Interface().(*Key)} }
54 » » return &mat
35 } 55 }
36 56
37 » if et.Kind() == reflect.Interface { 57 » // If we do identify a structCodec for this type, retain it so we don't
38 » » return multiArgTypeInterface() 58 » // resolve it multiple times.
59 » var codec *structCodec
60 » initCodec := func(t reflect.Type) *structCodec {
61 » » if codec == nil {
62 » » » codec = getCodec(t)
63 » » }
64 » » return codec
39 } 65 }
40 66
67 // Fill in MetaGetterSetter functions.
68 switch {
69 case et.Implements(typeOfMetaGetterSetter):
70 // MGS
71 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return slot.Interface().(MetaGetterSetter) }
72
73 case reflect.PtrTo(et).Implements(typeOfMetaGetterSetter):
74 // *MGS
75 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return slot.Addr().Interface().(MetaGetterSetter) }
76
77 default:
78 switch et.Kind() {
79 case reflect.Interface:
80 // I
81 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return getMGS(slot.Elem().Interface()) }
82
83 case reflect.Ptr:
84 // *S
85 if et.Elem().Kind() != reflect.Struct {
86 // Not a struct pointer.
87 return nil
88 }
89
90 initCodec(et.Elem())
91 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &structPLS{slot.Elem(), codec, nil} }
92
93 case reflect.Struct:
94 // S
95 initCodec(et)
96 mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &structPLS{slot, codec, nil} }
97
98 default:
99 // Don't know how to get MGS for this type.
100 return nil
101 }
102 }
103
104 // Fill in PropertyLoadSaver functions.
105 switch {
106 case et.Implements(typeOfPropertyLoadSaver):
107 // PLS
108 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return slot.Interface().(PropertyLoadSaver) }
109
110 case reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver):
111 // *PLS
112 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return slot.Addr().Interface().(PropertyLoadSaver) }
113
114 default:
115 switch et.Kind() {
116 case reflect.Interface:
117 // I
118 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver {
119 obj := slot.Elem().Interface()
120 if pls, ok := obj.(PropertyLoadSaver); ok {
121 return pls
122 }
123 return GetPLS(obj)
124 }
125
126 case reflect.Ptr:
127 // *S
128 if et.Elem().Kind() != reflect.Struct {
129 // Not a struct pointer.
130 return nil
131 }
132 initCodec(et.Elem())
133 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return &structPLS{slot.Elem(), codec, nil} }
134
135 case reflect.Struct:
136 // S
137 initCodec(et)
138 mat.getPLS = func(slot reflect.Value) PropertyLoadSaver { return &structPLS{slot, codec, nil} }
139
140 default:
141 // Don't know how to get PLS for this type.
142 return nil
143 }
144 }
145
146 // Generate new element.
147 //
41 // If a map/chan type implements an interface, its pointer is also consi dered 148 // If a map/chan type implements an interface, its pointer is also consi dered
42 // to implement that interface. 149 // to implement that interface.
43 // 150 //
44 // In this case, we have special pointer-to-map/chan logic in multiArgTy pePLS. 151 // In this case, we have special pointer-to-map/chan logic in multiArgTy pePLS.
45 » if et.Implements(typeOfPropertyLoadSaver) { 152 » mat.newElem = func() reflect.Value {
46 » » return multiArgTypePLS(et) 153 » » return reflect.New(et).Elem()
47 » }
48 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
49 » » return multiArgTypePLSPtr(et)
50 } 154 }
51 155
52 switch et.Kind() { 156 switch et.Kind() {
53 case reflect.Ptr:
54 if et.Elem().Kind() == reflect.Struct {
55 return multiArgTypeStructPtr(et)
56 }
57
58 case reflect.Struct:
59 return multiArgTypeStruct(et)
60 }
61
62 return nil
63 }
64
65 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some
66 // struct type S, for some interface type I, or some non-interface non-pointer
67 // type P such that P or *P implements PropertyLoadSaver.
68 func mustParseMultiArg(et reflect.Type) *multiArgType {
69 if et.Kind() != reflect.Slice {
70 panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
71 }
72 return mustParseArg(et.Elem())
73 }
74
75 func mustParseArg(et reflect.Type) *multiArgType {
76 if mat := parseArg(et, false); mat != nil {
77 return mat
78 }
79 panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et))
80 }
81
82 // multiArgTypePLS handles the case where et implements PropertyLoadSaver.
83 //
84 // This handles the special case of pointer-to-map and pointer-to-chan (
85 // see parseArg).
86 func multiArgTypePLS(et reflect.Type) *multiArgType {
87 ret := multiArgType{
88 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
89 return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
90 },
91 getPM: func(slot reflect.Value) (PropertyMap, error) {
92 return slot.Interface().(PropertyLoadSaver).Save(true)
93 },
94 getMetaPM: func(slot reflect.Value) PropertyMap {
95 return getMGS(slot.Interface()).GetAllMeta()
96 },
97 setPM: func(slot reflect.Value, pm PropertyMap) error {
98 return slot.Interface().(PropertyLoadSaver).Load(pm)
99 },
100 setKey: func(slot reflect.Value, k *Key) {
101 PopulateKey(slot.Interface(), k)
102 },
103 }
104 switch et.Kind() {
105 case reflect.Map: 157 case reflect.Map:
106 » » ret.newElem = func() reflect.Value { 158 » » mat.newElem = func() reflect.Value {
107 return reflect.MakeMap(et) 159 return reflect.MakeMap(et)
108 } 160 }
109 161
110 case reflect.Chan: 162 case reflect.Chan:
111 » » ret.newElem = func() reflect.Value { 163 » » mat.newElem = func() reflect.Value {
112 return reflect.MakeChan(et, 0) 164 return reflect.MakeChan(et, 0)
113 } 165 }
114 166
115 case reflect.Ptr: 167 case reflect.Ptr:
116 elem := et.Elem() 168 elem := et.Elem()
117 switch elem.Kind() { 169 switch elem.Kind() {
118 case reflect.Map: 170 case reflect.Map:
119 » » » ret.newElem = func() reflect.Value { 171 » » » mat.newElem = func() reflect.Value {
120 ptr := reflect.New(elem) 172 ptr := reflect.New(elem)
121 ptr.Elem().Set(reflect.MakeMap(elem)) 173 ptr.Elem().Set(reflect.MakeMap(elem))
122 return ptr 174 return ptr
123 } 175 }
124 176
125 case reflect.Chan: 177 case reflect.Chan:
126 » » » ret.newElem = func() reflect.Value { 178 » » » mat.newElem = func() reflect.Value {
127 ptr := reflect.New(elem) 179 ptr := reflect.New(elem)
128 ptr.Elem().Set(reflect.MakeChan(elem, 0)) 180 ptr.Elem().Set(reflect.MakeChan(elem, 0))
129 return ptr 181 return ptr
130 } 182 }
183
184 default:
185 mat.newElem = func() reflect.Value { return reflect.New( et.Elem()) }
131 } 186 }
187
188 case reflect.Interface:
189 mat.newElem = nil
132 } 190 }
133 191
134 » if ret.newElem == nil { 192 » return &mat
135 » » ret.newElem = func() reflect.Value {
136 » » » return reflect.New(et.Elem())
137 » » }
138 » }
139 » return &ret
140 } 193 }
141 194
142 // multiArgTypePLSPtr handles the case where et doesn't implement 195 // mustParseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for
143 // PropertyLoadSaver, but a pointer to et does. 196 // some struct type S, for some interface type I, or some non-interface
144 func multiArgTypePLSPtr(et reflect.Type) *multiArgType { 197 // non-pointer type P such that P or *P implements PropertyLoadSaver.
145 » return &multiArgType{ 198 func mustParseMultiArg(et reflect.Type) *multiArgType {
146 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 199 » if et.Kind() != reflect.Slice {
147 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e())) 200 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
148 » » },
149 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
150 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
151 » » },
152 » » getMetaPM: func(slot reflect.Value) PropertyMap {
153 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
154 » » },
155 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
156 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm)
157 » » },
158 » » setKey: func(slot reflect.Value, k *Key) {
159 » » » PopulateKey(slot.Addr().Interface(), k)
160 » » },
161 » » newElem: func() reflect.Value {
162 » » » return reflect.New(et).Elem()
163 » » },
164 } 201 }
202 return mustParseArg(et.Elem())
165 } 203 }
166 204
167 // multiArgTypeStruct == []S 205 func mustParseArg(et reflect.Type) *multiArgType {
168 func multiArgTypeStruct(et reflect.Type) *multiArgType { 206 » if mat := parseArg(et, false); mat != nil {
169 » cdc := getCodec(et) 207 » » return mat
170 » toPLS := func(slot reflect.Value) *structPLS {
171 » » return &structPLS{slot, cdc}
172 } 208 }
173 » return &multiArgType{ 209 » panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et))
174 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
175 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
176 » » },
177 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
178 » » » return toPLS(slot).Save(true)
179 » » },
180 » » getMetaPM: func(slot reflect.Value) PropertyMap {
181 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
182 » » },
183 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
184 » » » return toPLS(slot).Load(pm)
185 » » },
186 » » setKey: func(slot reflect.Value, k *Key) {
187 » » » PopulateKey(toPLS(slot), k)
188 » » },
189 » » newElem: func() reflect.Value {
190 » » » return reflect.New(et).Elem()
191 » » },
192 » }
193 }
194
195 // multiArgTypeStructPtr == []*S
196 func multiArgTypeStructPtr(et reflect.Type) *multiArgType {
197 » cdc := getCodec(et.Elem())
198 » toPLS := func(slot reflect.Value) *structPLS {
199 » » return &structPLS{slot.Elem(), cdc}
200 » }
201 » return &multiArgType{
202 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
203 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
204 » » },
205 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
206 » » » return toPLS(slot).Save(true)
207 » » },
208 » » getMetaPM: func(slot reflect.Value) PropertyMap {
209 » » » return getMGS(slot.Interface()).GetAllMeta()
210 » » },
211 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
212 » » » return toPLS(slot).Load(pm)
213 » » },
214 » » setKey: func(slot reflect.Value, k *Key) {
215 » » » PopulateKey(toPLS(slot), k)
216 » » },
217 » » newElem: func() reflect.Value {
218 » » » return reflect.New(et.Elem())
219 » » },
220 » }
221 }
222
223 // multiArgTypeInterface == []I
224 func multiArgTypeInterface() *multiArgType {
225 » return &multiArgType{
226 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
227 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac e()))
228 » » },
229 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
230 » » » return mkPLS(slot.Elem().Interface()).Save(true)
231 » » },
232 » » getMetaPM: func(slot reflect.Value) PropertyMap {
233 » » » return getMGS(slot.Elem().Interface()).GetAllMeta()
234 » » },
235 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
236 » » » return mkPLS(slot.Elem().Interface()).Load(pm)
237 » » },
238 » » setKey: func(slot reflect.Value, k *Key) {
239 » » » PopulateKey(slot.Elem().Interface(), k)
240 » » },
241 » }
242 }
243
244 // multiArgTypeKeyExtraction == *Key
245 //
246 // This ONLY implements getKey.
247 func multiArgTypeKeyExtraction() *multiArgType {
248 » return &multiArgType{
249 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
250 » » » return slot.Interface().(*Key), nil
251 » » },
252 » }
253 } 210 }
254 211
255 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) { 212 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
256 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil { 213 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
257 return key, nil 214 return key, nil
258 } 215 }
259 216
260 // get kind 217 // get kind
261 kind := GetMetaDefault(mgs, "kind", "").(string) 218 kind := GetMetaDefault(mgs, "kind", "").(string)
262 if kind == "" { 219 if kind == "" {
263 return nil, errors.New("unable to extract $kind") 220 return nil, errors.New("unable to extract $kind")
264 } 221 }
265 222
266 // get id - allow both to be default for default keys 223 // get id - allow both to be default for default keys
267 sid := GetMetaDefault(mgs, "id", "").(string) 224 sid := GetMetaDefault(mgs, "id", "").(string)
268 iid := GetMetaDefault(mgs, "id", 0).(int64) 225 iid := GetMetaDefault(mgs, "id", 0).(int64)
269 226
270 // get parent 227 // get parent
271 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key) 228 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
272 229
273 return NewKey(aid, ns, kind, sid, iid, par), nil 230 return NewKey(aid, ns, kind, sid, iid, par), nil
274 } 231 }
275 232
276 func mkPLS(o interface{}) PropertyLoadSaver {
277 if pls, ok := o.(PropertyLoadSaver); ok {
278 return pls
279 }
280 return GetPLS(o)
281 }
282
283 func isOKSingleType(t reflect.Type, keysOnly bool) error { 233 func isOKSingleType(t reflect.Type, keysOnly bool) error {
284 switch { 234 switch {
285 case t == nil: 235 case t == nil:
286 return errors.New("no type information") 236 return errors.New("no type information")
287 case t.Implements(typeOfPropertyLoadSaver): 237 case t.Implements(typeOfPropertyLoadSaver):
288 return nil 238 return nil
289 case !keysOnly && t == typeOfKey: 239 case !keysOnly && t == typeOfKey:
290 return errors.New("not user datatype") 240 return errors.New("not user datatype")
241
291 case t.Kind() != reflect.Ptr: 242 case t.Kind() != reflect.Ptr:
292 return errors.New("not a pointer") 243 return errors.New("not a pointer")
293 case t.Elem().Kind() != reflect.Struct: 244 case t.Elem().Kind() != reflect.Struct:
294 return errors.New("does not point to a struct") 245 return errors.New("does not point to a struct")
246
295 default: 247 default:
296 return nil 248 return nil
297 } 249 }
298 } 250 }
299 251
252 // keyExtractionMGS is a MetaGetterSetter that wraps a key and only implements
253 // GetMeta, and even then only retrieves the wrapped key meta value, "key".
254 type keyExtractionMGS struct {
255 MetaGetterSetter
256
257 key *Key
258 }
259
260 func (mgs *keyExtractionMGS) GetMeta(key string) (interface{}, bool) {
261 if key == "key" {
262 return mgs.key, true
263 }
264 return nil, false
265 }
266
300 type metaMultiArgElement struct { 267 type metaMultiArgElement struct {
301 arg reflect.Value 268 arg reflect.Value
302 mat *multiArgType 269 mat *multiArgType
303 size int // size is -1 if this element is not a slice. 270 size int // size is -1 if this element is not a slice.
304 } 271 }
305 272
306 type metaMultiArg struct { 273 type metaMultiArg struct {
307 elems []metaMultiArgElement 274 elems []metaMultiArgElement
308 keysOnly bool 275 keysOnly bool
309 276
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 default: 506 default:
540 // Pass through to track as MultiError. 507 // Pass through to track as MultiError.
541 bt.errorTracker.trackError(it, err) 508 bt.errorTracker.trackError(it, err)
542 } 509 }
543 } 510 }
544 511
545 func (bt *boolTracker) result() *ExistsResult { 512 func (bt *boolTracker) result() *ExistsResult {
546 bt.res.updateSlices() 513 bt.res.updateSlices()
547 return &bt.res 514 return &bt.res
548 } 515 }
OLDNEW
« no previous file with comments | « service/datastore/interface.go ('k') | service/datastore/pls.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698