datastore: add metadata accessor functions

New functions are:
- EntityGroupVersion
- Namespaces
- Kinds
- KindProperties

Change-Id: I6168a31cd11a0393c1e3791f16770f551f956f37
diff --git a/datastore/doc.go b/datastore/doc.go
index 5632164..92ffe6d 100644
--- a/datastore/doc.go
+++ b/datastore/doc.go
@@ -312,5 +312,40 @@
 		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 		fmt.Fprintf(w, "Count=%d", count)
 	}
+
+
+Metadata
+
+The datastore package provides access to some of App Engine's datastore
+metadata. This metadata includes information about the entity groups,
+namespaces, entity kinds, and properties in the datastore, as well as the
+property representations for each property.
+
+Example code:
+
+	func handle(w http.ResponseWriter, r *http.Request) {
+		// Print all the kinds in the datastore, with all the indexed
+		// properties (and their representations) for each.
+		ctx := appengine.NewContext(r)
+
+		kinds, err := datastore.Kinds(ctx)
+		if err != nil {
+			serveError(ctx, w, err)
+			return
+		}
+
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		for _, kind := range kinds {
+			fmt.Fprintf(w, "%s:\n", kind)
+			props, err := datastore.KindProperties(ctx, kind)
+			if err != nil {
+				fmt.Fprintln(w, "\t(unable to retrieve properties)")
+				continue
+			}
+			for p, rep := range props {
+				fmt.Fprintf(w, "\t-%s (%s)\n", p, strings.Join(", ", rep))
+			}
+		}
+	}
 */
 package datastore // import "google.golang.org/appengine/datastore"
diff --git a/datastore/metadata.go b/datastore/metadata.go
new file mode 100644
index 0000000..3192a31
--- /dev/null
+++ b/datastore/metadata.go
@@ -0,0 +1,79 @@
+// Copyright 2016 Google Inc. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+package datastore
+
+import "golang.org/x/net/context"
+
+// Datastore kinds for the metadata entities.
+const (
+	namespaceKind   = "__namespace__"
+	kindKind        = "__kind__"
+	propertyKind    = "__property__"
+	entityGroupKind = "__entitygroup__"
+)
+
+// Namespaces returns all the datastore namespaces.
+func Namespaces(ctx context.Context) ([]string, error) {
+	// TODO(djd): Support range queries.
+	q := NewQuery(namespaceKind).KeysOnly()
+	keys, err := q.GetAll(ctx, nil)
+	if err != nil {
+		return nil, err
+	}
+	// The empty namespace key uses a numeric ID (==1), but luckily
+	// the string ID defaults to "" for numeric IDs anyway.
+	return keyNames(keys), nil
+}
+
+// Kinds returns the names of all the kinds in the current namespace.
+func Kinds(ctx context.Context) ([]string, error) {
+	// TODO(djd): Support range queries.
+	q := NewQuery(kindKind).KeysOnly()
+	keys, err := q.GetAll(ctx, nil)
+	if err != nil {
+		return nil, err
+	}
+	return keyNames(keys), nil
+}
+
+// keyNames returns a slice of the provided keys' names (string IDs).
+func keyNames(keys []*Key) []string {
+	n := make([]string, 0, len(keys))
+	for _, k := range keys {
+		n = append(n, k.StringID())
+	}
+	return n
+}
+
+// KindProperties returns all the indexed properties for the given kind.
+// The properties are returned as a map of property names to a slice of the
+// representation types. The representation types for the supported Go property
+// types are:
+//   "INT64":     signed integers and time.Time
+//   "DOUBLE":    float32 and float64
+//   "BOOLEAN":   bool
+//   "STRING":    string, []byte and ByteString
+//   "POINT":     appengine.GeoPoint
+//   "REFERENCE": *Key
+//   "USER":      (not used in the Go runtime)
+func KindProperties(ctx context.Context, kind string) (map[string][]string, error) {
+	// TODO(djd): Support range queries.
+	kindKey := NewKey(ctx, kindKind, kind, 0, nil)
+	q := NewQuery(propertyKind).Ancestor(kindKey)
+
+	propMap := map[string][]string{}
+	props := []struct {
+		Repr []string `datastore:property_representation`
+	}{}
+
+	keys, err := q.GetAll(ctx, &props)
+	if err != nil {
+		return nil, err
+	}
+	for i, p := range props {
+		propMap[keys[i].StringID()] = p.Repr
+	}
+	return propMap, nil
+}