Index: impl/memory/datastore.go |
diff --git a/impl/memory/datastore.go b/impl/memory/datastore.go |
index 8001295d74ea8e7e570bcafd3b8b049c3cc0c3e2..8337626889763d8cdcbfc32b629da7960f70a55e 100644 |
--- a/impl/memory/datastore.go |
+++ b/impl/memory/datastore.go |
@@ -20,7 +20,7 @@ import ( |
// by gae.GetDS(c) |
func useRDS(c context.Context) context.Context { |
return ds.SetRawFactory(c, func(ic context.Context, wantTxn bool) ds.RawInterface { |
- ns := curGID(ic).namespace |
+ ns, hasNS := curGID(ic).getNamespace() |
maybeTxnCtx := cur(ic) |
needResetCtx := false |
@@ -37,9 +37,9 @@ func useRDS(c context.Context) context.Context { |
if needResetCtx { |
ic = context.WithValue(ic, memContextKey, maybeTxnCtx) |
} |
- return &dsImpl{x, ns, ic} |
+ return &dsImpl{x, ns, hasNS, ic} |
} |
- return &txnDsImpl{dsd.(*txnDataStoreData), ns} |
+ return &txnDsImpl{dsd.(*txnDataStoreData), ns, hasNS} |
}) |
} |
@@ -54,10 +54,15 @@ func useRDS(c context.Context) context.Context { |
// These settings can of course be changed by using the Testable() interface. |
func NewDatastore(aid, ns string) (ds.Interface, error) { |
ctx := UseWithAppID(context.Background(), aid) |
- ctx, err := info.Get(ctx).Namespace(ns) |
- if err != nil { |
- return nil, err |
+ |
+ if ns != "" { |
+ var err error |
+ ctx, err = info.Get(ctx).Namespace(ns) |
+ if err != nil { |
+ return nil, err |
+ } |
} |
+ |
ret := ds.Get(ctx) |
t := ret.Testable() |
t.AutoIndex(true) |
@@ -70,9 +75,10 @@ func NewDatastore(aid, ns string) (ds.Interface, error) { |
// dsImpl exists solely to bind the current c to the datastore data. |
type dsImpl struct { |
- data *dataStoreData |
- ns string |
- c context.Context |
+ data *dataStoreData |
+ ns string |
+ hasNS bool |
+ c context.Context |
} |
var _ ds.RawInterface = (*dsImpl)(nil) |
@@ -100,6 +106,10 @@ func (d *dsImpl) DecodeCursor(s string) (ds.Cursor, error) { |
} |
func (d *dsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { |
+ if err := assertQueryNamespace(d.ns, d.hasNS); err != nil { |
+ return err |
+ } |
+ |
idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
err := executeQuery(fq, d.data.aid, d.ns, false, idx, head, cb) |
if d.data.maybeAutoIndex(err) { |
@@ -110,6 +120,10 @@ func (d *dsImpl) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { |
} |
func (d *dsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { |
+ if err := assertQueryNamespace(d.ns, d.hasNS); err != nil { |
+ return 0, err |
+ } |
+ |
idx, head := d.data.getQuerySnaps(!fq.EventuallyConsistent()) |
ret, err = countQuery(fq, d.data.aid, d.ns, false, idx, head) |
if d.data.maybeAutoIndex(err) { |
@@ -168,8 +182,9 @@ func (d *dsImpl) Testable() ds.Testable { |
////////////////////////////////// txnDsImpl /////////////////////////////////// |
type txnDsImpl struct { |
- data *txnDataStoreData |
- ns string |
+ data *txnDataStoreData |
+ ns string |
+ hasNS bool |
} |
var _ ds.RawInterface = (*txnDsImpl)(nil) |
@@ -202,6 +217,10 @@ func (d *txnDsImpl) DecodeCursor(s string) (ds.Cursor, error) { |
} |
func (d *txnDsImpl) Run(q *ds.FinalizedQuery, cb ds.RawRunCB) error { |
+ if err := assertQueryNamespace(d.ns, d.hasNS); err != nil { |
+ return err |
+ } |
+ |
// note that autoIndex has no effect inside transactions. This is because |
// the transaction guarantees a consistent view of head at the time that the |
// transaction opens. At best, we could add the index on head, but then return |
@@ -215,6 +234,10 @@ func (d *txnDsImpl) Run(q *ds.FinalizedQuery, cb ds.RawRunCB) error { |
} |
func (d *txnDsImpl) Count(fq *ds.FinalizedQuery) (ret int64, err error) { |
+ if err := assertQueryNamespace(d.ns, d.hasNS); err != nil { |
+ return 0, err |
+ } |
+ |
return countQuery(fq, d.data.parent.aid, d.ns, true, d.data.snap, d.data.snap) |
} |
@@ -225,3 +248,15 @@ func (*txnDsImpl) RunInTransaction(func(c context.Context) error, *ds.Transactio |
func (*txnDsImpl) Testable() ds.Testable { |
return nil |
} |
+ |
+func assertQueryNamespace(ns string, hasNS bool) error { |
+ if ns == "" && hasNS { |
+ // The user has set an empty namespace. Datastore does not support this |
+ // for queries. |
+ // |
+ // Bug on file is: |
+ // https://code.google.com/p/googleappengine/issues/detail?id=12914 |
+ return errors.New("namespace may not be present and empty") |
+ } |
+ return nil |
+} |