func (d *dataStoreData) allocateIDs(incomplete *ds.Key, n int) (int64, error) { d.Lock() defer d.Unlock() ents := d.mutableEntsLocked(incomplete.Namespace()) return d.allocateIDsLocked(ents, incomplete, n) }
// Split splits the key into its constituent parts. Note that if the key is // not Valid, this method may not provide a round-trip for k. func Split(k ds.Key) (appID, namespace string, toks []ds.KeyTok) { if k == nil { return } if sk, ok := k.(*Generic); ok { if sk == nil { return } return sk.appID, sk.namespace, sk.toks } n := 0 for i := k; i != nil; i = i.Parent() { n++ } toks = make([]ds.KeyTok, n) for i := k; i != nil; i = i.Parent() { n-- toks[n].IntID = i.IntID() toks[n].StringID = i.StringID() toks[n].Kind = i.Kind() } appID = k.AppID() namespace = k.Namespace() return }
// Valid determines if a key is valid, according to a couple rules: // - k is not nil // - every token of k: // - (if !allowSpecial) token's kind doesn't start with '__' // - token's kind and appid are non-blank // - token is not incomplete // - all tokens have the same namespace and appid func Valid(k ds.Key, allowSpecial bool, aid, ns string) bool { if k == nil { return false } if aid != k.AppID() || ns != k.Namespace() { return false } for ; k != nil; k = k.Parent() { if !allowSpecial && len(k.Kind()) >= 2 && k.Kind()[:2] == "__" { return false } if k.Kind() == "" || k.AppID() == "" { return false } if k.StringID() != "" && k.IntID() != 0 { return false } if k.Parent() != nil { if k.Parent().Incomplete() { return false } if k.Parent().AppID() != k.AppID() || k.Parent().Namespace() != k.Namespace() { return false } } } return true }
func (q *queryImpl) Ancestor(k ds.Key) ds.Query { return q.checkMutateClone( func() error { if k == nil { // SDK has an explicit nil-check return errors.New("datastore: nil query ancestor") } if k.Namespace() != q.ns { return fmt.Errorf("bad namespace: %q (expected %q)", k.Namespace(), q.ns) } if !k.Valid(false, globalAppID, q.ns) { // technically the SDK implementation does a Weird Thing (tm) if both the // stringID and intID are set on a key; it only serializes the stringID in // the proto. This means that if you set the Ancestor to an invalid key, // you'll never actually hear about it. Instead of doing that insanity, we // just swap to an error here. return ds.ErrInvalidKey } if q.eqFilters["__ancestor__"] != nil { return errors.New("cannot have more than one ancestor") } return nil }, func(q *queryImpl) { q.addEqFilt("__ancestor__", ds.MkProperty(k)) }) }
func (d *dataStoreData) fixKeyLocked(ents *memCollection, key *ds.Key) (*ds.Key, error) { if key.Incomplete() { id, err := d.allocateIDsLocked(ents, key, 1) if err != nil { return key, err } key = ds.NewKey(key.AppID(), key.Namespace(), key.Kind(), "", id, key.Parent()) } return key, nil }
func updateIndexes(store *memStore, key ds.Key, oldEnt, newEnt ds.PropertyMap) { // load all current complex query index definitions. compIdx := []*ds.IndexDefinition{} walkCompIdxs(store, nil, func(i *ds.IndexDefinition) bool { compIdx = append(compIdx, i) return true }) mergeIndexes(key.Namespace(), store, indexEntriesWithBuiltins(key, oldEnt, compIdx), indexEntriesWithBuiltins(key, newEnt, compIdx)) }
// Equal returns true iff the two keys represent identical key values. func Equal(a, b ds.Key) (ret bool) { ret = (a.Kind() == b.Kind() && a.StringID() == b.StringID() && a.IntID() == b.IntID() && a.AppID() == b.AppID() && a.Namespace() == b.Namespace()) if !ret { return } ap, bp := a.Parent(), b.Parent() return (ap == nil && bp == nil) || Equal(ap, bp) }
func (d *dataStoreData) entsKeyLocked(key ds.Key) (*memCollection, ds.Key) { coll := "ents:" + key.Namespace() ents := d.head.GetCollection(coll) if ents == nil { ents = d.head.SetCollection(coll, nil) } if dskey.Incomplete(key) { idKey := []byte(nil) if key.Parent() == nil { idKey = rootIDsKey(key.Kind()) } else { idKey = groupIDsKey(key) } id := incrementLocked(ents, idKey) key = dskey.New(key.AppID(), key.Namespace(), key.Kind(), "", id, key.Parent()) } return ents, key }
// Encode encodes the provided key as a base64-encoded protobuf. // // This encoding is compatible with the SDK-provided encoding and is agnostic // to the underlying implementation of the Key. // // It's encoded with the urlsafe base64 table. func Encode(k ds.Key) string { n := 0 for i := k; i != nil; i = i.Parent() { n++ } e := make([]*pb.Path_Element, n) for i := k; i != nil; i = i.Parent() { n-- kind := i.Kind() e[n] = &pb.Path_Element{ Type: &kind, } // At most one of {Name,Id} should be set. // Neither will be set for incomplete keys. if i.StringID() != "" { sid := i.StringID() e[n].Name = &sid } else if i.IntID() != 0 { iid := i.IntID() e[n].Id = &iid } } var namespace *string if k.Namespace() != "" { namespace = proto.String(k.Namespace()) } r, err := proto.Marshal(&pb.Reference{ App: proto.String(k.AppID()), NameSpace: namespace, Path: &pb.Path{ Element: e, }, }) if err != nil { panic(err) } // trim padding return strings.TrimRight(base64.URLEncoding.EncodeToString(r), "=") }
func indexEntriesWithBuiltins(k ds.Key, pm ds.PropertyMap, complexIdxs []*ds.IndexDefinition) *memStore { sip := partiallySerialize(k, pm) return sip.indexEntries(k.Namespace(), append(defaultIndexes(k.Kind(), pm), complexIdxs...)) }
// PartialValid returns true iff this key is suitable for use in a Put // operation. This is the same as Valid(k, false, ...), but also allowing k to // be Incomplete(). func PartialValid(k ds.Key, aid, ns string) bool { if k.Incomplete() { k = New(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent()) } return Valid(k, false, aid, ns) }