| 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" | 
 |    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 | 
|   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 { | 
|   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 maybeSingleError(err, ent) | 
|  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         return maybeSingleError(err, ent) | 
|  134         // If the error is omitted from the signature, this will run until the q
     uery |  138 } | 
|  135         // returns all its results, or has an error/times out. |  139  | 
|  136         // |  140 // KeyForObj extracts a key from src. | 
|  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 // It is the same as KeyForObjErr, except that if KeyForObjErr would have | 
|  139         // will return nil. Otherwise, the query will stop and Run will return t
     he |  143 // returned an error, this method panics. It's safe to use if you know that | 
|  140         // user's error. |  144 // src statically meets the metadata constraints described by KeyForObjErr. | 
|  141         // |  145 func KeyForObj(c context.Context, src interface{}) *Key { | 
|  142         // Run may also stop on the first datastore error encountered, which can
      occur |  146         ret, err := KeyForObjErr(c, src) | 
|  143         // due to flakiness, timeout, etc. If it encounters such an error, it wi
     ll |  147         if err != nil { | 
|  144         // be returned. |  148                 panic(err) | 
|  145         Run(q *Query, cb interface{}) error |  149         } | 
|  146  |  150         return ret | 
|  147         // Count executes the given query and returns the number of entries whic
     h |  151 } | 
|  148         // match it. |  152  | 
|  149         Count(q *Query) (int64, error) |  153 // KeyForObjErr extracts a key from src. | 
|  150  |  154 // | 
|  151         // DecodeCursor converts a string returned by a Cursor into a Cursor ins
     tance. |  155 // src must be one of: | 
|  152         // It will return an error if the supplied string is not valid, or could
      not |  156 //   - *S, where S is a struct | 
|  153         // be decoded by the implementation. |  157 //   - a PropertyLoadSaver | 
|  154         DecodeCursor(string) (Cursor, error) |  158 // | 
|  155  |  159 // It is expected that the struct exposes the following metadata (as retrieved | 
|  156         // GetAll retrieves all of the Query results into dst. |  160 // by MetaGetter.GetMeta): | 
|  157         // |  161 //   - "key" (type: Key) - The full datastore key to use. Must not be nil. | 
|  158         // dst must be one of: |  162 //     OR | 
|  159         //   - *[]S or *[]*S, where S is a struct |  163 //   - "id" (type: int64 or string) - The id of the Key to create | 
|  160         //   - *[]P or *[]*P, where *P is a concrete type implementing |  164 //   - "kind" (optional, type: string) - The kind of the Key to create. If | 
|  161         //     PropertyLoadSaver |  165 //     blank or not present, KeyForObjErr will extract the name of the src | 
|  162         //   - *[]*Key implies a keys-only query. |  166 //     object's type. | 
|  163         GetAll(q *Query, dst interface{}) error |  167 //   - "parent" (optional, type: Key) - The parent key to use. | 
|  164  |  168 // | 
|  165         // Exists tests if the supplied objects are present in the datastore. |  169 // By default, the metadata will be extracted from the struct and its tagged | 
|  166         // |  170 // properties. However, if the struct implements MetaGetterSetter it is | 
|  167         // ent must be one of: |  171 // wholly responsible for exporting the required fields. A struct that | 
|  168         //      - *S, where S is a struct |  172 // implements GetMeta to make some minor tweaks can evoke the defualt behavior | 
|  169         //      - *P, where *P is a concrete type implementing PropertyLoadSaver |  173 // by using GetPLS(s).GetMeta. | 
|  170         //      - []S or []*S, where S is a struct |  174 // | 
|  171         //      - []P or []*P, where *P is a concrete type implementing Property
     LoadSaver |  175 // If a required metadata item is missing or of the wrong type, then this will | 
|  172         //      - []I, where I is some interface type. Each element of the slice
      must |  176 // return an error. | 
|  173         //        be non-nil, and its underlying type must be either *S or *P. |  177 func KeyForObjErr(c context.Context, src interface{}) (*Key, error) { | 
|  174         //      - *Key, to check a specific key from the datastore. |  178         return newKeyObjErr(GetKeyContext(c), getMGS(src)) | 
|  175         //      - []*Key, to check a slice of keys from the datastore. |  179 } | 
|  176         // |  180  | 
|  177         // If an error is encountered, the returned error value will depend on t
     he |  181 // MakeKey is a convenience method for manufacturing a *Key. It should only be | 
|  178         // input arguments. If one argument is supplied, the result will be the |  182 // used when elems... is known statically (e.g. in the code) to be correct. | 
|  179         // encountered error type. If multiple arguments are supplied, the resul
     t will |  183 // | 
|  180         // be a MultiError whose error index corresponds to the argument in whic
     h the |  184 // elems is pairs of (string, string|int|int32|int64) pairs, which correspond | 
|  181         // error was encountered. |  185 // to Kind/id pairs. Example: | 
|  182         // |  186 //   dstore.MakeKey("Parent", 1, "Child", "id") | 
|  183         // If an ent argument is a slice, its error type will be a MultiError. N
     ote |  187 // | 
|  184         // that in the scenario, where multiple slices are provided, this will r
     eturn a |  188 // Would create the key: | 
|  185         // MultiError containing a nested MultiError for each slice argument. |  189 //   <current appID>:<current Namespace>:/Parent,1/Child,id | 
|  186         Exists(ent ...interface{}) (*ExistsResult, error) |  190 // | 
|  187  |  191 // If elems is not parsable (e.g. wrong length, wrong types, etc.) this method | 
|  188         // Does a GetMulti for thes keys and returns true iff they exist. Will o
     nly |  192 // will panic. | 
|  189         // return an error if it's not ErrNoSuchEntity. This is slightly more |  193 func MakeKey(c context.Context, elems ...interface{}) *Key { | 
|  190         // efficient than using Get directly, because it uses the underlying |  194         kc := GetKeyContext(c) | 
|  191         // RawInterface to avoid some reflection and copies. |  195         return kc.MakeKey(elems...) | 
|  192         // |  196 } | 
|  193         // If an error is encountered, the returned error will be a MultiError w
     hose |  197  | 
|  194         // error index corresponds to the key for which the error was encountere
     d. |  198 // NewKey constructs a new key in the current appID/Namespace, using the | 
|  195         // |  199 // specified parameters. | 
|  196         // NOTE: ExistsMulti is obsolete. The vararg-accepting Exists should be 
     used |  200 func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) 
     *Key { | 
|  197         // instead. This is left for backwards compatibility, but will be remove
     d from |  201         kc := GetKeyContext(c) | 
|  198         // this interface at some point in the future. |  202         return kc.NewKey(kind, stringID, intID, parent) | 
|  199         ExistsMulti(k []*Key) (BoolList, error) |  203 } | 
|  200  |  204  | 
|  201         // Get retrieves objects from the datastore. |  205 // NewIncompleteKeys allocates count incomplete keys sharing the same kind and | 
|  202         // |  206 // parent. It is useful as input to AllocateIDs. | 
|  203         // Each element in dst must be one of: |  207 func NewIncompleteKeys(c context.Context, count int, kind string, parent *Key) (
     keys []*Key) { | 
|  204         //      - *S, where S is a struct |  208         kc := GetKeyContext(c) | 
|  205         //      - *P, where *P is a concrete type implementing PropertyLoadSaver |  209         if count > 0 { | 
|  206         //      - []S or []*S, where S is a struct |  210                 keys = make([]*Key, count) | 
|  207         //      - []P or []*P, where *P is a concrete type implementing Property
     LoadSaver |  211                 for i := range keys { | 
|  208         //      - []I, where I is some interface type. Each element of the slice
      must |  212                         keys[i] = kc.NewKey(kind, "", 0, parent) | 
|  209         //        be non-nil, and its underlying type must be either *S or *P. |  213                 } | 
|  210         // |  214         } | 
|  211         // If an error is encountered, the returned error value will depend on t
     he |  215         return | 
|  212         // input arguments. If one argument is supplied, the result will be the |  216 } | 
|  213         // encountered error type. If multiple arguments are supplied, the resul
     t will |  217  | 
|  214         // be a MultiError whose error index corresponds to the argument in whic
     h the |  218 // NewKeyToks constructs a new key in the current appID/Namespace, using the | 
|  215         // error was encountered. |  219 // specified key tokens. | 
|  216         // |  220 func NewKeyToks(c context.Context, toks []KeyTok) *Key { | 
|  217         // If a dst argument is a slice, its error type will be a MultiError. No
     te |  221         kc := GetKeyContext(c) | 
|  218         // that in the scenario where multiple slices are provided, this will re
     turn a |  222         return kc.NewKeyToks(toks) | 
|  219         // MultiError containing a nested MultiError for each slice argument. |  223 } | 
|  220         Get(dst ...interface{}) error |  224  | 
|  221  |  225 // PopulateKey loads key into obj. | 
|  222         // GetMulti retrieves items from the datastore. |  226 // | 
|  223         // |  227 // obj is any object that Interface.Get is able to accept. | 
|  224         // dst must be one of: |  228 // | 
|  225         //   - []S or []*S, where S is a struct |  229 // Upon successful application, this method will return true. If the key could | 
|  226         //   - []P or []*P, where *P is a concrete type implementing PropertyLoa
     dSaver |  230 // not be applied to the object, this method will return false. It will panic if | 
|  227         //   - []I, where I is some interface type. Each element of the slice mu
     st |  231 // obj is an invalid datastore model. | 
|  228         //     be non-nil, and its underlying type must be either *S or *P. |  232 // | 
|  229         // |  233 // This method will panic if obj is an invalid datastore model. If the key could | 
|  230         // NOTE: GetMulti is obsolete. The vararg-accepting Get should be used |  234 // not be applied to the object, nothing will happen. | 
|  231         // instead. This is left for backwards compatibility, but will be remove
     d from |  235 func PopulateKey(obj interface{}, key *Key) bool { | 
|  232         // this interface at some point in the future. |  236         return populateKeyMGS(getMGS(obj), key) | 
|  233         GetMulti(dst interface{}) error |  237 } | 
|  234  |  238  | 
|  235         // Put writes objects into the datastore. |  239 func populateKeyMGS(mgs MetaGetterSetter, key *Key) bool { | 
|  236         // |  240         if mgs.SetMeta("key", key) { | 
|  237         // src must be one of: |  241                 return true | 
|  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         lst := key.LastTok() | 
|  241         //      - []P or []*P, where *P is a concrete type implementing Property
     LoadSaver |  245         if lst.StringID != "" { | 
|  242         //      - []I, where I is some interface type. Each element of the slice
      must |  246                 if !mgs.SetMeta("id", lst.StringID) { | 
|  243         //        be non-nil, and its underlying type must be either *S or *P. |  247                         return false | 
|  244         // |  248                 } | 
|  245         // A *Key will be extracted from src via KeyForObj. If |  249         } else { | 
|  246         // extractedKey.Incomplete() is true, then Put will write the resolved (
     i.e. |  250                 if !mgs.SetMeta("id", lst.IntID) { | 
|  247         // automatic datastore-populated) *Key back to src. |  251                         return false | 
|  248         // |  252                 } | 
|  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  | 
|  251         // encountered error type. If multiple arguments are supplied, the resul
     t will |  255         mgs.SetMeta("kind", lst.Kind) | 
|  252         // be a MultiError whose error index corresponds to the argument in whic
     h the |  256         mgs.SetMeta("parent", key.Parent()) | 
|  253         // error was encountered. |  257         return true | 
|  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 // RunInTransaction runs f inside of a transaction. See the appengine SDK's | 
|  257         // MultiError containing a nested MultiError for each slice argument. |  261 // documentation for full details on the behavior of transactions in the | 
|  258         Put(src ...interface{}) error |  262 // datastore. | 
|  259  |  263 // | 
|  260         // PutMulti writes items to the datastore. |  264 // Note that the behavior of transactions may change depending on what filters | 
|  261         // |  265 // have been installed. It's possible that we'll end up implementing things | 
|  262         // src must be one of: |  266 // like nested/buffered transactions as filters. | 
|  263         //      - []S or []*S, where S is a struct |  267 func RunInTransaction(c context.Context, f func(c context.Context) error, opts *
     TransactionOptions) error { | 
|  264         //      - []P or []*P, where *P is a concrete type implementing Property
     LoadSaver |  268         return Raw(c).RunInTransaction(f, opts) | 
|  265         //      - []I, where I is some interface type. Each element of the slice
      must |  269 } | 
|  266         //        be non-nil, and its underlying type must be either *S or *P. |  270  | 
|  267         // |  271 // Run executes the given query, and calls `cb` for each successfully | 
|  268         // If items in src resolve to Incomplete keys, PutMulti will write the |  272 // retrieved item. | 
|  269         // resolved keys back to the items in src. |  273 // | 
|  270         // |  274 // cb is a callback function whose signature is | 
|  271         // NOTE: PutMulti is obsolete. The vararg-accepting Put should be used |  275 //   func(obj TYPE[, getCursor CursorCB]) [error] | 
|  272         // instead. This is left for backwards compatibility, but will be remove
     d from |  276 // | 
|  273         // this interface at some point in the future. |  277 // Where TYPE is one of: | 
|  274         PutMulti(src interface{}) error |  278 //   - S or *S, where S is a struct | 
|  275  |  279 //   - P or *P, where *P is a concrete type implementing PropertyLoadSaver | 
|  276         // Delete removes the supplied entities from the datastore. |  280 //   - *Key (implies a keys-only query) | 
|  277         // |  281 // | 
|  278         // ent must be one of: |  282 // If the error is omitted from the signature, this will run until the query | 
|  279         //      - *S, where S is a struct |  283 // returns all its results, or has an error/times out. | 
|  280         //      - *P, where *P is a concrete type implementing PropertyLoadSaver |  284 // | 
|  281         //      - []S or []*S, where S is a struct |  285 // If error is in the signature, the query will continue as long as the | 
|  282         //      - []P or []*P, where *P is a concrete type implementing Property
     LoadSaver |  286 // callback returns nil. If it returns `Stop`, the query will stop and Run | 
|  283         //      - []I, where I is some interface type. Each element of the slice
      must |  287 // will return nil. Otherwise, the query will stop and Run will return the | 
|  284         //        be non-nil, and its underlying type must be either *S or *P. |  288 // user's error. | 
|  285         //      - *Key, to remove a specific key from the datastore. |  289 // | 
|  286         //      - []*Key, to remove a slice of keys from the datastore. |  290 // Run may also stop on the first datastore error encountered, which can occur | 
|  287         // |  291 // due to flakiness, timeout, etc. If it encounters such an error, it will | 
|  288         // If an error is encountered, the returned error value will depend on t
     he |  292 // be returned. | 
|  289         // input arguments. If one argument is supplied, the result will be the |  293 func Run(c context.Context, q *Query, cb interface{}) error { | 
|  290         // encountered error type. If multiple arguments are supplied, the resul
     t will |  294         isKey, hasErr, hasCursorCB, mat := runParseCallback(cb) | 
|  291         // be a MultiError whose error index corresponds to the argument in whic
     h the |  295  | 
|  292         // error was encountered. |  296         if isKey { | 
|  293         // |  297                 q = q.KeysOnly(true) | 
|  294         // If an ent argument is a slice, its error type will be a MultiError. N
     ote |  298         } | 
|  295         // that in the scenario where multiple slices are provided, this will re
     turn a |  299         fq, err := q.Finalize() | 
|  296         // MultiError containing a nested MultiError for each slice argument. |  300         if err != nil { | 
|  297         Delete(ent ...interface{}) error |  301                 return err | 
|  298  |  302         } | 
|  299         // DeleteMulti removes keys from the datastore. |  303  | 
|  300         // |  304         cbVal := reflect.ValueOf(cb) | 
|  301         // If an error is encountered, the returned error will be a MultiError w
     hose |  305         var cbFunc func(reflect.Value, CursorCB) error | 
|  302         // error index corresponds to the key for which the error was encountere
     d. |  306         switch { | 
|  303         // |  307         case hasErr && hasCursorCB: | 
|  304         // NOTE: DeleteMulti is obsolete. The vararg-accepting Delete should be 
     used |  308                 cbFunc = func(v reflect.Value, cb CursorCB) error { | 
|  305         // instead. This is left for backwards compatibility, but will be remove
     d from |  309                         err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)
     })[0].Interface() | 
|  306         // this interface at some point in the future. |  310                         if err != nil { | 
|  307         DeleteMulti(keys []*Key) error |  311                                 return err.(error) | 
|  308  |  312                         } | 
|  309         // Testable returns the Testable interface for the implementation, or ni
     l if |  313                         return nil | 
|  310         // there is none. |  314                 } | 
|  311         Testable() Testable |  315  | 
|  312  |  316         case hasErr && !hasCursorCB: | 
|  313         // Raw returns the underlying RawInterface. The Interface and RawInterfa
     ce may |  317                 cbFunc = func(v reflect.Value, _ CursorCB) error { | 
|  314         // be used interchangably; there's no danger of interleaving access to t
     he |  318                         err := cbVal.Call([]reflect.Value{v})[0].Interface() | 
|  315         // datastore via the two. |  319                         if err != nil { | 
|  316         Raw() RawInterface |  320                                 return err.(error) | 
|  317 } |  321                         } | 
 |  322                         return nil | 
 |  323                 } | 
 |  324  | 
 |  325         case !hasErr && hasCursorCB: | 
 |  326                 cbFunc = func(v reflect.Value, cb CursorCB) error { | 
 |  327                         cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)}) | 
 |  328                         return nil | 
 |  329                 } | 
 |  330  | 
 |  331         case !hasErr && !hasCursorCB: | 
 |  332                 cbFunc = func(v reflect.Value, _ CursorCB) error { | 
 |  333                         cbVal.Call([]reflect.Value{v}) | 
 |  334                         return nil | 
 |  335                 } | 
 |  336         } | 
 |  337  | 
 |  338         raw := Raw(c) | 
 |  339         if isKey { | 
 |  340                 err = raw.Run(fq, func(k *Key, _ PropertyMap, gc CursorCB) error
      { | 
 |  341                         return cbFunc(reflect.ValueOf(k), gc) | 
 |  342                 }) | 
 |  343         } else { | 
 |  344                 err = raw.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) erro
     r { | 
 |  345                         itm := mat.newElem() | 
 |  346                         if err := mat.setPM(itm, pm); err != nil { | 
 |  347                                 return err | 
 |  348                         } | 
 |  349                         mat.setKey(itm, k) | 
 |  350                         return cbFunc(itm, gc) | 
 |  351                 }) | 
 |  352         } | 
 |  353         return filterStop(err) | 
 |  354 } | 
 |  355  | 
 |  356 // Count executes the given query and returns the number of entries which | 
 |  357 // match it. | 
 |  358 func Count(c context.Context, q *Query) (int64, error) { | 
 |  359         fq, err := q.Finalize() | 
 |  360         if err != nil { | 
 |  361                 return 0, err | 
 |  362         } | 
 |  363         v, err := Raw(c).Count(fq) | 
 |  364         return v, filterStop(err) | 
 |  365 } | 
 |  366  | 
 |  367 // DecodeCursor converts a string returned by a Cursor into a Cursor instance. | 
 |  368 // It will return an error if the supplied string is not valid, or could not | 
 |  369 // be decoded by the implementation. | 
 |  370 func DecodeCursor(c context.Context, s string) (Cursor, error) { | 
 |  371         return Raw(c).DecodeCursor(s) | 
 |  372 } | 
 |  373  | 
 |  374 // GetAll retrieves all of the Query results into dst. | 
 |  375 // | 
 |  376 // dst must be one of: | 
 |  377 //   - *[]S or *[]*S, where S is a struct | 
 |  378 //   - *[]P or *[]*P, where *P is a concrete type implementing | 
 |  379 //     PropertyLoadSaver | 
 |  380 //   - *[]*Key implies a keys-only query. | 
 |  381 func GetAll(c context.Context, q *Query, dst interface{}) error { | 
 |  382         v := reflect.ValueOf(dst) | 
 |  383         if v.Kind() != reflect.Ptr { | 
 |  384                 panic(fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: 
     %T", dst)) | 
 |  385         } | 
 |  386         if !v.IsValid() || v.IsNil() { | 
 |  387                 panic(errors.New("invalid GetAll dst: <nil>")) | 
 |  388         } | 
 |  389  | 
 |  390         raw := Raw(c) | 
 |  391         if keys, ok := dst.(*[]*Key); ok { | 
 |  392                 fq, err := q.KeysOnly(true).Finalize() | 
 |  393                 if err != nil { | 
 |  394                         return err | 
 |  395                 } | 
 |  396  | 
 |  397                 return raw.Run(fq, func(k *Key, _ PropertyMap, _ CursorCB) error
      { | 
 |  398                         *keys = append(*keys, k) | 
 |  399                         return nil | 
 |  400                 }) | 
 |  401         } | 
 |  402         fq, err := q.Finalize() | 
 |  403         if err != nil { | 
 |  404                 return err | 
 |  405         } | 
 |  406  | 
 |  407         slice := v.Elem() | 
 |  408         mat := mustParseMultiArg(slice.Type()) | 
 |  409         if mat.newElem == nil { | 
 |  410                 panic(fmt.Errorf("invalid GetAll dst (non-concrete element type)
     : %T", dst)) | 
 |  411         } | 
 |  412  | 
 |  413         errs := map[int]error{} | 
 |  414         i := 0 | 
 |  415         err = filterStop(raw.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) er
     ror { | 
 |  416                 slice.Set(reflect.Append(slice, mat.newElem())) | 
 |  417                 itm := slice.Index(i) | 
 |  418                 mat.setKey(itm, k) | 
 |  419                 err := mat.setPM(itm, pm) | 
 |  420                 if err != nil { | 
 |  421                         errs[i] = err | 
 |  422                 } | 
 |  423                 i++ | 
 |  424                 return nil | 
 |  425         })) | 
 |  426         if err == nil { | 
 |  427                 if len(errs) > 0 { | 
 |  428                         me := make(errors.MultiError, slice.Len()) | 
 |  429                         for i, e := range errs { | 
 |  430                                 me[i] = e | 
 |  431                         } | 
 |  432                         err = me | 
 |  433                 } | 
 |  434         } | 
 |  435         return err | 
 |  436 } | 
 |  437  | 
 |  438 // Exists tests if the supplied objects are present in the datastore. | 
 |  439 // | 
 |  440 // ent must be one of: | 
 |  441 //      - *S, where S is a struct | 
 |  442 //      - *P, where *P is a concrete type implementing PropertyLoadSaver | 
 |  443 //      - []S or []*S, where S is a struct | 
 |  444 //      - []P or []*P, where *P is a concrete type implementing PropertyLoadSave
     r | 
 |  445 //      - []I, where I is some interface type. Each element of the slice must | 
 |  446 //        be non-nil, and its underlying type must be either *S or *P. | 
 |  447 //      - *Key, to check a specific key from the datastore. | 
 |  448 //      - []*Key, to check a slice of keys from the datastore. | 
 |  449 // | 
 |  450 // If an error is encountered, the returned error value will depend on the | 
 |  451 // input arguments. If one argument is supplied, the result will be the | 
 |  452 // encountered error type. If multiple arguments are supplied, the result will | 
 |  453 // be a MultiError whose error index corresponds to the argument in which the | 
 |  454 // error was encountered. | 
 |  455 // | 
 |  456 // If an ent argument is a slice, its error type will be a MultiError. Note | 
 |  457 // that in the scenario, where multiple slices are provided, this will return a | 
 |  458 // MultiError containing a nested MultiError for each slice argument. | 
 |  459 func Exists(c context.Context, ent ...interface{}) (*ExistsResult, error) { | 
 |  460         if len(ent) == 0 { | 
 |  461                 return nil, nil | 
 |  462         } | 
 |  463  | 
 |  464         mma, err := makeMetaMultiArg(ent, mmaKeysOnly) | 
 |  465         if err != nil { | 
 |  466                 panic(err) | 
 |  467         } | 
 |  468  | 
 |  469         keys, _, err := mma.getKeysPMs(GetKeyContext(c), false) | 
 |  470         if err != nil { | 
 |  471                 return nil, maybeSingleError(err, ent) | 
 |  472         } | 
 |  473         if len(keys) == 0 { | 
 |  474                 return nil, nil | 
 |  475         } | 
 |  476  | 
 |  477         var bt boolTracker | 
 |  478         it := mma.iterator(bt.init(mma)) | 
 |  479         err = filterStop(Raw(c).GetMulti(keys, nil, func(_ PropertyMap, err erro
     r) error { | 
 |  480                 it.next(func(*multiArgType, reflect.Value) error { | 
 |  481                         return err | 
 |  482                 }) | 
 |  483                 return nil | 
 |  484         })) | 
 |  485         if err == nil { | 
 |  486                 err = bt.error() | 
 |  487         } | 
 |  488         return bt.result(), maybeSingleError(err, ent) | 
 |  489 } | 
 |  490  | 
 |  491 // Get retrieves objects from the datastore. | 
 |  492 // | 
 |  493 // Each element in dst must be one of: | 
 |  494 //      - *S, where S is a struct | 
 |  495 //      - *P, where *P is a concrete type implementing PropertyLoadSaver | 
 |  496 //      - []S or []*S, where S is a struct | 
 |  497 //      - []P or []*P, where *P is a concrete type implementing PropertyLoadSave
     r | 
 |  498 //      - []I, where I is some interface type. Each element of the slice must | 
 |  499 //        be non-nil, and its underlying type must be either *S or *P. | 
 |  500 // | 
 |  501 // If an error is encountered, the returned error value will depend on the | 
 |  502 // input arguments. If one argument is supplied, the result will be the | 
 |  503 // encountered error type. If multiple arguments are supplied, the result will | 
 |  504 // be a MultiError whose error index corresponds to the argument in which the | 
 |  505 // error was encountered. | 
 |  506 // | 
 |  507 // If a dst argument is a slice, its error type will be a MultiError. Note | 
 |  508 // that in the scenario where multiple slices are provided, this will return a | 
 |  509 // MultiError containing a nested MultiError for each slice argument. | 
 |  510 func Get(c context.Context, dst ...interface{}) error { | 
 |  511         if len(dst) == 0 { | 
 |  512                 return nil | 
 |  513         } | 
 |  514  | 
 |  515         mma, err := makeMetaMultiArg(dst, mmaReadWrite) | 
 |  516         if err != nil { | 
 |  517                 panic(err) | 
 |  518         } | 
 |  519  | 
 |  520         keys, pms, err := mma.getKeysPMs(GetKeyContext(c), true) | 
 |  521         if err != nil { | 
 |  522                 return maybeSingleError(err, dst) | 
 |  523         } | 
 |  524         if len(keys) == 0 { | 
 |  525                 return nil | 
 |  526         } | 
 |  527  | 
 |  528         var et errorTracker | 
 |  529         it := mma.iterator(et.init(mma)) | 
 |  530         meta := NewMultiMetaGetter(pms) | 
 |  531         err = filterStop(Raw(c).GetMulti(keys, meta, func(pm PropertyMap, err er
     ror) error { | 
 |  532                 it.next(func(mat *multiArgType, slot reflect.Value) error { | 
 |  533                         if err != nil { | 
 |  534                                 return err | 
 |  535                         } | 
 |  536                         return mat.setPM(slot, pm) | 
 |  537                 }) | 
 |  538                 return nil | 
 |  539         })) | 
 |  540  | 
 |  541         if err == nil { | 
 |  542                 err = et.error() | 
 |  543         } | 
 |  544         return maybeSingleError(err, dst) | 
 |  545 } | 
 |  546  | 
 |  547 // Put writes objects into the datastore. | 
 |  548 // | 
 |  549 // src must be one of: | 
 |  550 //      - *S, where S is a struct | 
 |  551 //      - *P, where *P is a concrete type implementing PropertyLoadSaver | 
 |  552 //      - []S or []*S, where S is a struct | 
 |  553 //      - []P or []*P, where *P is a concrete type implementing PropertyLoadSave
     r | 
 |  554 //      - []I, where I is some interface type. Each element of the slice must | 
 |  555 //        be non-nil, and its underlying type must be either *S or *P. | 
 |  556 // | 
 |  557 // A *Key will be extracted from src via KeyForObj. If | 
 |  558 // extractedKey.Incomplete() is true, then Put will write the resolved (i.e. | 
 |  559 // automatic datastore-populated) *Key back to src. | 
 |  560 // | 
 |  561 // If an error is encountered, the returned error value will depend on the | 
 |  562 // input arguments. If one argument is supplied, the result will be the | 
 |  563 // encountered error type. If multiple arguments are supplied, the result will | 
 |  564 // be a MultiError whose error index corresponds to the argument in which the | 
 |  565 // error was encountered. | 
 |  566 // | 
 |  567 // If a src argument is a slice, its error type will be a MultiError. Note | 
 |  568 // that in the scenario where multiple slices are provided, this will return a | 
 |  569 // MultiError containing a nested MultiError for each slice argument. | 
 |  570 func Put(c context.Context, src ...interface{}) error { | 
 |  571         if len(src) == 0 { | 
 |  572                 return nil | 
 |  573         } | 
 |  574  | 
 |  575         mma, err := makeMetaMultiArg(src, mmaReadWrite) | 
 |  576         if err != nil { | 
 |  577                 panic(err) | 
 |  578         } | 
 |  579  | 
 |  580         keys, vals, err := mma.getKeysPMs(GetKeyContext(c), false) | 
 |  581         if err != nil { | 
 |  582                 return maybeSingleError(err, src) | 
 |  583         } | 
 |  584         if len(keys) == 0 { | 
 |  585                 return nil | 
 |  586         } | 
 |  587  | 
 |  588         i := 0 | 
 |  589         var et errorTracker | 
 |  590         it := mma.iterator(et.init(mma)) | 
 |  591         err = filterStop(Raw(c).PutMulti(keys, vals, func(key *Key, err error) e
     rror { | 
 |  592                 it.next(func(mat *multiArgType, slot reflect.Value) error { | 
 |  593                         if err != nil { | 
 |  594                                 return err | 
 |  595                         } | 
 |  596                         if key != keys[i] { | 
 |  597                                 mat.setKey(slot, key) | 
 |  598                         } | 
 |  599                         return nil | 
 |  600                 }) | 
 |  601  | 
 |  602                 i++ | 
 |  603                 return nil | 
 |  604         })) | 
 |  605  | 
 |  606         if err == nil { | 
 |  607                 err = et.error() | 
 |  608         } | 
 |  609         return maybeSingleError(err, src) | 
 |  610 } | 
 |  611  | 
 |  612 // Delete removes the supplied entities from the datastore. | 
 |  613 // | 
 |  614 // ent must be one of: | 
 |  615 //      - *S, where S is a struct | 
 |  616 //      - *P, where *P is a concrete type implementing PropertyLoadSaver | 
 |  617 //      - []S or []*S, where S is a struct | 
 |  618 //      - []P or []*P, where *P is a concrete type implementing PropertyLoadSave
     r | 
 |  619 //      - []I, where I is some interface type. Each element of the slice must | 
 |  620 //        be non-nil, and its underlying type must be either *S or *P. | 
 |  621 //      - *Key, to remove a specific key from the datastore. | 
 |  622 //      - []*Key, to remove a slice of keys from the datastore. | 
 |  623 // | 
 |  624 // If an error is encountered, the returned error value will depend on the | 
 |  625 // input arguments. If one argument is supplied, the result will be the | 
 |  626 // encountered error type. If multiple arguments are supplied, the result will | 
 |  627 // be a MultiError whose error index corresponds to the argument in which the | 
 |  628 // error was encountered. | 
 |  629 // | 
 |  630 // If an ent argument is a slice, its error type will be a MultiError. Note | 
 |  631 // that in the scenario where multiple slices are provided, this will return a | 
 |  632 // MultiError containing a nested MultiError for each slice argument. | 
 |  633 func Delete(c context.Context, ent ...interface{}) error { | 
 |  634         if len(ent) == 0 { | 
 |  635                 return nil | 
 |  636         } | 
 |  637  | 
 |  638         mma, err := makeMetaMultiArg(ent, mmaKeysOnly) | 
 |  639         if err != nil { | 
 |  640                 panic(err) | 
 |  641         } | 
 |  642  | 
 |  643         keys, _, err := mma.getKeysPMs(GetKeyContext(c), false) | 
 |  644         if err != nil { | 
 |  645                 return maybeSingleError(err, ent) | 
 |  646         } | 
 |  647         if len(keys) == 0 { | 
 |  648                 return nil | 
 |  649         } | 
 |  650  | 
 |  651         var et errorTracker | 
 |  652         it := mma.iterator(et.init(mma)) | 
 |  653         err = filterStop(Raw(c).DeleteMulti(keys, func(err error) error { | 
 |  654                 it.next(func(*multiArgType, reflect.Value) error { | 
 |  655                         return err | 
 |  656                 }) | 
 |  657  | 
 |  658                 return nil | 
 |  659         })) | 
 |  660         if err == nil { | 
 |  661                 err = et.error() | 
 |  662         } | 
 |  663         return maybeSingleError(err, ent) | 
 |  664 } | 
 |  665  | 
 |  666 // GetTestable returns the Testable interface for the implementation, or nil if | 
 |  667 // there is none. | 
 |  668 func GetTestable(c context.Context) Testable { | 
 |  669         return Raw(c).GetTestable() | 
 |  670 } | 
 |  671  | 
 |  672 // maybeSingleError normalizes the error experience between single- and | 
 |  673 // multi-element API calls. | 
 |  674 // | 
 |  675 // Single-element API calls will return a single error for that element, while | 
 |  676 // multi-element API calls will return a MultiError, one for each element. This | 
 |  677 // accepts the slice of elements that is being operated on and determines what | 
 |  678 // sort of error to return. | 
 |  679 func maybeSingleError(err error, elems []interface{}) error { | 
 |  680         if err == nil { | 
 |  681                 return nil | 
 |  682         } | 
 |  683         if len(elems) == 1 { | 
 |  684                 return errors.SingleError(err) | 
 |  685         } | 
 |  686         return err | 
 |  687 } | 
 |  688  | 
 |  689 func filterStop(err error) error { | 
 |  690         if err == Stop { | 
 |  691                 err = nil | 
 |  692         } | 
 |  693         return err | 
 |  694 } | 
| OLD | NEW |