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

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

Issue 2011773002: datastore: variadic Get, Put, Exists, Delete. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: s/chn/chan/ Created 4 years, 6 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/types.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 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 "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 getKey func(aid, ns string, slot reflect.Value) (*Key, error)
16 getPM func(slot reflect.Value) (PropertyMap, error) 16 getPM func(slot reflect.Value) (PropertyMap, error)
17 getMetaPM func(slot reflect.Value) PropertyMap 17 getMetaPM func(slot reflect.Value) PropertyMap
18 setPM func(slot reflect.Value, pm PropertyMap) error 18 setPM func(slot reflect.Value, pm PropertyMap) error
19 setKey func(slot reflect.Value, k *Key) 19 setKey func(slot reflect.Value, k *Key)
20 newElem func() reflect.Value 20 newElem func() reflect.Value
21 } 21 }
22 22
23 func (mat *multiArgType) GetKeysPMs(aid, ns string, slice reflect.Value, meta bo ol) ([]*Key, []PropertyMap, error) { 23 // parseArg checks that et is of type S, *S, I, P or *P, for some
24 » retKey := make([]*Key, slice.Len()) 24 // struct type S, for some interface type I, or some non-interface non-pointer
25 » retPM := make([]PropertyMap, slice.Len()) 25 // type P such that P or *P implements PropertyLoadSaver.
26 » getter := mat.getPM 26 //
27 » if meta { 27 // If et is a chan type that implements PropertyLoadSaver, new elements will be
28 » » getter = func(slot reflect.Value) (PropertyMap, error) { 28 // allocated with a buffer of 0.
29 » » » return mat.getMetaPM(slot), nil 29 //
30 // If keysOnly is true, a read-only key extraction multiArgType will be
31 // returned if et is a *Key.
32 func parseArg(et reflect.Type, keysOnly bool) *multiArgType {
33 » if keysOnly && et == typeOfKey {
34 » » return multiArgTypeKeyExtraction()
35 » }
36
37 » if et.Kind() == reflect.Interface {
38 » » return multiArgTypeInterface()
39 » }
40
41 » // If a map/chan type implements an interface, its pointer is also consi dered
42 » // to implement that interface.
43 » //
44 » // In this case, we have special pointer-to-map/chan logic in multiArgTy pePLS.
45 » if et.Implements(typeOfPropertyLoadSaver) {
46 » » return multiArgTypePLS(et)
47 » }
48 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
49 » » return multiArgTypePLSPtr(et)
50 » }
51
52 » switch et.Kind() {
53 » case reflect.Ptr:
54 » » if et.Elem().Kind() == reflect.Struct {
55 » » » return multiArgTypeStructPtr(et)
30 } 56 }
57
58 case reflect.Struct:
59 return multiArgTypeStruct(et)
31 } 60 }
32 » lme := errors.NewLazyMultiError(len(retKey)) 61
33 » for i := range retKey { 62 » return nil
34 » » key, err := mat.getKey(aid, ns, slice.Index(i))
35 » » if !lme.Assign(i, err) {
36 » » » retKey[i] = key
37 » » » pm, err := getter(slice.Index(i))
38 » » » if !lme.Assign(i, err) {
39 » » » » retPM[i] = pm
40 » » » }
41 » » }
42 » }
43 » return retKey, retPM, lme.Get()
44 } 63 }
45 64
46 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some 65 // parseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for some
47 // struct type S, for some interface type I, or some non-interface non-pointer 66 // struct type S, for some interface type I, or some non-interface non-pointer
48 // type P such that P or *P implements PropertyLoadSaver. 67 // type P such that P or *P implements PropertyLoadSaver.
49 func parseMultiArg(e reflect.Type) multiArgType { 68 func mustParseMultiArg(et reflect.Type) *multiArgType {
50 » if e.Kind() != reflect.Slice { 69 » if et.Kind() != reflect.Slice {
51 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , e)) 70 » » panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
52 } 71 }
53 » return parseArg(e.Elem(), true) 72 » return mustParseArg(et.Elem())
54 } 73 }
55 74
56 // parseArg checks that et is of type S, *S, I, P or *P, for some 75 func mustParseArg(et reflect.Type) *multiArgType {
57 // struct type S, for some interface type I, or some non-interface non-pointer 76 » if mat := parseArg(et, false); mat != nil {
58 // type P such that P or *P implements PropertyLoadSaver. 77 » » return mat
59 func parseArg(et reflect.Type, multi bool) multiArgType {
60 » if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
61 » » return multiArgTypePLS(et)
62 } 78 }
63 » if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace { 79 » panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et))
64 » » return multiArgTypePLSPtr(et.Elem())
65 » }
66 » switch et.Kind() {
67 » case reflect.Struct:
68 » » return multiArgTypeStruct(et)
69 » case reflect.Interface:
70 » » return multiArgTypeInterface()
71 » case reflect.Ptr:
72 » » et = et.Elem()
73 » » if et.Kind() == reflect.Struct {
74 » » » return multiArgTypeStructPtr(et)
75 » » }
76 » }
77 » if multi {
78 » » panic(fmt.Errorf("invalid argument type: []%s", et))
79 » }
80 » panic(fmt.Errorf("invalid argument type: %s", et))
81 } 80 }
82 81
83 type newKeyFunc func(kind, sid string, iid int64, par Key) Key 82 // multiArgTypePLS handles the case where et implements PropertyLoadSaver.
84 83 //
85 // multiArgTypePLS == []P 84 // This handles the special case of pointer-to-map and pointer-to-chan (
86 // *P implements PropertyLoadSaver 85 // see parseArg).
87 func multiArgTypePLS(et reflect.Type) multiArgType { 86 func multiArgTypePLS(et reflect.Type) *multiArgType {
88 ret := multiArgType{ 87 ret := multiArgType{
89 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 88 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
90 » » » return newKeyObjErr(aid, ns, slot.Addr().Interface()) 89 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
91 » » },
92 » » getPM: func(slot reflect.Value) (PropertyMap, error) {
93 » » » return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
94 » » },
95 » » getMetaPM: func(slot reflect.Value) PropertyMap {
96 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
97 » » },
98 » » setPM: func(slot reflect.Value, pm PropertyMap) error {
99 » » » return slot.Addr().Interface().(PropertyLoadSaver).Load( pm)
100 » » },
101 » » setKey: func(slot reflect.Value, k *Key) {
102 » » » PopulateKey(slot.Addr().Interface(), k)
103 » » },
104 » }
105 » if et.Kind() == reflect.Map {
106 » » ret.newElem = func() reflect.Value {
107 » » » // Create a *map so that way slot.Addr() works above whe n this is
108 » » » // called from Run(). Otherwise the map is 'unaddressabl e' according
109 » » » // to reflect. ¯\_(ツ)_/¯
110 » » » ptr := reflect.New(et)
111 » » » ptr.Elem().Set(reflect.MakeMap(et))
112 » » » return ptr.Elem()
113 » » }
114 » } else {
115 » » ret.newElem = func() reflect.Value {
116 » » » return reflect.New(et).Elem()
117 » » }
118 » }
119 » return ret
120 }
121
122 // multiArgTypePLSPtr == []*P
123 // *P implements PropertyLoadSaver
124 func multiArgTypePLSPtr(et reflect.Type) multiArgType {
125 » ret := multiArgType{
126 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
127 » » » return newKeyObjErr(aid, ns, slot.Interface())
128 }, 90 },
129 getPM: func(slot reflect.Value) (PropertyMap, error) { 91 getPM: func(slot reflect.Value) (PropertyMap, error) {
130 return slot.Interface().(PropertyLoadSaver).Save(true) 92 return slot.Interface().(PropertyLoadSaver).Save(true)
131 }, 93 },
132 getMetaPM: func(slot reflect.Value) PropertyMap { 94 getMetaPM: func(slot reflect.Value) PropertyMap {
133 return getMGS(slot.Interface()).GetAllMeta() 95 return getMGS(slot.Interface()).GetAllMeta()
134 }, 96 },
135 setPM: func(slot reflect.Value, pm PropertyMap) error { 97 setPM: func(slot reflect.Value, pm PropertyMap) error {
136 return slot.Interface().(PropertyLoadSaver).Load(pm) 98 return slot.Interface().(PropertyLoadSaver).Load(pm)
137 }, 99 },
138 setKey: func(slot reflect.Value, k *Key) { 100 setKey: func(slot reflect.Value, k *Key) {
139 PopulateKey(slot.Interface(), k) 101 PopulateKey(slot.Interface(), k)
140 }, 102 },
141 } 103 }
142 » if et.Kind() == reflect.Map { 104 » switch et.Kind() {
105 » case reflect.Map:
143 ret.newElem = func() reflect.Value { 106 ret.newElem = func() reflect.Value {
144 » » » ptr := reflect.New(et) 107 » » » return reflect.MakeMap(et)
145 » » » ptr.Elem().Set(reflect.MakeMap(et))
146 » » » return ptr
147 } 108 }
148 » } else { 109
149 » » ret.newElem = func() reflect.Value { return reflect.New(et) } 110 » case reflect.Chan:
111 » » ret.newElem = func() reflect.Value {
112 » » » return reflect.MakeChan(et, 0)
113 » » }
114
115 » case reflect.Ptr:
116 » » elem := et.Elem()
117 » » switch elem.Kind() {
118 » » case reflect.Map:
119 » » » ret.newElem = func() reflect.Value {
120 » » » » ptr := reflect.New(elem)
121 » » » » ptr.Elem().Set(reflect.MakeMap(elem))
122 » » » » return ptr
123 » » » }
124
125 » » case reflect.Chan:
126 » » » ret.newElem = func() reflect.Value {
127 » » » » ptr := reflect.New(elem)
128 » » » » ptr.Elem().Set(reflect.MakeChan(elem, 0))
129 » » » » return ptr
130 » » » }
131 » » }
150 } 132 }
151 » return ret 133
134 » if ret.newElem == nil {
135 » » ret.newElem = func() reflect.Value {
136 » » » return reflect.New(et.Elem())
137 » » }
138 » }
139 » return &ret
140 }
141
142 // multiArgTypePLSPtr handles the case where et doesn't implement
143 // PropertyLoadSaver, but a pointer to et does.
144 func multiArgTypePLSPtr(et reflect.Type) *multiArgType {
145 » return &multiArgType{
146 » » getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
147 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
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 » }
152 } 165 }
153 166
154 // multiArgTypeStruct == []S 167 // multiArgTypeStruct == []S
155 func multiArgTypeStruct(et reflect.Type) multiArgType { 168 func multiArgTypeStruct(et reflect.Type) *multiArgType {
156 cdc := getCodec(et) 169 cdc := getCodec(et)
157 toPLS := func(slot reflect.Value) *structPLS { 170 toPLS := func(slot reflect.Value) *structPLS {
158 return &structPLS{slot, cdc} 171 return &structPLS{slot, cdc}
159 } 172 }
160 » return multiArgType{ 173 » return &multiArgType{
161 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 174 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
162 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 175 » » » return newKeyObjErr(aid, ns, getMGS(slot.Addr().Interfac e()))
163 }, 176 },
164 getPM: func(slot reflect.Value) (PropertyMap, error) { 177 getPM: func(slot reflect.Value) (PropertyMap, error) {
165 return toPLS(slot).Save(true) 178 return toPLS(slot).Save(true)
166 }, 179 },
167 getMetaPM: func(slot reflect.Value) PropertyMap { 180 getMetaPM: func(slot reflect.Value) PropertyMap {
168 » » » if slot.Type().Implements(typeOfMGS) { 181 » » » return getMGS(slot.Addr().Interface()).GetAllMeta()
169 » » » » return slot.Interface().(MetaGetterSetter).GetAl lMeta()
170 » » » }
171 » » » return toPLS(slot).GetAllMeta()
172 }, 182 },
173 setPM: func(slot reflect.Value, pm PropertyMap) error { 183 setPM: func(slot reflect.Value, pm PropertyMap) error {
174 return toPLS(slot).Load(pm) 184 return toPLS(slot).Load(pm)
175 }, 185 },
176 setKey: func(slot reflect.Value, k *Key) { 186 setKey: func(slot reflect.Value, k *Key) {
177 PopulateKey(toPLS(slot), k) 187 PopulateKey(toPLS(slot), k)
178 }, 188 },
179 newElem: func() reflect.Value { 189 newElem: func() reflect.Value {
180 return reflect.New(et).Elem() 190 return reflect.New(et).Elem()
181 }, 191 },
182 } 192 }
183 } 193 }
184 194
185 // multiArgTypeStructPtr == []*S 195 // multiArgTypeStructPtr == []*S
186 func multiArgTypeStructPtr(et reflect.Type) multiArgType { 196 func multiArgTypeStructPtr(et reflect.Type) *multiArgType {
187 » cdc := getCodec(et) 197 » cdc := getCodec(et.Elem())
188 toPLS := func(slot reflect.Value) *structPLS { 198 toPLS := func(slot reflect.Value) *structPLS {
189 return &structPLS{slot.Elem(), cdc} 199 return &structPLS{slot.Elem(), cdc}
190 } 200 }
191 » return multiArgType{ 201 » return &multiArgType{
192 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 202 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
193 » » » return newKeyObjErr(aid, ns, toPLS(slot)) 203 » » » return newKeyObjErr(aid, ns, getMGS(slot.Interface()))
194 }, 204 },
195 getPM: func(slot reflect.Value) (PropertyMap, error) { 205 getPM: func(slot reflect.Value) (PropertyMap, error) {
196 return toPLS(slot).Save(true) 206 return toPLS(slot).Save(true)
197 }, 207 },
198 getMetaPM: func(slot reflect.Value) PropertyMap { 208 getMetaPM: func(slot reflect.Value) PropertyMap {
199 » » » if slot.Elem().Type().Implements(typeOfMGS) { 209 » » » return getMGS(slot.Interface()).GetAllMeta()
200 » » » » return getMGS(slot.Interface()).GetAllMeta()
201 » » » }
202 » » » return toPLS(slot).GetAllMeta()
203 }, 210 },
204 setPM: func(slot reflect.Value, pm PropertyMap) error { 211 setPM: func(slot reflect.Value, pm PropertyMap) error {
205 return toPLS(slot).Load(pm) 212 return toPLS(slot).Load(pm)
206 }, 213 },
207 setKey: func(slot reflect.Value, k *Key) { 214 setKey: func(slot reflect.Value, k *Key) {
208 PopulateKey(toPLS(slot), k) 215 PopulateKey(toPLS(slot), k)
209 }, 216 },
210 newElem: func() reflect.Value { 217 newElem: func() reflect.Value {
211 » » » return reflect.New(et) 218 » » » return reflect.New(et.Elem())
212 }, 219 },
213 } 220 }
214 } 221 }
215 222
216 // multiArgTypeInterface == []I 223 // multiArgTypeInterface == []I
217 func multiArgTypeInterface() multiArgType { 224 func multiArgTypeInterface() *multiArgType {
218 » return multiArgType{ 225 » return &multiArgType{
219 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) { 226 getKey: func(aid, ns string, slot reflect.Value) (*Key, error) {
220 » » » return newKeyObjErr(aid, ns, slot.Elem().Interface()) 227 » » » return newKeyObjErr(aid, ns, getMGS(slot.Elem().Interfac e()))
221 }, 228 },
222 getPM: func(slot reflect.Value) (PropertyMap, error) { 229 getPM: func(slot reflect.Value) (PropertyMap, error) {
223 return mkPLS(slot.Elem().Interface()).Save(true) 230 return mkPLS(slot.Elem().Interface()).Save(true)
224 }, 231 },
225 getMetaPM: func(slot reflect.Value) PropertyMap { 232 getMetaPM: func(slot reflect.Value) PropertyMap {
226 return getMGS(slot.Elem().Interface()).GetAllMeta() 233 return getMGS(slot.Elem().Interface()).GetAllMeta()
227 }, 234 },
228 setPM: func(slot reflect.Value, pm PropertyMap) error { 235 setPM: func(slot reflect.Value, pm PropertyMap) error {
229 return mkPLS(slot.Elem().Interface()).Load(pm) 236 return mkPLS(slot.Elem().Interface()).Load(pm)
230 }, 237 },
231 setKey: func(slot reflect.Value, k *Key) { 238 setKey: func(slot reflect.Value, k *Key) {
232 PopulateKey(slot.Elem().Interface(), k) 239 PopulateKey(slot.Elem().Interface(), k)
233 }, 240 },
234 } 241 }
235 } 242 }
236 243
237 func newKeyObjErr(aid, ns string, src interface{}) (*Key, error) { 244 // multiArgTypeKeyExtraction == *Key
238 » pls := getMGS(src) 245 //
239 » if key, _ := GetMetaDefault(pls, "key", nil).(*Key); key != nil { 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 }
254
255 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
256 » if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
240 return key, nil 257 return key, nil
241 } 258 }
242 259
243 // get kind 260 // get kind
244 » kind := GetMetaDefault(pls, "kind", "").(string) 261 » kind := GetMetaDefault(mgs, "kind", "").(string)
245 if kind == "" { 262 if kind == "" {
246 » » return nil, fmt.Errorf("unable to extract $kind from %T", src) 263 » » return nil, errors.New("unable to extract $kind")
247 } 264 }
248 265
249 // get id - allow both to be default for default keys 266 // get id - allow both to be default for default keys
250 » sid := GetMetaDefault(pls, "id", "").(string) 267 » sid := GetMetaDefault(mgs, "id", "").(string)
251 » iid := GetMetaDefault(pls, "id", 0).(int64) 268 » iid := GetMetaDefault(mgs, "id", 0).(int64)
252 269
253 // get parent 270 // get parent
254 » par, _ := GetMetaDefault(pls, "parent", nil).(*Key) 271 » par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
255 272
256 return NewKey(aid, ns, kind, sid, iid, par), nil 273 return NewKey(aid, ns, kind, sid, iid, par), nil
257 } 274 }
258 275
259 func mkPLS(o interface{}) PropertyLoadSaver { 276 func mkPLS(o interface{}) PropertyLoadSaver {
260 if pls, ok := o.(PropertyLoadSaver); ok { 277 if pls, ok := o.(PropertyLoadSaver); ok {
261 return pls 278 return pls
262 } 279 }
263 return GetPLS(o) 280 return GetPLS(o)
264 } 281 }
282
283 func isOKSingleType(t reflect.Type, keysOnly bool) error {
284 switch {
285 case t == nil:
286 return errors.New("no type information")
287 case t.Implements(typeOfPropertyLoadSaver):
288 return nil
289 case !keysOnly && t == typeOfKey:
290 return errors.New("not user datatype")
291 case t.Kind() != reflect.Ptr:
292 return errors.New("not a pointer")
293 case t.Elem().Kind() != reflect.Struct:
294 return errors.New("does not point to a struct")
295 default:
296 return nil
297 }
298 }
299
300 type metaMultiArgElement struct {
301 arg reflect.Value
302 mat *multiArgType
303 size int // size is -1 if this element is not a slice.
304 }
305
306 type metaMultiArg struct {
307 elems []metaMultiArgElement
308 keysOnly bool
309
310 count int // total number of elements, flattening slices
311 }
312
313 func makeMetaMultiArg(args []interface{}, keysOnly bool) (*metaMultiArg, error) {
314 mma := metaMultiArg{
315 elems: make([]metaMultiArgElement, len(args)),
316 keysOnly: keysOnly,
317 }
318
319 lme := errors.NewLazyMultiError(len(args))
320 for i, arg := range args {
321 if arg == nil {
322 lme.Assign(i, errors.New("cannot use nil as single argum ent"))
323 continue
324 }
325
326 v := reflect.ValueOf(arg)
327 vt := v.Type()
328 mma.elems[i].arg = v
329
330 // Try and treat the argument as a single-value first. This allo ws slices
331 // that implement PropertyLoadSaver to be properly treated as a single
332 // element.
333 var err error
334 isSlice := false
335 mat := parseArg(vt, keysOnly)
336 if mat == nil {
337 // If this is a slice, treat it as a slice of arg candid ates.
338 if v.Kind() == reflect.Slice {
339 isSlice = true
340 mat = parseArg(vt.Elem(), keysOnly)
341 }
342 } else {
343 // Single types need to be able to be assigned to.
344 err = isOKSingleType(vt, keysOnly)
345 }
346 if mat == nil {
347 err = errors.New("not a PLS or pointer-to-struct")
348 }
349 if err != nil {
350 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err))
351 continue
352 }
353
354 mma.elems[i].mat = mat
355 if isSlice {
356 l := v.Len()
357 mma.count += l
358 mma.elems[i].size = l
359 } else {
360 mma.count++
361 mma.elems[i].size = -1
362 }
363 }
364 if err := lme.Get(); err != nil {
365 return nil, err
366 }
367
368 return &mma, nil
369 }
370
371 func (mma *metaMultiArg) iterator(cb metaMultiArgIteratorCallback) *metaMultiArg Iterator {
372 return &metaMultiArgIterator{
373 metaMultiArg: mma,
374 cb: cb,
375 }
376 }
377
378 // getKeysPMs returns the
379 func (mma *metaMultiArg) getKeysPMs(aid, ns string, meta bool) ([]*Key, []Proper tyMap, error) {
380 var et errorTracker
381 it := mma.iterator(et.init(mma))
382
383 // Determine our flattened keys and property maps.
384 retKey := make([]*Key, mma.count)
385 var retPM []PropertyMap
386 if !mma.keysOnly {
387 retPM = make([]PropertyMap, mma.count)
388 }
389
390 for i := 0; i < mma.count; i++ {
391 it.next(func(mat *multiArgType, slot reflect.Value) error {
392 key, err := mat.getKey(aid, ns, slot)
393 if err != nil {
394 return err
395 }
396 retKey[i] = key
397
398 if !mma.keysOnly {
399 var pm PropertyMap
400 if meta {
401 pm = mat.getMetaPM(slot)
402 } else {
403 var err error
404 if pm, err = mat.getPM(slot); err != nil {
405 return err
406 }
407 }
408 retPM[i] = pm
409 }
410 return nil
411 })
412 }
413 return retKey, retPM, et.error()
414 }
415
416 type metaMultiArgIterator struct {
417 *metaMultiArg
418
419 cb metaMultiArgIteratorCallback
420
421 index int // flattened index
422 elemIdx int // current index in slice
423 slotIdx int // current index within elemIdx element (0 if single)
424 }
425
426 func (it *metaMultiArgIterator) next(fn func(*multiArgType, reflect.Value) error ) {
427 if it.remaining() <= 0 {
428 panic("out of bounds")
429 }
430
431 // Advance to the next populated element/slot.
432 elem := &it.elems[it.elemIdx]
433 if it.index > 0 {
434 for {
435 it.slotIdx++
436 if it.slotIdx >= elem.size {
437 it.elemIdx++
438 it.slotIdx = 0
439 elem = &it.elems[it.elemIdx]
440 }
441
442 // We're done iterating, unless we're on a zero-sized sl ice element.
443 if elem.size != 0 {
444 break
445 }
446 }
447 }
448
449 // Get the current slot value.
450 slot := elem.arg
451 if elem.size >= 0 {
452 // slot is a slice type, get its member.
453 slot = slot.Index(it.slotIdx)
454 }
455
456 // Execute our callback.
457 it.cb(it, fn(elem.mat, slot))
458
459 // Advance our flattened index.
460 it.index++
461 }
462
463 func (it *metaMultiArgIterator) remaining() int {
464 return it.count - it.index
465 }
466
467 type metaMultiArgIteratorCallback func(*metaMultiArgIterator, error)
468
469 type errorTracker struct {
470 elemErrors errors.MultiError
471 }
472
473 func (et *errorTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
474 return et.trackError
475 }
476
477 func (et *errorTracker) trackError(it *metaMultiArgIterator, err error) {
478 if err == nil {
479 return
480 }
481
482 if et.elemErrors == nil {
483 et.elemErrors = make(errors.MultiError, len(it.elems))
484 }
485
486 // If this is a single element, assign the error directly.
487 elem := it.elems[it.elemIdx]
488 if elem.size < 0 {
489 et.elemErrors[it.elemIdx] = err
490 } else {
491 // This is a slice element. Use a slice-sized MultiError for its element
492 // error slot, then add this error to the inner MultiError's slo t index.
493 serr, ok := et.elemErrors[it.elemIdx].(errors.MultiError)
494 if !ok {
495 serr = make(errors.MultiError, elem.size)
496 et.elemErrors[it.elemIdx] = serr
497 }
498 serr[it.slotIdx] = err
499 }
500 }
501
502 func (et *errorTracker) error() error {
503 if err := et.elemErrors; err != nil {
504 return err
505 }
506 return nil
507 }
508
509 type boolTracker struct {
510 errorTracker
511
512 res ExistsResult
513 }
514
515 func (bt *boolTracker) init(mma *metaMultiArg) metaMultiArgIteratorCallback {
516 bt.errorTracker.init(mma)
517
518 sizes := make([]int, len(mma.elems))
519 for i, e := range mma.elems {
520 if e.size < 0 {
521 sizes[i] = 1
522 } else {
523 sizes[i] = e.size
524 }
525 }
526
527 bt.res.init(sizes...)
528 return bt.trackExistsResult
529 }
530
531 func (bt *boolTracker) trackExistsResult(it *metaMultiArgIterator, err error) {
532 switch err {
533 case nil:
534 bt.res.set(it.elemIdx, it.slotIdx)
535
536 case ErrNoSuchEntity:
537 break
538
539 default:
540 // Pass through to track as MultiError.
541 bt.errorTracker.trackError(it, err)
542 }
543 }
544
545 func (bt *boolTracker) result() *ExistsResult {
546 bt.res.updateSlices()
547 return &bt.res
548 }
OLDNEW
« no previous file with comments | « service/datastore/interface.go ('k') | service/datastore/types.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698