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

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

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: more docs Created 5 years, 4 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package datastore
6
7 import (
8 "fmt"
9 "reflect"
10
11 "github.com/luci/luci-go/common/errors"
12 )
13
14 type multiArgType struct {
15 valid bool
16
17 getKey func(nk newKeyFunc, slot reflect.Value) (Key, error)
18 getPM func(slot reflect.Value) (PropertyMap, error)
19 setPM func(slot reflect.Value, pm PropertyMap) error
20 setKey func(slot reflect.Value, k Key)
21 newElem func() reflect.Value
22 }
23
24 func (mat *multiArgType) GetKeys(nk newKeyFunc, slice reflect.Value) ([]Key, err or) {
25 ret := make([]Key, slice.Len())
26 lme := errors.LazyMultiError{Size: len(ret)}
27 for i := range ret {
28 key, err := mat.getKey(nk, slice.Index(i))
29 lme.Assign(i, err)
30 ret[i] = key
31 }
32 return ret, lme.Get()
33 }
34
35 func (mat *multiArgType) GetPMs(slice reflect.Value) ([]PropertyMap, error) {
36 ret := make([]PropertyMap, slice.Len())
37 lme := errors.LazyMultiError{Size: len(ret)}
38 for i := range ret {
39 key, err := mat.getPM(slice.Index(i))
40 lme.Assign(i, err)
41 ret[i] = key
42 }
43 return ret, lme.Get()
44 }
45
46 // 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
48 // type P such that P or *P implements PropertyLoadSaver.
49 func parseMultiArg(e reflect.Type) multiArgType {
50 if e.Kind() != reflect.Slice {
51 return multiArgTypeInvalid()
52 }
53 return parseArg(e.Elem())
54 }
55
56 // parseArg checks that et is of type S, *S, I, P or *P, for some
57 // struct type S, for some interface type I, or some non-interface non-pointer
58 // type P such that P or *P implements PropertyLoadSaver.
59 func parseArg(et reflect.Type) multiArgType {
60 if reflect.PtrTo(et).Implements(typeOfPropertyLoadSaver) {
61 return multiArgTypePLS(et)
62 }
63 if et.Implements(typeOfPropertyLoadSaver) && et.Kind() != reflect.Interf ace {
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 return multiArgTypeInvalid()
78 }
79
80 type newKeyFunc func(kind, sid string, iid int64, par Key) Key
81
82 func multiArgTypeInvalid() multiArgType {
83 return multiArgType{}
84 }
85
86 // multiArgTypePLS == []P
87 // *P implements PropertyLoadSaver
88 func multiArgTypePLS(et reflect.Type) multiArgType {
89 ret := multiArgType{
90 valid: true,
91
92 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) {
93 return newKeyObjErr(nk, slot.Addr().Interface())
94 },
95 getPM: func(slot reflect.Value) (PropertyMap, error) {
96 return slot.Addr().Interface().(PropertyLoadSaver).Save( true)
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 setKey(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 valid: true,
127
128 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) {
129 return newKeyObjErr(nk, slot.Interface())
130 },
131 getPM: func(slot reflect.Value) (PropertyMap, error) {
132 return slot.Interface().(PropertyLoadSaver).Save(true)
133 },
134 setPM: func(slot reflect.Value, pm PropertyMap) error {
135 return slot.Interface().(PropertyLoadSaver).Load(pm)
136 },
137 setKey: func(slot reflect.Value, k Key) {
138 setKey(slot.Interface(), k)
139 },
140 }
141 if et.Kind() == reflect.Map {
142 ret.newElem = func() reflect.Value {
143 ptr := reflect.New(et)
144 ptr.Elem().Set(reflect.MakeMap(et))
145 return ptr
146 }
147 } else {
148 ret.newElem = func() reflect.Value { return reflect.New(et) }
149 }
150 return ret
151 }
152
153 // multiArgTypeStruct == []S
154 func multiArgTypeStruct(et reflect.Type) multiArgType {
155 cdc := getCodec(et)
156 if cdc.problem != nil {
157 return multiArgTypeInvalid()
158 }
159 toPLS := func(slot reflect.Value) PropertyLoadSaver {
160 return &structPLS{slot, cdc}
161 }
162 return multiArgType{
163 valid: true,
164
165 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) {
166 return newKeyObjErr(nk, toPLS(slot))
167 },
168 getPM: func(slot reflect.Value) (PropertyMap, error) {
169 return toPLS(slot).(PropertyLoadSaver).Save(true)
170 },
171 setPM: func(slot reflect.Value, pm PropertyMap) error {
172 return toPLS(slot).(PropertyLoadSaver).Load(pm)
173 },
174 setKey: func(slot reflect.Value, k Key) {
175 setKey(toPLS(slot), k)
176 },
177 newElem: func() reflect.Value {
178 return reflect.New(et).Elem()
179 },
180 }
181 }
182
183 // multiArgTypeStructPtr == []*S
184 func multiArgTypeStructPtr(et reflect.Type) multiArgType {
185 cdc := getCodec(et)
186 if cdc.problem != nil {
187 return multiArgTypeInvalid()
188 }
189 toPLS := func(slot reflect.Value) PropertyLoadSaver {
190 return &structPLS{slot.Elem(), cdc}
191 }
192 return multiArgType{
193 valid: true,
194
195 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) {
196 return newKeyObjErr(nk, toPLS(slot))
197 },
198 getPM: func(slot reflect.Value) (PropertyMap, error) {
199 return toPLS(slot).(PropertyLoadSaver).Save(true)
200 },
201 setPM: func(slot reflect.Value, pm PropertyMap) error {
202 return toPLS(slot).(PropertyLoadSaver).Load(pm)
203 },
204 setKey: func(slot reflect.Value, k Key) {
205 setKey(toPLS(slot), k)
206 },
207 newElem: func() reflect.Value {
208 return reflect.New(et)
209 },
210 }
211 }
212
213 // multiArgTypeInterface == []I
214 func multiArgTypeInterface() multiArgType {
215 return multiArgType{
216 valid: true,
217
218 getKey: func(nk newKeyFunc, slot reflect.Value) (Key, error) {
219 return newKeyObjErr(nk, slot.Elem().Interface())
220 },
221 getPM: func(slot reflect.Value) (PropertyMap, error) {
222 pls, _ := mkPLSName(slot.Elem().Interface())
223 return pls.Save(true)
224 },
225 setPM: func(slot reflect.Value, pm PropertyMap) error {
226 pls, _ := mkPLSName(slot.Elem().Interface())
227 return pls.Load(pm)
228 },
229 setKey: func(slot reflect.Value, k Key) {
230 setKey(slot.Elem().Interface(), k)
231 },
232 }
233 }
234
235 func newKeyObjErr(nk newKeyFunc, src interface{}) (Key, error) {
236 pls, name := mkPLSName(src)
237 if key := getMetaKey(pls, "key"); key != nil {
238 return key, nil
239 }
240
241 // get kind
242 kind := getMetaString(pls, "kind", name)
243 if kind == "" {
244 return nil, fmt.Errorf("unable to extract $kind from %v", src)
245 }
246
247 // get id - allow both to be default for default keys
248 sid := getMetaString(pls, "id", "")
249 iid := getMetaInt64(pls, "id", 0)
250
251 // get parent
252 par := getMetaKey(pls, "parent")
253
254 return nk(kind, sid, iid, par), nil
255 }
256
257 func setKey(src interface{}, key Key) {
258 pls, _ := mkPLSName(src)
259 if pls.SetMeta("key", key) == ErrMetaFieldUnset {
260 if key.StringID() != "" {
261 pls.SetMeta("id", key.StringID())
262 } else {
263 pls.SetMeta("id", key.IntID())
264 }
265 pls.SetMeta("kind", key.Kind())
266 pls.SetMeta("parent", key.Parent())
267 }
268 }
269
270 func mkPLSName(o interface{}) (PropertyLoadSaver, string) {
271 if pls, ok := o.(*structPLS); ok {
272 return pls, pls.o.Type().Name()
273 }
274 if pls, ok := o.(PropertyLoadSaver); ok {
275 return pls, ""
276 }
277 pls := GetPLS(o)
278 name := pls.(*structPLS).o.Type().Name()
279 return pls, name
280 }
281
282 func getMetaString(pls PropertyLoadSaver, key, dflt string) string {
283 mstr, err := pls.GetMeta(key)
284 ret, ok := mstr.(string)
285 if err != nil || !ok {
286 return dflt
287 }
288 return ret
289 }
290
291 func getMetaInt64(pls PropertyLoadSaver, key string, dflt int64) int64 {
292 mint, err := pls.GetMeta(key)
293 ret, ok := mint.(int64)
294 if err != nil || !ok {
295 return dflt
296 }
297 return ret
298 }
299
300 func getMetaKey(pls PropertyLoadSaver, key string) Key {
301 mkey, _ := pls.GetMeta(key)
302 ret, _ := mkey.(Key)
303 return ret
304 }
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