| Index: go/src/infra/gae/libs/gae/helper/generic_key.go
 | 
| diff --git a/go/src/infra/gae/libs/gae/helper/generic_key.go b/go/src/infra/gae/libs/gae/helper/generic_key.go
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..892e2c32121d70e74013b3025f758db70334ddc3
 | 
| --- /dev/null
 | 
| +++ b/go/src/infra/gae/libs/gae/helper/generic_key.go
 | 
| @@ -0,0 +1,84 @@
 | 
| +// Copyright 2015 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +package helper
 | 
| +
 | 
| +import (
 | 
| +	"encoding/json"
 | 
| +	"infra/gae/libs/gae"
 | 
| +)
 | 
| +
 | 
| +// GenericDSKey is an implementation of gae.DSKey which doesn't rely on the
 | 
| +// SDK's implementation. It differs slightly in that it's not recursive (and
 | 
| +// thus cannot express some of the invalid Key's that the SDK implementation
 | 
| +// can). In particular, it's not possible to have a GenericDSKey in a namespace
 | 
| +// whose Parent() is in a different namespace.
 | 
| +//
 | 
| +// GenericDSKey also implements json.Marshaler and json.Unmarshaler so it's
 | 
| +// suitable for use in structs which need to serialize both to json and to
 | 
| +// datastore.
 | 
| +type GenericDSKey struct {
 | 
| +	appID     string
 | 
| +	namespace string
 | 
| +	toks      []gae.DSKeyTok
 | 
| +}
 | 
| +
 | 
| +var _ interface {
 | 
| +	gae.DSKey
 | 
| +	json.Marshaler
 | 
| +	json.Unmarshaler
 | 
| +} = (*GenericDSKey)(nil)
 | 
| +
 | 
| +// NewDSKeyToks creates a new GenericDSKey. It is the DSKey implementation
 | 
| +// returned from the various DSPropertyMap serialization routines, as well as
 | 
| +// the native key implementation for the in-memory implementation of gae.
 | 
| +func NewDSKeyToks(appID, ns string, toks []gae.DSKeyTok) *GenericDSKey {
 | 
| +	newToks := make([]gae.DSKeyTok, len(toks))
 | 
| +	copy(newToks, toks)
 | 
| +	return &GenericDSKey{appID, ns, newToks}
 | 
| +}
 | 
| +
 | 
| +// NewDSKey is a wrapper around NewDSKeyToks which has an interface similar
 | 
| +// to NewKey in the SDK.
 | 
| +func NewDSKey(appID, ns, kind, stringID string, intID int64, parent gae.DSKey) *GenericDSKey {
 | 
| +	_, _, toks := DSKeySplit(parent)
 | 
| +	newToks := make([]gae.DSKeyTok, len(toks))
 | 
| +	copy(newToks, toks)
 | 
| +	newToks = append(newToks, gae.DSKeyTok{Kind: kind, StringID: stringID, IntID: intID})
 | 
| +	return &GenericDSKey{appID, ns, newToks}
 | 
| +}
 | 
| +
 | 
| +func (k *GenericDSKey) lastTok() (ret gae.DSKeyTok) {
 | 
| +	if len(k.toks) > 0 {
 | 
| +		ret = k.toks[len(k.toks)-1]
 | 
| +	}
 | 
| +	return
 | 
| +}
 | 
| +
 | 
| +func (k *GenericDSKey) AppID() string     { return k.appID }
 | 
| +func (k *GenericDSKey) Namespace() string { return k.namespace }
 | 
| +func (k *GenericDSKey) Kind() string      { return k.lastTok().Kind }
 | 
| +func (k *GenericDSKey) StringID() string  { return k.lastTok().StringID }
 | 
| +func (k *GenericDSKey) IntID() int64      { return k.lastTok().IntID }
 | 
| +func (k *GenericDSKey) String() string    { return DSKeyString(k) }
 | 
| +
 | 
| +func (k *GenericDSKey) MarshalJSON() ([]byte, error) {
 | 
| +	return DSKeyMarshalJSON(k)
 | 
| +}
 | 
| +
 | 
| +func (k *GenericDSKey) UnmarshalJSON(buf []byte) error {
 | 
| +	appID, namespace, toks, err := DSKeyUnmarshalJSON(buf)
 | 
| +	if err != nil {
 | 
| +		return err
 | 
| +	}
 | 
| +	*k = *NewDSKeyToks(appID, namespace, toks)
 | 
| +	return nil
 | 
| +}
 | 
| +
 | 
| +func (k *GenericDSKey) Parent() gae.DSKey {
 | 
| +	if len(k.toks) <= 1 {
 | 
| +		return nil
 | 
| +	}
 | 
| +	return &GenericDSKey{k.appID, k.namespace, k.toks[:len(k.toks)-1]}
 | 
| +}
 | 
| 
 |