OLD | NEW |
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 Loading... |
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 } |
OLD | NEW |