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

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

Issue 2302743002: Interface update, per-method Contexts. (Closed)
Patch Set: Created 4 years, 3 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
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"
9 "reflect"
10
11 "github.com/luci/luci-go/common/errors"
8 "golang.org/x/net/context" 12 "golang.org/x/net/context"
9 ) 13 )
10 14
11 // Interface is the 'user-friendly' interface to access the current filtered 15 func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat *multiArgType) {
12 // datastore service implementation. 16 badSig := func() {
13 // 17 panic(fmt.Errorf(
14 // Note that in exchange for userfriendliness, this interface ends up doing 18 "cb does not match the required callback signature: `%T` != `func(TYPE, [CursorCB]) [error]`",
15 // a lot of reflection. 19 cbIface))
16 // 20 }
17 // Methods taking 'interface{}' objects describe what a valid type for that 21
18 // interface are in the comments. 22 if cbIface == nil {
19 // 23 badSig()
20 // Struct objects passed in will be converted to PropertyLoadSaver interfaces 24 }
21 // using this package's GetPLS function. 25
22 type Interface interface { 26 // TODO(riannucci): Profile and determine if any of this is causing a re al
dnj 2016/09/01 15:25:40 Now gone. This is done for all service/* packages.
23 // AllocateIDs allows you to allocate IDs from the datastore without put ting 27 // slowdown. Could potentially cache reflection stuff by cbTyp?
24 // any data. 28 cbTyp := reflect.TypeOf(cbIface)
25 // 29
26 // A partial valid key will be constructed from each entity's kind and p arent, 30 if cbTyp.Kind() != reflect.Func {
27 // if present. An allocation will then be performed against the datastor e for 31 badSig()
28 // each key, and the partial key will be populated with a unique integer ID. 32 }
29 // The resulting keys will be applied to their objects using PopulateKey . If 33
30 // successful, any existing ID will be destroyed. 34 numIn := cbTyp.NumIn()
31 // 35 if numIn != 1 && numIn != 2 {
32 // If the object is supplied that cannot accept an integer key, this met hod 36 badSig()
33 // will panic. 37 }
34 // 38
35 // ent must be one of: 39 firstArg := cbTyp.In(0)
36 // - *S where S is a struct 40 if firstArg == typeOfKey {
37 // - *P where *P is a concrete type implementing PropertyLoadSaver 41 isKey = true
38 // - []S or []*S where S is a struct 42 } else {
39 // - []P or []*P where *P is a concrete type implementing PropertyL oadSaver 43 mat = mustParseArg(firstArg, false)
40 // - []I where i is some interface type. Each element of the slice must 44 if mat.newElem == nil {
41 // be non-nil, and its underlying type must be either *S or *P. 45 badSig()
42 // - []*Key, to populate a slice of partial-valid keys. 46 }
43 // 47 }
44 // If an error is encountered, the returned error value will depend on t he 48
45 // input arguments. If one argument is supplied, the result will be the 49 hasCursorCB = numIn == 2
46 // encountered error type. If multiple arguments are supplied, the resul t will 50 if hasCursorCB && cbTyp.In(1) != typeOfCursorCB {
47 // be a MultiError whose error index corresponds to the argument in whic h the 51 badSig()
48 // error was encountered. 52 }
49 // 53
50 // If an ent argument is a slice, its error type will be a MultiError. N ote 54 if cbTyp.NumOut() > 1 {
51 // that in the scenario where multiple slices are provided, this will re turn a 55 badSig()
52 // MultiError containing a nested MultiError for each slice argument. 56 } else if cbTyp.NumOut() == 1 && cbTyp.Out(0) != typeOfError {
53 AllocateIDs(ent ...interface{}) error 57 badSig()
54 58 }
55 // KeyForObj extracts a key from src. 59 hasErr = cbTyp.NumOut() == 1
56 // 60
57 // It is the same as KeyForObjErr, except that if KeyForObjErr would hav e 61 return
58 // returned an error, this method panics. It's safe to use if you know t hat 62 }
59 // src statically meets the metadata constraints described by KeyForObjE rr. 63
60 KeyForObj(src interface{}) *Key 64 // AllocateIDs allows you to allocate IDs from the datastore without putting
61 65 // any data.
62 // MakeKey is a convenience method for manufacturing a *Key. It should o nly be 66 //
63 // used when elems... is known statically (e.g. in the code) to be corre ct. 67 // A partial valid key will be constructed from each entity's kind and parent,
64 // 68 // if present. An allocation will then be performed against the datastore for
65 // elems is pairs of (string, string|int|int32|int64) pairs, which corre spond 69 // each key, and the partial key will be populated with a unique integer ID.
66 // to Kind/id pairs. Example: 70 // The resulting keys will be applied to their objects using PopulateKey. If
67 // dstore.MakeKey("Parent", 1, "Child", "id") 71 // successful, any existing ID will be destroyed.
68 // 72 //
69 // Would create the key: 73 // If the object is supplied that cannot accept an integer key, this method
70 // <current appID>:<current Namespace>:/Parent,1/Child,id 74 // will panic.
71 // 75 //
72 // If elems is not parsable (e.g. wrong length, wrong types, etc.) this method 76 // ent must be one of:
73 // will panic. 77 // - *S where S is a struct
74 MakeKey(elems ...interface{}) *Key 78 // - *P where *P is a concrete type implementing PropertyLoadSaver
75 79 // - []S or []*S where S is a struct
76 // NewKey constructs a new key in the current appID/Namespace, using the 80 // - []P or []*P where *P is a concrete type implementing PropertyLoadSaver
77 // specified parameters. 81 // - []I where i is some interface type. Each element of the slice must
78 NewKey(kind, stringID string, intID int64, parent *Key) *Key 82 // be non-nil, and its underlying type must be either *S or *P.
79 83 // - []*Key, to populate a slice of partial-valid keys.
80 // NewIncompleteKeys allocates count incomplete keys sharing the same ki nd and 84 //
81 // parent. It is useful as input to AllocateIDs. 85 // If an error is encountered, the returned error value will depend on the
82 NewIncompleteKeys(count int, kind string, parent *Key) []*Key 86 // input arguments. If one argument is supplied, the result will be the
83 87 // encountered error type. If multiple arguments are supplied, the result will
84 // NewKeyToks constructs a new key in the current appID/Namespace, using the 88 // be a MultiError whose error index corresponds to the argument in which the
85 // specified key tokens. 89 // error was encountered.
86 NewKeyToks([]KeyTok) *Key 90 //
87 91 // If an ent argument is a slice, its error type will be a MultiError. Note
88 // KeyForObjErr extracts a key from src. 92 // that in the scenario where multiple slices are provided, this will return a
89 // 93 // MultiError containing a nested MultiError for each slice argument.
90 // src must be one of: 94 func AllocateIDs(c context.Context, ent ...interface{}) error {
dnj 2016/09/01 15:25:40 Now top-level! This is basically just copy/paste w
91 // - *S, where S is a struct 95 if len(ent) == 0 {
92 // - a PropertyLoadSaver 96 return nil
93 // 97 }
94 // It is expected that the struct exposes the following metadata (as ret rieved 98
95 // by MetaGetter.GetMeta): 99 mma, err := makeMetaMultiArg(ent, mmaWriteKeys)
96 // - "key" (type: Key) - The full datastore key to use. Must not be ni l. 100 if err != nil {
97 // OR 101 panic(err)
98 // - "id" (type: int64 or string) - The id of the Key to create 102 }
99 // - "kind" (optional, type: string) - The kind of the Key to create. If 103
100 // blank or not present, KeyForObjErr will extract the name of the s rc 104 keys, _, err := mma.getKeysPMs(GetKeyContext(c), false)
101 // object's type. 105 if err != nil {
102 // - "parent" (optional, type: Key) - The parent key to use. 106 return err
103 // 107 }
104 // By default, the metadata will be extracted from the struct and its ta gged 108 if len(keys) == 0 {
105 // properties. However, if the struct implements MetaGetterSetter it is 109 return nil
106 // wholly responsible for exporting the required fields. A struct that 110 }
107 // implements GetMeta to make some minor tweaks can evoke the defualt be havior 111
108 // by using GetPLS(s).GetMeta. 112 // Convert each key to be partial valid, assigning an integer ID of 0. C onfirm
109 // 113 // that each object can be populated with such a key.
110 // If a required metadata item is missing or of the wrong type, then thi s will 114 for i, key := range keys {
111 // return an error. 115 keys[i] = key.Incomplete()
112 KeyForObjErr(src interface{}) (*Key, error) 116 }
113 117
114 // RunInTransaction runs f inside of a transaction. See the appengine SD K's 118 var et errorTracker
115 // documentation for full details on the behavior of transactions in the 119 it := mma.iterator(et.init(mma))
116 // datastore. 120 err = filterStop(Raw(c).AllocateIDs(keys, func(key *Key, err error) erro r {
117 // 121 it.next(func(mat *multiArgType, v reflect.Value) error {
118 // Note that the behavior of transactions may change depending on what f ilters 122 if err != nil {
119 // have been installed. It's possible that we'll end up implementing thi ngs 123 return err
120 // like nested/buffered transactions as filters. 124 }
121 RunInTransaction(f func(c context.Context) error, opts *TransactionOptio ns) error 125
122 126 if !mat.setKey(v, key) {
123 // Run executes the given query, and calls `cb` for each successfully 127 return ErrInvalidKey
124 // retrieved item. 128 }
125 // 129 return nil
126 // cb is a callback function whose signature is 130 })
127 // func(obj TYPE[, getCursor CursorCB]) [error] 131
128 // 132 return nil
129 // Where TYPE is one of: 133 }))
130 // - S or *S, where S is a struct 134 if err == nil {
131 // - P or *P, where *P is a concrete type implementing PropertyLoadSav er 135 err = et.error()
132 // - *Key (implies a keys-only query) 136
133 // 137 if err != nil && len(ent) == 1 {
134 // If the error is omitted from the signature, this will run until the q uery 138 // Single-argument Exists will return a single error.
135 // returns all its results, or has an error/times out. 139 err = errors.SingleError(err)
136 // 140 }
137 // If error is in the signature, the query will continue as long as the 141 }
138 // callback returns nil. If it returns `Stop`, the query will stop and R un 142 return err
139 // will return nil. Otherwise, the query will stop and Run will return t he 143 }
140 // user's error. 144
141 // 145 // KeyForObj extracts a key from src.
142 // Run may also stop on the first datastore error encountered, which can occur 146 //
143 // due to flakiness, timeout, etc. If it encounters such an error, it wi ll 147 // It is the same as KeyForObjErr, except that if KeyForObjErr would have
144 // be returned. 148 // returned an error, this method panics. It's safe to use if you know that
145 Run(q *Query, cb interface{}) error 149 // src statically meets the metadata constraints described by KeyForObjErr.
146 150 func KeyForObj(c context.Context, src interface{}) *Key {
147 // Count executes the given query and returns the number of entries whic h 151 ret, err := KeyForObjErr(c, src)
148 // match it. 152 if err != nil {
149 Count(q *Query) (int64, error) 153 panic(err)
150 154 }
151 // DecodeCursor converts a string returned by a Cursor into a Cursor ins tance. 155 return ret
152 // It will return an error if the supplied string is not valid, or could not 156 }
153 // be decoded by the implementation. 157
154 DecodeCursor(string) (Cursor, error) 158 // KeyForObjErr extracts a key from src.
155 159 //
156 // GetAll retrieves all of the Query results into dst. 160 // src must be one of:
157 // 161 // - *S, where S is a struct
158 // dst must be one of: 162 // - a PropertyLoadSaver
159 // - *[]S or *[]*S, where S is a struct 163 //
160 // - *[]P or *[]*P, where *P is a concrete type implementing 164 // It is expected that the struct exposes the following metadata (as retrieved
161 // PropertyLoadSaver 165 // by MetaGetter.GetMeta):
162 // - *[]*Key implies a keys-only query. 166 // - "key" (type: Key) - The full datastore key to use. Must not be nil.
163 GetAll(q *Query, dst interface{}) error 167 // OR
164 168 // - "id" (type: int64 or string) - The id of the Key to create
165 // Exists tests if the supplied objects are present in the datastore. 169 // - "kind" (optional, type: string) - The kind of the Key to create. If
166 // 170 // blank or not present, KeyForObjErr will extract the name of the src
167 // ent must be one of: 171 // object's type.
168 // - *S, where S is a struct 172 // - "parent" (optional, type: Key) - The parent key to use.
169 // - *P, where *P is a concrete type implementing PropertyLoadSaver 173 //
170 // - []S or []*S, where S is a struct 174 // By default, the metadata will be extracted from the struct and its tagged
171 // - []P or []*P, where *P is a concrete type implementing Property LoadSaver 175 // properties. However, if the struct implements MetaGetterSetter it is
172 // - []I, where I is some interface type. Each element of the slice must 176 // wholly responsible for exporting the required fields. A struct that
173 // be non-nil, and its underlying type must be either *S or *P. 177 // implements GetMeta to make some minor tweaks can evoke the defualt behavior
174 // - *Key, to check a specific key from the datastore. 178 // by using GetPLS(s).GetMeta.
175 // - []*Key, to check a slice of keys from the datastore. 179 //
176 // 180 // If a required metadata item is missing or of the wrong type, then this will
177 // If an error is encountered, the returned error value will depend on t he 181 // return an error.
178 // input arguments. If one argument is supplied, the result will be the 182 func KeyForObjErr(c context.Context, src interface{}) (*Key, error) {
179 // encountered error type. If multiple arguments are supplied, the resul t will 183 return newKeyObjErr(GetKeyContext(c), getMGS(src))
180 // be a MultiError whose error index corresponds to the argument in whic h the 184 }
181 // error was encountered. 185
182 // 186 // MakeKey is a convenience method for manufacturing a *Key. It should only be
183 // If an ent argument is a slice, its error type will be a MultiError. N ote 187 // used when elems... is known statically (e.g. in the code) to be correct.
184 // that in the scenario, where multiple slices are provided, this will r eturn a 188 //
185 // MultiError containing a nested MultiError for each slice argument. 189 // elems is pairs of (string, string|int|int32|int64) pairs, which correspond
186 Exists(ent ...interface{}) (*ExistsResult, error) 190 // to Kind/id pairs. Example:
187 191 // dstore.MakeKey("Parent", 1, "Child", "id")
188 // Does a GetMulti for thes keys and returns true iff they exist. Will o nly 192 //
189 // return an error if it's not ErrNoSuchEntity. This is slightly more 193 // Would create the key:
190 // efficient than using Get directly, because it uses the underlying 194 // <current appID>:<current Namespace>:/Parent,1/Child,id
191 // RawInterface to avoid some reflection and copies. 195 //
192 // 196 // If elems is not parsable (e.g. wrong length, wrong types, etc.) this method
193 // If an error is encountered, the returned error will be a MultiError w hose 197 // will panic.
194 // error index corresponds to the key for which the error was encountere d. 198 func MakeKey(c context.Context, elems ...interface{}) *Key {
195 // 199 kc := GetKeyContext(c)
196 // NOTE: ExistsMulti is obsolete. The vararg-accepting Exists should be used 200 return kc.MakeKey(elems...)
197 // instead. This is left for backwards compatibility, but will be remove d from 201 }
198 // this interface at some point in the future. 202
199 ExistsMulti(k []*Key) (BoolList, error) 203 // NewKey constructs a new key in the current appID/Namespace, using the
200 204 // specified parameters.
201 // Get retrieves objects from the datastore. 205 func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key {
202 // 206 kc := GetKeyContext(c)
203 // Each element in dst must be one of: 207 return kc.NewKey(kind, stringID, intID, parent)
204 // - *S, where S is a struct 208 }
205 // - *P, where *P is a concrete type implementing PropertyLoadSaver 209
206 // - []S or []*S, where S is a struct 210 // NewIncompleteKeys allocates count incomplete keys sharing the same kind and
207 // - []P or []*P, where *P is a concrete type implementing Property LoadSaver 211 // parent. It is useful as input to AllocateIDs.
208 // - []I, where I is some interface type. Each element of the slice must 212 func NewIncompleteKeys(c context.Context, count int, kind string, parent *Key) ( keys []*Key) {
209 // be non-nil, and its underlying type must be either *S or *P. 213 kc := GetKeyContext(c)
210 // 214 if count > 0 {
211 // If an error is encountered, the returned error value will depend on t he 215 keys = make([]*Key, count)
212 // input arguments. If one argument is supplied, the result will be the 216 for i := range keys {
213 // encountered error type. If multiple arguments are supplied, the resul t will 217 keys[i] = kc.NewKey(kind, "", 0, parent)
214 // be a MultiError whose error index corresponds to the argument in whic h the 218 }
215 // error was encountered. 219 }
216 // 220 return
217 // If a dst argument is a slice, its error type will be a MultiError. No te 221 }
218 // that in the scenario where multiple slices are provided, this will re turn a 222
219 // MultiError containing a nested MultiError for each slice argument. 223 // NewKeyToks constructs a new key in the current appID/Namespace, using the
220 Get(dst ...interface{}) error 224 // specified key tokens.
221 225 func NewKeyToks(c context.Context, toks []KeyTok) *Key {
222 // GetMulti retrieves items from the datastore. 226 kc := GetKeyContext(c)
223 // 227 return kc.NewKeyToks(toks)
224 // dst must be one of: 228 }
225 // - []S or []*S, where S is a struct 229
226 // - []P or []*P, where *P is a concrete type implementing PropertyLoa dSaver 230 // PopulateKey loads key into obj.
227 // - []I, where I is some interface type. Each element of the slice mu st 231 //
228 // be non-nil, and its underlying type must be either *S or *P. 232 // obj is any object that Interface.Get is able to accept.
229 // 233 //
230 // NOTE: GetMulti is obsolete. The vararg-accepting Get should be used 234 // Upon successful application, this method will return true. If the key could
231 // instead. This is left for backwards compatibility, but will be remove d from 235 // not be applied to the object, this method will return false. It will panic if
232 // this interface at some point in the future. 236 // obj is an invalid datastore model.
233 GetMulti(dst interface{}) error 237 //
234 238 // This method will panic if obj is an invalid datastore model. If the key could
235 // Put writes objects into the datastore. 239 // not be applied to the object, nothing will happen.
236 // 240 func PopulateKey(obj interface{}, key *Key) bool {
237 // src must be one of: 241 return populateKeyMGS(getMGS(obj), key)
238 // - *S, where S is a struct 242 }
239 // - *P, where *P is a concrete type implementing PropertyLoadSaver 243
240 // - []S or []*S, where S is a struct 244 func populateKeyMGS(mgs MetaGetterSetter, key *Key) bool {
241 // - []P or []*P, where *P is a concrete type implementing Property LoadSaver 245 if mgs.SetMeta("key", key) {
242 // - []I, where I is some interface type. Each element of the slice must 246 return true
243 // be non-nil, and its underlying type must be either *S or *P. 247 }
244 // 248
245 // A *Key will be extracted from src via KeyForObj. If 249 lst := key.LastTok()
246 // extractedKey.Incomplete() is true, then Put will write the resolved ( i.e. 250 if lst.StringID != "" {
247 // automatic datastore-populated) *Key back to src. 251 if !mgs.SetMeta("id", lst.StringID) {
248 // 252 return false
249 // If an error is encountered, the returned error value will depend on t he 253 }
250 // input arguments. If one argument is supplied, the result will be the 254 } else {
251 // encountered error type. If multiple arguments are supplied, the resul t will 255 if !mgs.SetMeta("id", lst.IntID) {
252 // be a MultiError whose error index corresponds to the argument in whic h the 256 return false
253 // error was encountered. 257 }
254 // 258 }
255 // If a src argument is a slice, its error type will be a MultiError. No te 259
256 // that in the scenario where multiple slices are provided, this will re turn a 260 mgs.SetMeta("kind", lst.Kind)
257 // MultiError containing a nested MultiError for each slice argument. 261 mgs.SetMeta("parent", key.Parent())
258 Put(src ...interface{}) error 262 return true
259 263 }
260 // PutMulti writes items to the datastore. 264
261 // 265 // RunInTransaction runs f inside of a transaction. See the appengine SDK's
262 // src must be one of: 266 // documentation for full details on the behavior of transactions in the
263 // - []S or []*S, where S is a struct 267 // datastore.
264 // - []P or []*P, where *P is a concrete type implementing Property LoadSaver 268 //
265 // - []I, where I is some interface type. Each element of the slice must 269 // Note that the behavior of transactions may change depending on what filters
266 // be non-nil, and its underlying type must be either *S or *P. 270 // have been installed. It's possible that we'll end up implementing things
267 // 271 // like nested/buffered transactions as filters.
268 // If items in src resolve to Incomplete keys, PutMulti will write the 272 func RunInTransaction(c context.Context, f func(c context.Context) error, opts * TransactionOptions) error {
269 // resolved keys back to the items in src. 273 return Raw(c).RunInTransaction(f, opts)
270 // 274 }
271 // NOTE: PutMulti is obsolete. The vararg-accepting Put should be used 275
272 // instead. This is left for backwards compatibility, but will be remove d from 276 // Run executes the given query, and calls `cb` for each successfully
273 // this interface at some point in the future. 277 // retrieved item.
274 PutMulti(src interface{}) error 278 //
275 279 // cb is a callback function whose signature is
276 // Delete removes the supplied entities from the datastore. 280 // func(obj TYPE[, getCursor CursorCB]) [error]
277 // 281 //
278 // ent must be one of: 282 // Where TYPE is one of:
279 // - *S, where S is a struct 283 // - S or *S, where S is a struct
280 // - *P, where *P is a concrete type implementing PropertyLoadSaver 284 // - P or *P, where *P is a concrete type implementing PropertyLoadSaver
281 // - []S or []*S, where S is a struct 285 // - *Key (implies a keys-only query)
282 // - []P or []*P, where *P is a concrete type implementing Property LoadSaver 286 //
283 // - []I, where I is some interface type. Each element of the slice must 287 // If the error is omitted from the signature, this will run until the query
284 // be non-nil, and its underlying type must be either *S or *P. 288 // returns all its results, or has an error/times out.
285 // - *Key, to remove a specific key from the datastore. 289 //
286 // - []*Key, to remove a slice of keys from the datastore. 290 // If error is in the signature, the query will continue as long as the
287 // 291 // callback returns nil. If it returns `Stop`, the query will stop and Run
288 // If an error is encountered, the returned error value will depend on t he 292 // will return nil. Otherwise, the query will stop and Run will return the
289 // input arguments. If one argument is supplied, the result will be the 293 // user's error.
290 // encountered error type. If multiple arguments are supplied, the resul t will 294 //
291 // be a MultiError whose error index corresponds to the argument in whic h the 295 // Run may also stop on the first datastore error encountered, which can occur
292 // error was encountered. 296 // due to flakiness, timeout, etc. If it encounters such an error, it will
293 // 297 // be returned.
294 // If an ent argument is a slice, its error type will be a MultiError. N ote 298 func Run(c context.Context, q *Query, cb interface{}) error {
295 // that in the scenario where multiple slices are provided, this will re turn a 299 isKey, hasErr, hasCursorCB, mat := runParseCallback(cb)
296 // MultiError containing a nested MultiError for each slice argument. 300
297 Delete(ent ...interface{}) error 301 if isKey {
298 302 q = q.KeysOnly(true)
299 // DeleteMulti removes keys from the datastore. 303 }
300 // 304 fq, err := q.Finalize()
301 // If an error is encountered, the returned error will be a MultiError w hose 305 if err != nil {
302 // error index corresponds to the key for which the error was encountere d. 306 return err
303 // 307 }
304 // NOTE: DeleteMulti is obsolete. The vararg-accepting Delete should be used 308
305 // instead. This is left for backwards compatibility, but will be remove d from 309 cbVal := reflect.ValueOf(cb)
306 // this interface at some point in the future. 310 var cbFunc func(reflect.Value, CursorCB) error
307 DeleteMulti(keys []*Key) error 311 switch {
308 312 case hasErr && hasCursorCB:
309 // Testable returns the Testable interface for the implementation, or ni l if 313 cbFunc = func(v reflect.Value, cb CursorCB) error {
310 // there is none. 314 err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb) })[0].Interface()
311 Testable() Testable 315 if err != nil {
312 316 return err.(error)
313 // Raw returns the underlying RawInterface. The Interface and RawInterfa ce may 317 }
314 // be used interchangably; there's no danger of interleaving access to t he 318 return nil
315 // datastore via the two. 319 }
316 Raw() RawInterface 320
317 } 321 case hasErr && !hasCursorCB:
322 cbFunc = func(v reflect.Value, _ CursorCB) error {
323 err := cbVal.Call([]reflect.Value{v})[0].Interface()
324 if err != nil {
325 return err.(error)
326 }
327 return nil
328 }
329
330 case !hasErr && hasCursorCB:
331 cbFunc = func(v reflect.Value, cb CursorCB) error {
332 cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)})
333 return nil
334 }
335
336 case !hasErr && !hasCursorCB:
337 cbFunc = func(v reflect.Value, _ CursorCB) error {
338 cbVal.Call([]reflect.Value{v})
339 return nil
340 }
341 }
342
343 raw := Raw(c)
344 if isKey {
345 err = raw.Run(fq, func(k *Key, _ PropertyMap, gc CursorCB) error {
346 return cbFunc(reflect.ValueOf(k), gc)
347 })
348 } else {
349 err = raw.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) erro r {
350 itm := mat.newElem()
351 if err := mat.setPM(itm, pm); err != nil {
352 return err
353 }
354 mat.setKey(itm, k)
355 return cbFunc(itm, gc)
356 })
357 }
358 return filterStop(err)
359 }
360
361 // Count executes the given query and returns the number of entries which
362 // match it.
363 func Count(c context.Context, q *Query) (int64, error) {
364 fq, err := q.Finalize()
365 if err != nil {
366 return 0, err
367 }
368 v, err := Raw(c).Count(fq)
369 return v, filterStop(err)
370 }
371
372 // DecodeCursor converts a string returned by a Cursor into a Cursor instance.
373 // It will return an error if the supplied string is not valid, or could not
374 // be decoded by the implementation.
375 func DecodeCursor(c context.Context, s string) (Cursor, error) {
376 return Raw(c).DecodeCursor(s)
377 }
378
379 // GetAll retrieves all of the Query results into dst.
380 //
381 // dst must be one of:
382 // - *[]S or *[]*S, where S is a struct
383 // - *[]P or *[]*P, where *P is a concrete type implementing
384 // PropertyLoadSaver
385 // - *[]*Key implies a keys-only query.
386 func GetAll(c context.Context, q *Query, dst interface{}) error {
387 v := reflect.ValueOf(dst)
388 if v.Kind() != reflect.Ptr {
389 panic(fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst))
390 }
391 if !v.IsValid() || v.IsNil() {
392 panic(errors.New("invalid GetAll dst: <nil>"))
393 }
394
395 raw := Raw(c)
396 if keys, ok := dst.(*[]*Key); ok {
397 fq, err := q.KeysOnly(true).Finalize()
398 if err != nil {
399 return err
400 }
401
402 return raw.Run(fq, func(k *Key, _ PropertyMap, _ CursorCB) error {
403 *keys = append(*keys, k)
404 return nil
405 })
406 }
407 fq, err := q.Finalize()
408 if err != nil {
409 return err
410 }
411
412 slice := v.Elem()
413 mat := mustParseMultiArg(slice.Type())
414 if mat.newElem == nil {
415 panic(fmt.Errorf("invalid GetAll dst (non-concrete element type) : %T", dst))
416 }
417
418 errs := map[int]error{}
419 i := 0
420 err = filterStop(raw.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) er ror {
421 slice.Set(reflect.Append(slice, mat.newElem()))
422 itm := slice.Index(i)
423 mat.setKey(itm, k)
424 err := mat.setPM(itm, pm)
425 if err != nil {
426 errs[i] = err
427 }
428 i++
429 return nil
430 }))
431 if err == nil {
432 if len(errs) > 0 {
433 me := make(errors.MultiError, slice.Len())
434 for i, e := range errs {
435 me[i] = e
436 }
437 err = me
438 }
439 }
440 return err
441 }
442
443 // Exists tests if the supplied objects are present in the datastore.
444 //
445 // ent must be one of:
446 // - *S, where S is a struct
447 // - *P, where *P is a concrete type implementing PropertyLoadSaver
448 // - []S or []*S, where S is a struct
449 // - []P or []*P, where *P is a concrete type implementing PropertyLoadSave r
450 // - []I, where I is some interface type. Each element of the slice must
451 // be non-nil, and its underlying type must be either *S or *P.
452 // - *Key, to check a specific key from the datastore.
453 // - []*Key, to check a slice of keys from the datastore.
454 //
455 // If an error is encountered, the returned error value will depend on the
456 // input arguments. If one argument is supplied, the result will be the
457 // encountered error type. If multiple arguments are supplied, the result will
458 // be a MultiError whose error index corresponds to the argument in which the
459 // error was encountered.
460 //
461 // If an ent argument is a slice, its error type will be a MultiError. Note
462 // that in the scenario, where multiple slices are provided, this will return a
463 // MultiError containing a nested MultiError for each slice argument.
464 func Exists(c context.Context, ent ...interface{}) (*ExistsResult, error) {
465 if len(ent) == 0 {
466 return nil, nil
467 }
468
469 mma, err := makeMetaMultiArg(ent, mmaKeysOnly)
470 if err != nil {
471 panic(err)
472 }
473
474 keys, _, err := mma.getKeysPMs(GetKeyContext(c), false)
475 if err != nil {
476 return nil, err
477 }
478 if len(keys) == 0 {
479 return nil, nil
480 }
481
482 var bt boolTracker
483 it := mma.iterator(bt.init(mma))
484 err = filterStop(Raw(c).GetMulti(keys, nil, func(_ PropertyMap, err erro r) error {
485 it.next(func(*multiArgType, reflect.Value) error {
486 return err
487 })
488 return nil
489 }))
490 if err == nil {
491 err = bt.error()
492
493 if err != nil && len(ent) == 1 {
494 // Single-argument Exists will return a single error.
495 err = errors.SingleError(err)
496 }
497 }
498 return bt.result(), err
499 }
500
501 // Get retrieves objects from the datastore.
502 //
503 // Each element in dst must be one of:
504 // - *S, where S is a struct
505 // - *P, where *P is a concrete type implementing PropertyLoadSaver
506 // - []S or []*S, where S is a struct
507 // - []P or []*P, where *P is a concrete type implementing PropertyLoadSave r
508 // - []I, where I is some interface type. Each element of the slice must
509 // be non-nil, and its underlying type must be either *S or *P.
510 //
511 // If an error is encountered, the returned error value will depend on the
512 // input arguments. If one argument is supplied, the result will be the
513 // encountered error type. If multiple arguments are supplied, the result will
514 // be a MultiError whose error index corresponds to the argument in which the
515 // error was encountered.
516 //
517 // If a dst argument is a slice, its error type will be a MultiError. Note
518 // that in the scenario where multiple slices are provided, this will return a
519 // MultiError containing a nested MultiError for each slice argument.
520 func Get(c context.Context, dst ...interface{}) error {
521 if len(dst) == 0 {
522 return nil
523 }
524
525 mma, err := makeMetaMultiArg(dst, mmaReadWrite)
526 if err != nil {
527 panic(err)
528 }
529
530 keys, pms, err := mma.getKeysPMs(GetKeyContext(c), true)
531 if err != nil {
532 return err
533 }
534 if len(keys) == 0 {
535 return nil
536 }
537
538 var et errorTracker
539 it := mma.iterator(et.init(mma))
540 meta := NewMultiMetaGetter(pms)
541 err = filterStop(Raw(c).GetMulti(keys, meta, func(pm PropertyMap, err er ror) error {
542 it.next(func(mat *multiArgType, slot reflect.Value) error {
543 if err != nil {
544 return err
545 }
546 return mat.setPM(slot, pm)
547 })
548 return nil
549 }))
550
551 if err == nil {
552 err = et.error()
553
554 if err != nil && len(dst) == 1 {
555 // Single-argument Get will return a single error.
556 err = errors.SingleError(err)
557 }
558 }
559 return err
560 }
561
562 // Put writes objects into the datastore.
563 //
564 // src must be one of:
565 // - *S, where S is a struct
566 // - *P, where *P is a concrete type implementing PropertyLoadSaver
567 // - []S or []*S, where S is a struct
568 // - []P or []*P, where *P is a concrete type implementing PropertyLoadSave r
569 // - []I, where I is some interface type. Each element of the slice must
570 // be non-nil, and its underlying type must be either *S or *P.
571 //
572 // A *Key will be extracted from src via KeyForObj. If
573 // extractedKey.Incomplete() is true, then Put will write the resolved (i.e.
574 // automatic datastore-populated) *Key back to src.
575 //
576 // If an error is encountered, the returned error value will depend on the
577 // input arguments. If one argument is supplied, the result will be the
578 // encountered error type. If multiple arguments are supplied, the result will
579 // be a MultiError whose error index corresponds to the argument in which the
580 // error was encountered.
581 //
582 // If a src argument is a slice, its error type will be a MultiError. Note
583 // that in the scenario where multiple slices are provided, this will return a
584 // MultiError containing a nested MultiError for each slice argument.
585 func Put(c context.Context, src ...interface{}) error {
586 if len(src) == 0 {
587 return nil
588 }
589
590 mma, err := makeMetaMultiArg(src, mmaReadWrite)
591 if err != nil {
592 panic(err)
593 }
594
595 keys, vals, err := mma.getKeysPMs(GetKeyContext(c), false)
596 if err != nil {
597 return err
598 }
599 if len(keys) == 0 {
600 return nil
601 }
602
603 i := 0
604 var et errorTracker
605 it := mma.iterator(et.init(mma))
606 err = filterStop(Raw(c).PutMulti(keys, vals, func(key *Key, err error) e rror {
607 it.next(func(mat *multiArgType, slot reflect.Value) error {
608 if err != nil {
609 return err
610 }
611 if key != keys[i] {
612 mat.setKey(slot, key)
613 }
614 return nil
615 })
616
617 i++
618 return nil
619 }))
620
621 if err == nil {
622 err = et.error()
623
624 if err != nil && len(src) == 1 {
625 // Single-argument Put will return a single error.
626 err = errors.SingleError(err)
627 }
628 }
629 return err
630 }
631
632 // Delete removes the supplied entities from the datastore.
633 //
634 // ent must be one of:
635 // - *S, where S is a struct
636 // - *P, where *P is a concrete type implementing PropertyLoadSaver
637 // - []S or []*S, where S is a struct
638 // - []P or []*P, where *P is a concrete type implementing PropertyLoadSave r
639 // - []I, where I is some interface type. Each element of the slice must
640 // be non-nil, and its underlying type must be either *S or *P.
641 // - *Key, to remove a specific key from the datastore.
642 // - []*Key, to remove a slice of keys from the datastore.
643 //
644 // If an error is encountered, the returned error value will depend on the
645 // input arguments. If one argument is supplied, the result will be the
646 // encountered error type. If multiple arguments are supplied, the result will
647 // be a MultiError whose error index corresponds to the argument in which the
648 // error was encountered.
649 //
650 // If an ent argument is a slice, its error type will be a MultiError. Note
651 // that in the scenario where multiple slices are provided, this will return a
652 // MultiError containing a nested MultiError for each slice argument.
653 func Delete(c context.Context, ent ...interface{}) error {
654 if len(ent) == 0 {
655 return nil
656 }
657
658 mma, err := makeMetaMultiArg(ent, mmaKeysOnly)
659 if err != nil {
660 panic(err)
661 }
662
663 keys, _, err := mma.getKeysPMs(GetKeyContext(c), false)
664 if err != nil {
665 return err
666 }
667 if len(keys) == 0 {
668 return nil
669 }
670
671 var et errorTracker
672 it := mma.iterator(et.init(mma))
673 err = filterStop(Raw(c).DeleteMulti(keys, func(err error) error {
674 it.next(func(*multiArgType, reflect.Value) error {
675 return err
676 })
677
678 return nil
679 }))
680 if err == nil {
681 err = et.error()
682
683 if err != nil && len(ent) == 1 {
684 // Single-argument Delete will return a single error.
685 err = errors.SingleError(err)
686 }
687 }
688 return err
689 }
690
691 // GetTestable returns the Testable interface for the implementation, or nil if
692 // there is none.
693 func GetTestable(c context.Context) Testable {
694 return Raw(c).GetTestable()
695 }
696
697 func filterStop(err error) error {
698 if err == Stop {
699 err = nil
700 }
701 return err
702 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698