Index: impl/prod/raw_datastore.go |
diff --git a/impl/prod/raw_datastore.go b/impl/prod/raw_datastore.go |
index bb8a37779577bd5edb7186e494818e171734a87b..ce4f1df6fd90b0ec0d16feeeddeeea8ae646c1cc 100644 |
--- a/impl/prod/raw_datastore.go |
+++ b/impl/prod/raw_datastore.go |
@@ -7,8 +7,8 @@ package prod |
import ( |
ds "github.com/luci/gae/service/datastore" |
"github.com/luci/gae/service/info" |
+ "github.com/luci/luci-go/common/errors" |
"golang.org/x/net/context" |
- "google.golang.org/appengine" |
"google.golang.org/appengine/datastore" |
) |
@@ -20,44 +20,6 @@ func useRDS(c context.Context) context.Context { |
}) |
} |
-////////// Query |
- |
-type queryImpl struct{ *datastore.Query } |
- |
-func (q queryImpl) Distinct() ds.Query { |
- return queryImpl{q.Query.Distinct()} |
-} |
-func (q queryImpl) End(c ds.Cursor) ds.Query { |
- return queryImpl{q.Query.End(c.(datastore.Cursor))} |
-} |
-func (q queryImpl) EventualConsistency() ds.Query { |
- return queryImpl{q.Query.EventualConsistency()} |
-} |
-func (q queryImpl) KeysOnly() ds.Query { |
- return queryImpl{q.Query.KeysOnly()} |
-} |
-func (q queryImpl) Limit(limit int) ds.Query { |
- return queryImpl{q.Query.Limit(limit)} |
-} |
-func (q queryImpl) Offset(offset int) ds.Query { |
- return queryImpl{q.Query.Offset(offset)} |
-} |
-func (q queryImpl) Order(fieldName string) ds.Query { |
- return queryImpl{q.Query.Order(fieldName)} |
-} |
-func (q queryImpl) Start(c ds.Cursor) ds.Query { |
- return queryImpl{q.Query.Start(c.(datastore.Cursor))} |
-} |
-func (q queryImpl) Ancestor(ancestor ds.Key) ds.Query { |
- return queryImpl{q.Query.Ancestor(dsF2R(ancestor))} |
-} |
-func (q queryImpl) Project(fieldNames ...string) ds.Query { |
- return queryImpl{q.Query.Project(fieldNames...)} |
-} |
-func (q queryImpl) Filter(filterStr string, value interface{}) ds.Query { |
- return queryImpl{q.Query.Filter(filterStr, value)} |
-} |
- |
////////// Datastore |
type rdsImpl struct { |
@@ -66,15 +28,6 @@ type rdsImpl struct { |
ns string |
} |
-func (d rdsImpl) NewKey(kind, stringID string, intID int64, parent ds.Key) ds.Key { |
- return dsR2F(datastore.NewKey(d, kind, stringID, intID, dsF2R(parent))) |
-} |
- |
-func (rdsImpl) DecodeKey(encoded string) (ds.Key, error) { |
- k, err := datastore.DecodeKey(encoded) |
- return dsR2F(k), err |
-} |
- |
func idxCallbacker(err error, amt int, cb func(idx int, err error)) error { |
if err == nil { |
for i := 0; i < amt; i++ { |
@@ -82,7 +35,8 @@ func idxCallbacker(err error, amt int, cb func(idx int, err error)) error { |
} |
return nil |
} |
- me, ok := err.(appengine.MultiError) |
+ err = errors.Fix(err) |
+ me, ok := err.(errors.MultiError) |
if ok { |
for i, err := range me { |
cb(i, err) |
@@ -92,34 +46,45 @@ func idxCallbacker(err error, amt int, cb func(idx int, err error)) error { |
return err |
} |
-func (d rdsImpl) DeleteMulti(ks []ds.Key, cb ds.DeleteMultiCB) error { |
- err := datastore.DeleteMulti(d, dsMF2R(ks)) |
+func (d rdsImpl) DeleteMulti(ks []*ds.Key, cb ds.DeleteMultiCB) error { |
+ keys, err := dsMF2R(d, ks) |
+ if err == nil { |
+ err = datastore.DeleteMulti(d, keys) |
+ } |
return idxCallbacker(err, len(ks), func(_ int, err error) { |
cb(err) |
}) |
} |
-func (d rdsImpl) GetMulti(keys []ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMultiCB) error { |
- rkeys := dsMF2R(keys) |
+func (d rdsImpl) GetMulti(keys []*ds.Key, _meta ds.MultiMetaGetter, cb ds.GetMultiCB) error { |
vals := make([]datastore.PropertyLoadSaver, len(keys)) |
- for i := range keys { |
- vals[i] = &typeFilter{ds.PropertyMap{}} |
+ rkeys, err := dsMF2R(d, keys) |
+ if err == nil { |
+ for i := range keys { |
+ vals[i] = &typeFilter{d, ds.PropertyMap{}} |
+ } |
+ err = datastore.GetMulti(d, rkeys, vals) |
} |
- err := datastore.GetMulti(d, rkeys, vals) |
return idxCallbacker(err, len(keys), func(idx int, err error) { |
- cb(vals[idx].(*typeFilter).pm, err) |
+ if pls := vals[idx]; pls != nil { |
+ cb(pls.(*typeFilter).pm, err) |
+ } else { |
+ cb(nil, err) |
+ } |
}) |
} |
-func (d rdsImpl) PutMulti(keys []ds.Key, vals []ds.PropertyMap, cb ds.PutMultiCB) error { |
- rkeys := dsMF2R(keys) |
- rvals := make([]datastore.PropertyLoadSaver, len(vals)) |
- for i, val := range vals { |
- rvals[i] = &typeFilter{val} |
+func (d rdsImpl) PutMulti(keys []*ds.Key, vals []ds.PropertyMap, cb ds.PutMultiCB) error { |
+ rkeys, err := dsMF2R(d, keys) |
+ if err == nil { |
+ rvals := make([]datastore.PropertyLoadSaver, len(vals)) |
+ for i, val := range vals { |
+ rvals[i] = &typeFilter{d, val} |
+ } |
+ rkeys, err = datastore.PutMulti(d, rkeys, rvals) |
} |
- rkeys, err := datastore.PutMulti(d, rkeys, rvals) |
return idxCallbacker(err, len(keys), func(idx int, err error) { |
- k := ds.Key(nil) |
+ k := (*ds.Key)(nil) |
if err == nil { |
k = dsR2F(rkeys[idx]) |
} |
@@ -127,17 +92,94 @@ func (d rdsImpl) PutMulti(keys []ds.Key, vals []ds.PropertyMap, cb ds.PutMultiCB |
}) |
} |
-func (d rdsImpl) NewQuery(kind string) ds.Query { |
- return queryImpl{datastore.NewQuery(kind)} |
+func (d rdsImpl) fixQuery(fq *ds.FinalizedQuery) (*datastore.Query, error) { |
+ ret := datastore.NewQuery(fq.Kind()) |
+ |
+ start, end := fq.Bounds() |
+ if start != nil { |
+ ret = ret.Start(start.(datastore.Cursor)) |
+ } |
+ if end != nil { |
+ ret = ret.End(end.(datastore.Cursor)) |
+ } |
+ |
+ for prop, vals := range fq.EqFilters() { |
+ if prop == "__ancestor__" { |
+ p, err := dsF2RProp(d, vals[0]) |
+ if err != nil { |
+ return nil, err |
+ } |
+ ret = ret.Ancestor(p.Value.(*datastore.Key)) |
+ } else { |
+ filt := prop + "=" |
+ for _, v := range vals { |
+ p, err := dsF2RProp(d, v) |
+ if err != nil { |
+ return nil, err |
+ } |
+ |
+ ret = ret.Filter(filt, p.Value) |
+ } |
+ } |
+ } |
+ |
+ if lnam, lop, lprop := fq.IneqFilterLow(); lnam != "" { |
+ p, err := dsF2RProp(d, lprop) |
+ if err != nil { |
+ return nil, err |
+ } |
+ ret = ret.Filter(lnam+" "+lop, p.Value) |
+ } |
+ |
+ if hnam, hop, hprop := fq.IneqFilterHigh(); hnam != "" { |
+ p, err := dsF2RProp(d, hprop) |
+ if err != nil { |
+ return nil, err |
+ } |
+ ret = ret.Filter(hnam+" "+hop, p.Value) |
+ } |
+ |
+ if fq.EventuallyConsistent() { |
+ ret = ret.EventualConsistency() |
+ } |
+ |
+ if fq.KeysOnly() { |
+ ret = ret.KeysOnly() |
+ } |
+ |
+ if lim, ok := fq.Limit(); ok { |
+ ret = ret.Limit(int(lim)) |
+ } |
+ |
+ if off, ok := fq.Offset(); ok { |
+ ret = ret.Offset(int(off)) |
+ } |
+ |
+ for _, o := range fq.Orders() { |
+ ret = ret.Order(o.String()) |
+ } |
+ |
+ ret = ret.Project(fq.Project()...) |
+ if fq.Distinct() { |
+ ret = ret.Distinct() |
+ } |
+ |
+ return ret, nil |
} |
func (d rdsImpl) DecodeCursor(s string) (ds.Cursor, error) { |
return datastore.DecodeCursor(s) |
} |
-func (d rdsImpl) Run(q ds.Query, cb ds.RawRunCB) error { |
+func (d rdsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { |
tf := typeFilter{} |
- t := q.(queryImpl).Query.Run(d) |
+ q, err := d.fixQuery(fq) |
+ if err != nil { |
+ return err |
+ } |
+ |
+ t := q.Run(d) |
+ |
cfunc := func() (ds.Cursor, error) { |
return t.Cursor() |
} |