github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/datastore/key.go (about)

     1  // Copyright 2011 Google Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache 2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package datastore
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"encoding/gob"
    11  	"errors"
    12  	"fmt"
    13  	"strconv"
    14  	"strings"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"golang.org/x/net/context"
    18  
    19  	"google.golang.org/appengine/internal"
    20  	pb "google.golang.org/appengine/internal/datastore"
    21  )
    22  
    23  // Key represents the datastore key for a stored entity, and is immutable.
    24  type Key struct {
    25  	kind      string
    26  	stringID  string
    27  	intID     int64
    28  	parent    *Key
    29  	appID     string
    30  	namespace string
    31  }
    32  
    33  // Kind returns the key's kind (also known as entity type).
    34  func (k *Key) Kind() string {
    35  	return k.kind
    36  }
    37  
    38  // StringID returns the key's string ID (also known as an entity name or key
    39  // name), which may be "".
    40  func (k *Key) StringID() string {
    41  	return k.stringID
    42  }
    43  
    44  // IntID returns the key's integer ID, which may be 0.
    45  func (k *Key) IntID() int64 {
    46  	return k.intID
    47  }
    48  
    49  // Parent returns the key's parent key, which may be nil.
    50  func (k *Key) Parent() *Key {
    51  	return k.parent
    52  }
    53  
    54  // AppID returns the key's application ID.
    55  func (k *Key) AppID() string {
    56  	return k.appID
    57  }
    58  
    59  // Namespace returns the key's namespace.
    60  func (k *Key) Namespace() string {
    61  	return k.namespace
    62  }
    63  
    64  // Incomplete returns whether the key does not refer to a stored entity.
    65  // In particular, whether the key has a zero StringID and a zero IntID.
    66  func (k *Key) Incomplete() bool {
    67  	return k.stringID == "" && k.intID == 0
    68  }
    69  
    70  // valid returns whether the key is valid.
    71  func (k *Key) valid() bool {
    72  	if k == nil {
    73  		return false
    74  	}
    75  	for ; k != nil; k = k.parent {
    76  		if k.kind == "" || k.appID == "" {
    77  			return false
    78  		}
    79  		if k.stringID != "" && k.intID != 0 {
    80  			return false
    81  		}
    82  		if k.parent != nil {
    83  			if k.parent.Incomplete() {
    84  				return false
    85  			}
    86  			if k.parent.appID != k.appID || k.parent.namespace != k.namespace {
    87  				return false
    88  			}
    89  		}
    90  	}
    91  	return true
    92  }
    93  
    94  // Equal returns whether two keys are equal.
    95  func (k *Key) Equal(o *Key) bool {
    96  	for k != nil && o != nil {
    97  		if k.kind != o.kind || k.stringID != o.stringID || k.intID != o.intID || k.appID != o.appID || k.namespace != o.namespace {
    98  			return false
    99  		}
   100  		k, o = k.parent, o.parent
   101  	}
   102  	return k == o
   103  }
   104  
   105  // root returns the furthest ancestor of a key, which may be itself.
   106  func (k *Key) root() *Key {
   107  	for k.parent != nil {
   108  		k = k.parent
   109  	}
   110  	return k
   111  }
   112  
   113  // marshal marshals the key's string representation to the buffer.
   114  func (k *Key) marshal(b *bytes.Buffer) {
   115  	if k.parent != nil {
   116  		k.parent.marshal(b)
   117  	}
   118  	b.WriteByte('/')
   119  	b.WriteString(k.kind)
   120  	b.WriteByte(',')
   121  	if k.stringID != "" {
   122  		b.WriteString(k.stringID)
   123  	} else {
   124  		b.WriteString(strconv.FormatInt(k.intID, 10))
   125  	}
   126  }
   127  
   128  // String returns a string representation of the key.
   129  func (k *Key) String() string {
   130  	if k == nil {
   131  		return ""
   132  	}
   133  	b := bytes.NewBuffer(make([]byte, 0, 512))
   134  	k.marshal(b)
   135  	return b.String()
   136  }
   137  
   138  type gobKey struct {
   139  	Kind      string
   140  	StringID  string
   141  	IntID     int64
   142  	Parent    *gobKey
   143  	AppID     string
   144  	Namespace string
   145  }
   146  
   147  func keyToGobKey(k *Key) *gobKey {
   148  	if k == nil {
   149  		return nil
   150  	}
   151  	return &gobKey{
   152  		Kind:      k.kind,
   153  		StringID:  k.stringID,
   154  		IntID:     k.intID,
   155  		Parent:    keyToGobKey(k.parent),
   156  		AppID:     k.appID,
   157  		Namespace: k.namespace,
   158  	}
   159  }
   160  
   161  func gobKeyToKey(gk *gobKey) *Key {
   162  	if gk == nil {
   163  		return nil
   164  	}
   165  	return &Key{
   166  		kind:      gk.Kind,
   167  		stringID:  gk.StringID,
   168  		intID:     gk.IntID,
   169  		parent:    gobKeyToKey(gk.Parent),
   170  		appID:     gk.AppID,
   171  		namespace: gk.Namespace,
   172  	}
   173  }
   174  
   175  func (k *Key) GobEncode() ([]byte, error) {
   176  	buf := new(bytes.Buffer)
   177  	if err := gob.NewEncoder(buf).Encode(keyToGobKey(k)); err != nil {
   178  		return nil, err
   179  	}
   180  	return buf.Bytes(), nil
   181  }
   182  
   183  func (k *Key) GobDecode(buf []byte) error {
   184  	gk := new(gobKey)
   185  	if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil {
   186  		return err
   187  	}
   188  	*k = *gobKeyToKey(gk)
   189  	return nil
   190  }
   191  
   192  func (k *Key) MarshalJSON() ([]byte, error) {
   193  	return []byte(`"` + k.Encode() + `"`), nil
   194  }
   195  
   196  func (k *Key) UnmarshalJSON(buf []byte) error {
   197  	if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' {
   198  		return errors.New("datastore: bad JSON key")
   199  	}
   200  	k2, err := DecodeKey(string(buf[1 : len(buf)-1]))
   201  	if err != nil {
   202  		return err
   203  	}
   204  	*k = *k2
   205  	return nil
   206  }
   207  
   208  // Encode returns an opaque representation of the key
   209  // suitable for use in HTML and URLs.
   210  // This is compatible with the Python and Java runtimes.
   211  func (k *Key) Encode() string {
   212  	ref := keyToProto("", k)
   213  
   214  	b, err := proto.Marshal(ref)
   215  	if err != nil {
   216  		panic(err)
   217  	}
   218  
   219  	// Trailing padding is stripped.
   220  	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
   221  }
   222  
   223  // DecodeKey decodes a key from the opaque representation returned by Encode.
   224  func DecodeKey(encoded string) (*Key, error) {
   225  	// Re-add padding.
   226  	if m := len(encoded) % 4; m != 0 {
   227  		encoded += strings.Repeat("=", 4-m)
   228  	}
   229  
   230  	b, err := base64.URLEncoding.DecodeString(encoded)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	ref := new(pb.Reference)
   236  	if err := proto.Unmarshal(b, ref); err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	return protoToKey(ref)
   241  }
   242  
   243  // NewIncompleteKey creates a new incomplete key.
   244  // kind cannot be empty.
   245  func NewIncompleteKey(c context.Context, kind string, parent *Key) *Key {
   246  	return NewKey(c, kind, "", 0, parent)
   247  }
   248  
   249  // NewKey creates a new key.
   250  // kind cannot be empty.
   251  // Either one or both of stringID and intID must be zero. If both are zero,
   252  // the key returned is incomplete.
   253  // parent must either be a complete key or nil.
   254  func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key {
   255  	// If there's a parent key, use its namespace.
   256  	// Otherwise, use any namespace attached to the context.
   257  	var namespace string
   258  	if parent != nil {
   259  		namespace = parent.namespace
   260  	} else {
   261  		namespace = internal.NamespaceFromContext(c)
   262  	}
   263  
   264  	return &Key{
   265  		kind:      kind,
   266  		stringID:  stringID,
   267  		intID:     intID,
   268  		parent:    parent,
   269  		appID:     internal.FullyQualifiedAppID(c),
   270  		namespace: namespace,
   271  	}
   272  }
   273  
   274  // AllocateIDs returns a range of n integer IDs with the given kind and parent
   275  // combination. kind cannot be empty; parent may be nil. The IDs in the range
   276  // returned will not be used by the datastore's automatic ID sequence generator
   277  // and may be used with NewKey without conflict.
   278  //
   279  // The range is inclusive at the low end and exclusive at the high end. In
   280  // other words, valid intIDs x satisfy low <= x && x < high.
   281  //
   282  // If no error is returned, low + n == high.
   283  func AllocateIDs(c context.Context, kind string, parent *Key, n int) (low, high int64, err error) {
   284  	if kind == "" {
   285  		return 0, 0, errors.New("datastore: AllocateIDs given an empty kind")
   286  	}
   287  	if n < 0 {
   288  		return 0, 0, fmt.Errorf("datastore: AllocateIDs given a negative count: %d", n)
   289  	}
   290  	if n == 0 {
   291  		return 0, 0, nil
   292  	}
   293  	req := &pb.AllocateIdsRequest{
   294  		ModelKey: keyToProto("", NewIncompleteKey(c, kind, parent)),
   295  		Size:     proto.Int64(int64(n)),
   296  	}
   297  	res := &pb.AllocateIdsResponse{}
   298  	if err := internal.Call(c, "datastore_v3", "AllocateIds", req, res); err != nil {
   299  		return 0, 0, err
   300  	}
   301  	// The protobuf is inclusive at both ends. Idiomatic Go (e.g. slices, for loops)
   302  	// is inclusive at the low end and exclusive at the high end, so we add 1.
   303  	low = res.GetStart()
   304  	high = res.GetEnd() + 1
   305  	if low+int64(n) != high {
   306  		return 0, 0, fmt.Errorf("datastore: internal error: could not allocate %d IDs", n)
   307  	}
   308  	return low, high, nil
   309  }