| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package datastore | 5 package datastore |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "reflect" | 9 "reflect" |
| 10 | 10 |
| 11 "github.com/luci/luci-go/common/errors" | 11 "github.com/luci/luci-go/common/errors" |
| 12 ) | 12 ) |
| 13 | 13 |
| 14 type datastoreImpl struct{ RawInterface } | 14 type datastoreImpl struct { |
| 15 » RawInterface |
| 16 |
| 17 » aid string |
| 18 » ns string |
| 19 } |
| 15 | 20 |
| 16 var _ Interface = (*datastoreImpl)(nil) | 21 var _ Interface = (*datastoreImpl)(nil) |
| 17 | 22 |
| 18 func (d *datastoreImpl) KeyForObj(src interface{}) Key { | 23 func (d *datastoreImpl) KeyForObj(src interface{}) *Key { |
| 19 ret, err := d.KeyForObjErr(src) | 24 ret, err := d.KeyForObjErr(src) |
| 20 if err != nil { | 25 if err != nil { |
| 21 panic(err) | 26 panic(err) |
| 22 } | 27 } |
| 23 return ret | 28 return ret |
| 24 } | 29 } |
| 25 | 30 |
| 26 func (d *datastoreImpl) KeyForObjErr(src interface{}) (Key, error) { | 31 func (d *datastoreImpl) KeyForObjErr(src interface{}) (*Key, error) { |
| 27 » return newKeyObjErr(d.NewKey, src) | 32 » return newKeyObjErr(d.aid, d.ns, src) |
| 28 } | 33 } |
| 29 | 34 |
| 30 func (d *datastoreImpl) DecodeCursor(s string) (Cursor, error) { | 35 func (d *datastoreImpl) MakeKey(elems ...interface{}) *Key { |
| 31 » return d.RawInterface.DecodeCursor(s) | 36 » return MakeKey(d.aid, d.ns, elems...) |
| 32 } | 37 } |
| 33 | 38 |
| 34 func (d *datastoreImpl) Run(q Query, cbIface interface{}) error { | 39 func (d *datastoreImpl) NewKey(kind, stringID string, intID int64, parent *Key)
*Key { |
| 40 » return NewKey(d.aid, d.ns, kind, stringID, intID, parent) |
| 41 } |
| 42 |
| 43 func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { |
| 44 » return NewKeyToks(d.aid, d.ns, toks) |
| 45 } |
| 46 |
| 47 func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error { |
| 35 if cbIface == nil { | 48 if cbIface == nil { |
| 36 return fmt.Errorf("cannot use nil callback when Running query") | 49 return fmt.Errorf("cannot use nil callback when Running query") |
| 37 } | 50 } |
| 38 | 51 |
| 39 // TODO(riannucci): Profile and determine if any of this is causing a re
al | 52 // TODO(riannucci): Profile and determine if any of this is causing a re
al |
| 40 » // slowdown. Could potentially cache reflection stuff by cbType? | 53 » // slowdown. Could potentially cache reflection stuff by cbTyp? |
| 41 cbTyp := reflect.TypeOf(cbIface) | 54 cbTyp := reflect.TypeOf(cbIface) |
| 42 | 55 |
| 43 badSig := false | 56 badSig := false |
| 44 mat := multiArgType{} | 57 mat := multiArgType{} |
| 45 isKey := false | 58 isKey := false |
| 46 | 59 |
| 47 if cbTyp.Kind() == reflect.Func && cbTyp.NumIn() == 2 && cbTyp.NumOut()
== 1 { | 60 if cbTyp.Kind() == reflect.Func && cbTyp.NumIn() == 2 && cbTyp.NumOut()
== 1 { |
| 48 firstArg := cbTyp.In(0) | 61 firstArg := cbTyp.In(0) |
| 49 if firstArg == typeOfKey { | 62 if firstArg == typeOfKey { |
| 50 isKey = true | 63 isKey = true |
| 51 } else { | 64 } else { |
| 52 mat = parseArg(firstArg) | 65 mat = parseArg(firstArg) |
| 53 badSig = !mat.valid || mat.newElem == nil | 66 badSig = !mat.valid || mat.newElem == nil |
| 54 } | 67 } |
| 55 } else { | 68 } else { |
| 56 badSig = true | 69 badSig = true |
| 57 } | 70 } |
| 58 | 71 |
| 59 if badSig || cbTyp.Out(0) != typeOfBool || cbTyp.In(1) != typeOfCursorCB
{ | 72 if badSig || cbTyp.Out(0) != typeOfBool || cbTyp.In(1) != typeOfCursorCB
{ |
| 60 panic(fmt.Errorf( | 73 panic(fmt.Errorf( |
| 61 "cb does not match the required callback signature: `%T`
!= `func(TYPE, CursorCB) bool`", | 74 "cb does not match the required callback signature: `%T`
!= `func(TYPE, CursorCB) bool`", |
| 62 cbIface)) | 75 cbIface)) |
| 63 } | 76 } |
| 64 | 77 |
| 65 if isKey { | 78 if isKey { |
| 66 » » cb := cbIface.(func(Key, CursorCB) bool) | 79 » » cb := cbIface.(func(*Key, CursorCB) bool) |
| 67 » » return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMa
p, gc CursorCB) bool { | 80 » » fq, err := q.KeysOnly(true).Finalize() |
| 81 » » if err != nil { |
| 82 » » » return err |
| 83 » » } |
| 84 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc Cur
sorCB) bool { |
| 68 return cb(k, gc) | 85 return cb(k, gc) |
| 69 }) | 86 }) |
| 70 } | 87 } |
| 71 | 88 |
| 89 fq, err := q.Finalize() |
| 90 if err != nil { |
| 91 return err |
| 92 } |
| 93 |
| 72 cbVal := reflect.ValueOf(cbIface) | 94 cbVal := reflect.ValueOf(cbIface) |
| 73 | 95 |
| 74 innerErr := error(nil) | 96 innerErr := error(nil) |
| 75 » err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, gc CursorCB) bo
ol { | 97 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) b
ool { |
| 76 itm := mat.newElem() | 98 itm := mat.newElem() |
| 77 if innerErr = mat.setPM(itm, pm); innerErr != nil { | 99 if innerErr = mat.setPM(itm, pm); innerErr != nil { |
| 78 return false | 100 return false |
| 79 } | 101 } |
| 80 mat.setKey(itm, k) | 102 mat.setKey(itm, k) |
| 81 return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0].
Bool() | 103 return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0].
Bool() |
| 82 }) | 104 }) |
| 83 if err == nil { | 105 if err == nil { |
| 84 err = innerErr | 106 err = innerErr |
| 85 } | 107 } |
| 86 return err | 108 return err |
| 87 } | 109 } |
| 88 | 110 |
| 89 func (d *datastoreImpl) GetAll(q Query, dst interface{}) error { | 111 func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
| 90 v := reflect.ValueOf(dst) | 112 v := reflect.ValueOf(dst) |
| 91 if v.Kind() != reflect.Ptr { | 113 if v.Kind() != reflect.Ptr { |
| 92 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice:
%T", dst) | 114 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice:
%T", dst) |
| 93 } | 115 } |
| 94 if !v.IsValid() || v.IsNil() { | 116 if !v.IsValid() || v.IsNil() { |
| 95 return errors.New("invalid GetAll dst: <nil>") | 117 return errors.New("invalid GetAll dst: <nil>") |
| 96 } | 118 } |
| 97 | 119 |
| 98 » if keys, ok := dst.(*[]Key); ok { | 120 » if keys, ok := dst.(*[]*Key); ok { |
| 99 » » return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMa
p, _ CursorCB) bool { | 121 » » fq, err := q.KeysOnly(true).Finalize() |
| 122 » » if err != nil { |
| 123 » » » return err |
| 124 » » } |
| 125 |
| 126 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ Curs
orCB) bool { |
| 100 *keys = append(*keys, k) | 127 *keys = append(*keys, k) |
| 101 return true | 128 return true |
| 102 }) | 129 }) |
| 103 } | 130 } |
| 131 fq, err := q.Finalize() |
| 132 if err != nil { |
| 133 return err |
| 134 } |
| 104 | 135 |
| 105 slice := v.Elem() | 136 slice := v.Elem() |
| 106 mat := parseMultiArg(slice.Type()) | 137 mat := parseMultiArg(slice.Type()) |
| 107 if !mat.valid || mat.newElem == nil { | 138 if !mat.valid || mat.newElem == nil { |
| 108 return fmt.Errorf("invalid GetAll input type: %T", dst) | 139 return fmt.Errorf("invalid GetAll input type: %T", dst) |
| 109 } | 140 } |
| 110 | 141 |
| 111 » lme := errors.NewLazyMultiError(slice.Len()) | 142 » errs := map[int]error{} |
| 112 i := 0 | 143 i := 0 |
| 113 » err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, _ CursorCB) boo
l { | 144 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) bo
ol { |
| 114 slice.Set(reflect.Append(slice, mat.newElem())) | 145 slice.Set(reflect.Append(slice, mat.newElem())) |
| 115 itm := slice.Index(i) | 146 itm := slice.Index(i) |
| 116 mat.setKey(itm, k) | 147 mat.setKey(itm, k) |
| 117 » » lme.Assign(i, mat.setPM(itm, pm)) | 148 » » err := mat.setPM(itm, pm) |
| 149 » » if err != nil { |
| 150 » » » errs[i] = err |
| 151 » » } |
| 118 i++ | 152 i++ |
| 119 return true | 153 return true |
| 120 }) | 154 }) |
| 121 if err == nil { | 155 if err == nil { |
| 122 » » err = lme.Get() | 156 » » if len(errs) > 0 { |
| 157 » » » me := make(errors.MultiError, slice.Len()) |
| 158 » » » for i, e := range errs { |
| 159 » » » » me[i] = e |
| 160 » » » } |
| 161 » » » err = me |
| 162 » » } |
| 123 } | 163 } |
| 124 return err | 164 return err |
| 125 } | 165 } |
| 126 | 166 |
| 127 func isOkType(v reflect.Type) bool { | 167 func isOkType(v reflect.Type) bool { |
| 128 if v.Implements(typeOfPropertyLoadSaver) { | 168 if v.Implements(typeOfPropertyLoadSaver) { |
| 129 return true | 169 return true |
| 130 } | 170 } |
| 131 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { | 171 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { |
| 132 return true | 172 return true |
| 133 } | 173 } |
| 134 return false | 174 return false |
| 135 } | 175 } |
| 136 | 176 |
| 137 func (d *datastoreImpl) Get(dst interface{}) (err error) { | 177 func (d *datastoreImpl) Get(dst interface{}) (err error) { |
| 138 if !isOkType(reflect.TypeOf(dst)) { | 178 if !isOkType(reflect.TypeOf(dst)) { |
| 139 return fmt.Errorf("invalid Get input type: %T", dst) | 179 return fmt.Errorf("invalid Get input type: %T", dst) |
| 140 } | 180 } |
| 141 return errors.SingleError(d.GetMulti([]interface{}{dst})) | 181 return errors.SingleError(d.GetMulti([]interface{}{dst})) |
| 142 } | 182 } |
| 143 | 183 |
| 144 func (d *datastoreImpl) Put(src interface{}) (err error) { | 184 func (d *datastoreImpl) Put(src interface{}) (err error) { |
| 145 if !isOkType(reflect.TypeOf(src)) { | 185 if !isOkType(reflect.TypeOf(src)) { |
| 146 return fmt.Errorf("invalid Put input type: %T", src) | 186 return fmt.Errorf("invalid Put input type: %T", src) |
| 147 } | 187 } |
| 148 return errors.SingleError(d.PutMulti([]interface{}{src})) | 188 return errors.SingleError(d.PutMulti([]interface{}{src})) |
| 149 } | 189 } |
| 150 | 190 |
| 151 func (d *datastoreImpl) Delete(key Key) (err error) { | 191 func (d *datastoreImpl) Delete(key *Key) (err error) { |
| 152 » return errors.SingleError(d.DeleteMulti([]Key{key})) | 192 » return errors.SingleError(d.DeleteMulti([]*Key{key})) |
| 153 } | 193 } |
| 154 | 194 |
| 155 func (d *datastoreImpl) GetMulti(dst interface{}) error { | 195 func (d *datastoreImpl) GetMulti(dst interface{}) error { |
| 156 slice := reflect.ValueOf(dst) | 196 slice := reflect.ValueOf(dst) |
| 157 mat := parseMultiArg(slice.Type()) | 197 mat := parseMultiArg(slice.Type()) |
| 158 if !mat.valid { | 198 if !mat.valid { |
| 159 return fmt.Errorf("invalid GetMulti input type: %T", dst) | 199 return fmt.Errorf("invalid GetMulti input type: %T", dst) |
| 160 } | 200 } |
| 161 | 201 |
| 162 » keys, pms, err := mat.GetKeysPMs(d.NewKey, slice) | 202 » keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice) |
| 163 if err != nil { | 203 if err != nil { |
| 164 return err | 204 return err |
| 165 } | 205 } |
| 166 | 206 |
| 167 lme := errors.NewLazyMultiError(len(keys)) | 207 lme := errors.NewLazyMultiError(len(keys)) |
| 168 i := 0 | 208 i := 0 |
| 169 meta := NewMultiMetaGetter(pms) | 209 meta := NewMultiMetaGetter(pms) |
| 170 err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error
) { | 210 err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error
) { |
| 171 if !lme.Assign(i, err) { | 211 if !lme.Assign(i, err) { |
| 172 lme.Assign(i, mat.setPM(slice.Index(i), pm)) | 212 lme.Assign(i, mat.setPM(slice.Index(i), pm)) |
| 173 } | 213 } |
| 174 i++ | 214 i++ |
| 175 }) | 215 }) |
| 176 | 216 |
| 177 if err == nil { | 217 if err == nil { |
| 178 err = lme.Get() | 218 err = lme.Get() |
| 179 } | 219 } |
| 180 return err | 220 return err |
| 181 } | 221 } |
| 182 | 222 |
| 183 func (d *datastoreImpl) PutMulti(src interface{}) error { | 223 func (d *datastoreImpl) PutMulti(src interface{}) error { |
| 184 slice := reflect.ValueOf(src) | 224 slice := reflect.ValueOf(src) |
| 185 mat := parseMultiArg(slice.Type()) | 225 mat := parseMultiArg(slice.Type()) |
| 186 if !mat.valid { | 226 if !mat.valid { |
| 187 return fmt.Errorf("invalid PutMulti input type: %T", src) | 227 return fmt.Errorf("invalid PutMulti input type: %T", src) |
| 188 } | 228 } |
| 189 | 229 |
| 190 » keys, vals, err := mat.GetKeysPMs(d.NewKey, slice) | 230 » keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice) |
| 191 if err != nil { | 231 if err != nil { |
| 192 return err | 232 return err |
| 193 } | 233 } |
| 194 | 234 |
| 195 lme := errors.NewLazyMultiError(len(keys)) | 235 lme := errors.NewLazyMultiError(len(keys)) |
| 196 i := 0 | 236 i := 0 |
| 197 » err = d.RawInterface.PutMulti(keys, vals, func(key Key, err error) { | 237 » err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) { |
| 198 if key != keys[i] { | 238 if key != keys[i] { |
| 199 mat.setKey(slice.Index(i), key) | 239 mat.setKey(slice.Index(i), key) |
| 200 } | 240 } |
| 201 lme.Assign(i, err) | 241 lme.Assign(i, err) |
| 202 i++ | 242 i++ |
| 203 }) | 243 }) |
| 204 | 244 |
| 205 if err == nil { | 245 if err == nil { |
| 206 err = lme.Get() | 246 err = lme.Get() |
| 207 } | 247 } |
| 208 return err | 248 return err |
| 209 } | 249 } |
| 210 | 250 |
| 211 func (d *datastoreImpl) DeleteMulti(keys []Key) (err error) { | 251 func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) { |
| 212 lme := errors.NewLazyMultiError(len(keys)) | 252 lme := errors.NewLazyMultiError(len(keys)) |
| 213 i := 0 | 253 i := 0 |
| 214 extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { | 254 extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { |
| 215 lme.Assign(i, internalErr) | 255 lme.Assign(i, internalErr) |
| 216 i++ | 256 i++ |
| 217 }) | 257 }) |
| 218 err = lme.Get() | 258 err = lme.Get() |
| 219 if err == nil { | 259 if err == nil { |
| 220 err = extErr | 260 err = extErr |
| 221 } | 261 } |
| 222 return | 262 return |
| 223 } | 263 } |
| 224 | 264 |
| 225 func (d *datastoreImpl) Raw() RawInterface { | 265 func (d *datastoreImpl) Raw() RawInterface { |
| 226 return d.RawInterface | 266 return d.RawInterface |
| 227 } | 267 } |
| OLD | NEW |