| 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 prod | 5 package prod |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 ds "github.com/luci/gae/service/datastore" | 8 ds "github.com/luci/gae/service/datastore" |
| 9 "github.com/luci/gae/service/info" | 9 "github.com/luci/gae/service/info" |
| 10 "github.com/luci/luci-go/common/errors" |
| 10 "golang.org/x/net/context" | 11 "golang.org/x/net/context" |
| 11 "google.golang.org/appengine" | |
| 12 "google.golang.org/appengine/datastore" | 12 "google.golang.org/appengine/datastore" |
| 13 ) | 13 ) |
| 14 | 14 |
| 15 // useRDS adds a gae.RawDatastore implementation to context, accessible | 15 // useRDS adds a gae.RawDatastore implementation to context, accessible |
| 16 // by gae.GetDS(c) | 16 // by gae.GetDS(c) |
| 17 func useRDS(c context.Context) context.Context { | 17 func useRDS(c context.Context) context.Context { |
| 18 return ds.SetRawFactory(c, func(ci context.Context) ds.RawInterface { | 18 return ds.SetRawFactory(c, func(ci context.Context) ds.RawInterface { |
| 19 return rdsImpl{ci, info.Get(ci).GetNamespace()} | 19 return rdsImpl{ci, info.Get(ci).GetNamespace()} |
| 20 }) | 20 }) |
| 21 } | 21 } |
| 22 | 22 |
| 23 ////////// Query | |
| 24 | |
| 25 type queryImpl struct{ *datastore.Query } | |
| 26 | |
| 27 func (q queryImpl) Distinct() ds.Query { | |
| 28 return queryImpl{q.Query.Distinct()} | |
| 29 } | |
| 30 func (q queryImpl) End(c ds.Cursor) ds.Query { | |
| 31 return queryImpl{q.Query.End(c.(datastore.Cursor))} | |
| 32 } | |
| 33 func (q queryImpl) EventualConsistency() ds.Query { | |
| 34 return queryImpl{q.Query.EventualConsistency()} | |
| 35 } | |
| 36 func (q queryImpl) KeysOnly() ds.Query { | |
| 37 return queryImpl{q.Query.KeysOnly()} | |
| 38 } | |
| 39 func (q queryImpl) Limit(limit int) ds.Query { | |
| 40 return queryImpl{q.Query.Limit(limit)} | |
| 41 } | |
| 42 func (q queryImpl) Offset(offset int) ds.Query { | |
| 43 return queryImpl{q.Query.Offset(offset)} | |
| 44 } | |
| 45 func (q queryImpl) Order(fieldName string) ds.Query { | |
| 46 return queryImpl{q.Query.Order(fieldName)} | |
| 47 } | |
| 48 func (q queryImpl) Start(c ds.Cursor) ds.Query { | |
| 49 return queryImpl{q.Query.Start(c.(datastore.Cursor))} | |
| 50 } | |
| 51 func (q queryImpl) Ancestor(ancestor ds.Key) ds.Query { | |
| 52 return queryImpl{q.Query.Ancestor(dsF2R(ancestor))} | |
| 53 } | |
| 54 func (q queryImpl) Project(fieldNames ...string) ds.Query { | |
| 55 return queryImpl{q.Query.Project(fieldNames...)} | |
| 56 } | |
| 57 func (q queryImpl) Filter(filterStr string, value interface{}) ds.Query { | |
| 58 return queryImpl{q.Query.Filter(filterStr, value)} | |
| 59 } | |
| 60 | |
| 61 ////////// Datastore | 23 ////////// Datastore |
| 62 | 24 |
| 63 type rdsImpl struct { | 25 type rdsImpl struct { |
| 64 context.Context | 26 context.Context |
| 65 | 27 |
| 66 ns string | 28 ns string |
| 67 } | 29 } |
| 68 | 30 |
| 69 func (d rdsImpl) NewKey(kind, stringID string, intID int64, parent ds.Key) ds.Ke
y { | |
| 70 return dsR2F(datastore.NewKey(d, kind, stringID, intID, dsF2R(parent))) | |
| 71 } | |
| 72 | |
| 73 func (rdsImpl) DecodeKey(encoded string) (ds.Key, error) { | |
| 74 k, err := datastore.DecodeKey(encoded) | |
| 75 return dsR2F(k), err | |
| 76 } | |
| 77 | |
| 78 func idxCallbacker(err error, amt int, cb func(idx int, err error)) error { | 31 func idxCallbacker(err error, amt int, cb func(idx int, err error)) error { |
| 79 if err == nil { | 32 if err == nil { |
| 80 for i := 0; i < amt; i++ { | 33 for i := 0; i < amt; i++ { |
| 81 cb(i, nil) | 34 cb(i, nil) |
| 82 } | 35 } |
| 83 return nil | 36 return nil |
| 84 } | 37 } |
| 85 » me, ok := err.(appengine.MultiError) | 38 » err = errors.Fix(err) |
| 39 » me, ok := err.(errors.MultiError) |
| 86 if ok { | 40 if ok { |
| 87 for i, err := range me { | 41 for i, err := range me { |
| 88 cb(i, err) | 42 cb(i, err) |
| 89 } | 43 } |
| 90 return nil | 44 return nil |
| 91 } | 45 } |
| 92 return err | 46 return err |
| 93 } | 47 } |
| 94 | 48 |
| 95 func (d rdsImpl) DeleteMulti(ks []ds.Key, cb ds.DeleteMultiCB) error { | 49 func (d rdsImpl) DeleteMulti(ks []*ds.Key, cb ds.DeleteMultiCB) error { |
| 96 » err := datastore.DeleteMulti(d, dsMF2R(ks)) | 50 » keys, err := dsMF2R(d, ks) |
| 51 » if err == nil { |
| 52 » » err = datastore.DeleteMulti(d, keys) |
| 53 » } |
| 97 return idxCallbacker(err, len(ks), func(_ int, err error) { | 54 return idxCallbacker(err, len(ks), func(_ int, err error) { |
| 98 cb(err) | 55 cb(err) |
| 99 }) | 56 }) |
| 100 } | 57 } |
| 101 | 58 |
| 102 func (d rdsImpl) GetMulti(keys []ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMult
iCB) error { | 59 func (d rdsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMul
tiCB) error { |
| 103 » rkeys := dsMF2R(keys) | |
| 104 vals := make([]datastore.PropertyLoadSaver, len(keys)) | 60 vals := make([]datastore.PropertyLoadSaver, len(keys)) |
| 105 » for i := range keys { | 61 » rkeys, err := dsMF2R(d, keys) |
| 106 » » vals[i] = &typeFilter{ds.PropertyMap{}} | 62 » if err == nil { |
| 63 » » for i := range keys { |
| 64 » » » vals[i] = &typeFilter{d, ds.PropertyMap{}} |
| 65 » » } |
| 66 » » err = datastore.GetMulti(d, rkeys, vals) |
| 107 } | 67 } |
| 108 err := datastore.GetMulti(d, rkeys, vals) | |
| 109 return idxCallbacker(err, len(keys), func(idx int, err error) { | 68 return idxCallbacker(err, len(keys), func(idx int, err error) { |
| 110 » » cb(vals[idx].(*typeFilter).pm, err) | 69 » » if pls := vals[idx]; pls != nil { |
| 70 » » » cb(pls.(*typeFilter).pm, err) |
| 71 » » } else { |
| 72 » » » cb(nil, err) |
| 73 » » } |
| 111 }) | 74 }) |
| 112 } | 75 } |
| 113 | 76 |
| 114 func (d rdsImpl) PutMulti(keys []ds.Key, vals []ds.PropertyMap, cb ds.PutMultiCB
) error { | 77 func (d rdsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.PutMultiC
B) error { |
| 115 » rkeys := dsMF2R(keys) | 78 » rkeys, err := dsMF2R(d, keys) |
| 116 » rvals := make([]datastore.PropertyLoadSaver, len(vals)) | 79 » if err == nil { |
| 117 » for i, val := range vals { | 80 » » rvals := make([]datastore.PropertyLoadSaver, len(vals)) |
| 118 » » rvals[i] = &typeFilter{val} | 81 » » for i, val := range vals { |
| 82 » » » rvals[i] = &typeFilter{d, val} |
| 83 » » } |
| 84 » » rkeys, err = datastore.PutMulti(d, rkeys, rvals) |
| 119 } | 85 } |
| 120 rkeys, err := datastore.PutMulti(d, rkeys, rvals) | |
| 121 return idxCallbacker(err, len(keys), func(idx int, err error) { | 86 return idxCallbacker(err, len(keys), func(idx int, err error) { |
| 122 » » k := ds.Key(nil) | 87 » » k := (*ds.Key)(nil) |
| 123 if err == nil { | 88 if err == nil { |
| 124 k = dsR2F(rkeys[idx]) | 89 k = dsR2F(rkeys[idx]) |
| 125 } | 90 } |
| 126 cb(k, err) | 91 cb(k, err) |
| 127 }) | 92 }) |
| 128 } | 93 } |
| 129 | 94 |
| 130 func (d rdsImpl) NewQuery(kind string) ds.Query { | 95 func (d rdsImpl) fixQuery(fq *ds.FinalizedQuery) (*datastore.Query, error) { |
| 131 » return queryImpl{datastore.NewQuery(kind)} | 96 » ret := datastore.NewQuery(fq.Kind()) |
| 97 |
| 98 » start, end := fq.Bounds() |
| 99 » if start != nil { |
| 100 » » ret = ret.Start(start.(datastore.Cursor)) |
| 101 » } |
| 102 » if end != nil { |
| 103 » » ret = ret.End(end.(datastore.Cursor)) |
| 104 » } |
| 105 |
| 106 » for prop, vals := range fq.EqFilters() { |
| 107 » » if prop == "__ancestor__" { |
| 108 » » » p, err := dsF2RProp(d, vals[0]) |
| 109 » » » if err != nil { |
| 110 » » » » return nil, err |
| 111 » » » } |
| 112 » » » ret = ret.Ancestor(p.Value.(*datastore.Key)) |
| 113 » » } else { |
| 114 » » » filt := prop + "=" |
| 115 » » » for _, v := range vals { |
| 116 » » » » p, err := dsF2RProp(d, v) |
| 117 » » » » if err != nil { |
| 118 » » » » » return nil, err |
| 119 » » » » } |
| 120 |
| 121 » » » » ret = ret.Filter(filt, p.Value) |
| 122 » » » } |
| 123 » » } |
| 124 » } |
| 125 |
| 126 » if lnam, lop, lprop := fq.IneqFilterLow(); lnam != "" { |
| 127 » » p, err := dsF2RProp(d, lprop) |
| 128 » » if err != nil { |
| 129 » » » return nil, err |
| 130 » » } |
| 131 » » ret = ret.Filter(lnam+" "+lop, p.Value) |
| 132 » } |
| 133 |
| 134 » if hnam, hop, hprop := fq.IneqFilterHigh(); hnam != "" { |
| 135 » » p, err := dsF2RProp(d, hprop) |
| 136 » » if err != nil { |
| 137 » » » return nil, err |
| 138 » » } |
| 139 » » ret = ret.Filter(hnam+" "+hop, p.Value) |
| 140 » } |
| 141 |
| 142 » if fq.EventuallyConsistent() { |
| 143 » » ret = ret.EventualConsistency() |
| 144 » } |
| 145 |
| 146 » if fq.KeysOnly() { |
| 147 » » ret = ret.KeysOnly() |
| 148 » } |
| 149 |
| 150 » if lim, ok := fq.Limit(); ok { |
| 151 » » ret = ret.Limit(int(lim)) |
| 152 » } |
| 153 |
| 154 » if off, ok := fq.Offset(); ok { |
| 155 » » ret = ret.Offset(int(off)) |
| 156 » } |
| 157 |
| 158 » for _, o := range fq.Orders() { |
| 159 » » ret = ret.Order(o.String()) |
| 160 » } |
| 161 |
| 162 » ret = ret.Project(fq.Project()...) |
| 163 » if fq.Distinct() { |
| 164 » » ret = ret.Distinct() |
| 165 » } |
| 166 |
| 167 » return ret, nil |
| 132 } | 168 } |
| 133 | 169 |
| 134 func (d rdsImpl) DecodeCursor(s string) (ds.Cursor, error) { | 170 func (d rdsImpl) DecodeCursor(s string) (ds.Cursor, error) { |
| 135 return datastore.DecodeCursor(s) | 171 return datastore.DecodeCursor(s) |
| 136 } | 172 } |
| 137 | 173 |
| 138 func (d rdsImpl) Run(q ds.Query, cb ds.RawRunCB) error { | 174 func (d rdsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { |
| 139 tf := typeFilter{} | 175 tf := typeFilter{} |
| 140 » t := q.(queryImpl).Query.Run(d) | 176 » q, err := d.fixQuery(fq) |
| 177 » if err != nil { |
| 178 » » return err |
| 179 » } |
| 180 |
| 181 » t := q.Run(d) |
| 182 |
| 141 cfunc := func() (ds.Cursor, error) { | 183 cfunc := func() (ds.Cursor, error) { |
| 142 return t.Cursor() | 184 return t.Cursor() |
| 143 } | 185 } |
| 144 for { | 186 for { |
| 145 k, err := t.Next(&tf) | 187 k, err := t.Next(&tf) |
| 146 if err == datastore.Done { | 188 if err == datastore.Done { |
| 147 return nil | 189 return nil |
| 148 } | 190 } |
| 149 if err != nil { | 191 if err != nil { |
| 150 return err | 192 return err |
| 151 } | 193 } |
| 152 if !cb(dsR2F(k), tf.pm, cfunc) { | 194 if !cb(dsR2F(k), tf.pm, cfunc) { |
| 153 return nil | 195 return nil |
| 154 } | 196 } |
| 155 } | 197 } |
| 156 } | 198 } |
| 157 | 199 |
| 158 func (d rdsImpl) RunInTransaction(f func(c context.Context) error, opts *ds.Tran
sactionOptions) error { | 200 func (d rdsImpl) RunInTransaction(f func(c context.Context) error, opts *ds.Tran
sactionOptions) error { |
| 159 ropts := (*datastore.TransactionOptions)(opts) | 201 ropts := (*datastore.TransactionOptions)(opts) |
| 160 return datastore.RunInTransaction(d, f, ropts) | 202 return datastore.RunInTransaction(d, f, ropts) |
| 161 } | 203 } |
| 162 | 204 |
| 163 func (d rdsImpl) Testable() ds.Testable { | 205 func (d rdsImpl) Testable() ds.Testable { |
| 164 return nil | 206 return nil |
| 165 } | 207 } |
| OLD | NEW |