Source code for google.appengine.ext.db.metadata

#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#




"""Models and helper functions for access to app's datastore metadata.

These entities cannot be created by users, but are created as results of
__namespace__, __kind__ and __property__ metadata queries such as

  # Find all namespaces
  q = db.GqlQuery("SELECT * FROM __namespace__")
  for p in q.run():
    print "namespace:", repr(p.namespace_name)

or

  # Find all properties of A whose name starts with a lower-case letter
  q = db.GqlQuery("SELECT __key__ from __property__ " +
                  "WHERE __key__ >= :1 AND __key__ < :2",
                  Property.key_for_property("A", "a"),
                  Property.key_for_property("A", chr(ord("z") + 1)))
  for p in q.run():
    print "%s: %s" % (Property.key_to_kind(p), Property.key_to_property(p))

or, using Query objects

  # Find all kinds >= "a"
  q = metadata.Kind().all()
  q.filter("__key__ >=", metadata.Kind.key_for_kind("a"))
  for p in q.run():
    print "kind:", repr(p.kind_name)
"""








import os


if os.environ.get('APPENGINE_RUNTIME') == 'python27':
  from google.appengine.api import datastore_types
  from google.appengine.ext import db
else:
  from google.appengine.api import datastore_types
  from google.appengine.ext import db


[docs]class BaseMetadata(db.Model): """Base class for all metadata models.""" KIND_NAME = '__BaseMetadata__'
[docs] @classmethod def kind(cls): """Kind name override.""" return cls.KIND_NAME
[docs]class Namespace(BaseMetadata): """Model for __namespace__ metadata query results.""" KIND_NAME = '__namespace__' EMPTY_NAMESPACE_ID = datastore_types._EMPTY_NAMESPACE_ID @property def namespace_name(self): """Return the namespace name specified by this entity's key.""" return self.key_to_namespace(self.key())
[docs] @classmethod def key_for_namespace(cls, namespace): """Return the __namespace__ key for namespace. Args: namespace: namespace whose key is requested. Returns: The key for namespace. """ if namespace: return db.Key.from_path(cls.KIND_NAME, namespace) else: return db.Key.from_path(cls.KIND_NAME, cls.EMPTY_NAMESPACE_ID)
[docs] @classmethod def key_to_namespace(cls, key): """Return the namespace specified by a given __namespace__ key. Args: key: key whose name is requested. Returns: The namespace specified by key. """ return key.name() or ''
[docs]class Kind(BaseMetadata): """Model for __kind__ metadata query results.""" KIND_NAME = '__kind__' @property def kind_name(self): """Return the kind name specified by this entity's key.""" return self.key_to_kind(self.key())
[docs] @classmethod def key_for_kind(cls, kind): """Return the __kind__ key for kind. Args: kind: kind whose key is requested. Returns: The key for kind. """ return db.Key.from_path(cls.KIND_NAME, kind)
[docs] @classmethod def key_to_kind(cls, key): """Return the kind specified by a given __kind__ key. Args: key: key whose name is requested. Returns: The kind specified by key. """ return key.name()
[docs]class Property(BaseMetadata): """Model for __property__ metadata query results.""" KIND_NAME = '__property__' @property def property_name(self): """Return the property name specified by this entity's key.""" return self.key_to_property(self.key()) @property def kind_name(self): """Return the kind name specified by this entity's key.""" return self.key_to_kind(self.key()) property_representation = db.StringListProperty()
[docs] @classmethod def key_for_kind(cls, kind): """Return the __property__ key for kind. Args: kind: kind whose key is requested. Returns: The parent key for __property__ keys of kind. """ return db.Key.from_path(Kind.KIND_NAME, kind)
[docs] @classmethod def key_for_property(cls, kind, property): """Return the __property__ key for property of kind. Args: kind: kind whose key is requested. property: property whose key is requested. Returns: The key for property of kind. """ return db.Key.from_path(Kind.KIND_NAME, kind, Property.KIND_NAME, property)
[docs] @classmethod def key_to_kind(cls, key): """Return the kind specified by a given __property__ key. Args: key: key whose kind name is requested. Returns: The kind specified by key. """ if key.kind() == Kind.KIND_NAME: return key.name() else: return key.parent().name()
[docs] @classmethod def key_to_property(cls, key): """Return the property specified by a given __property__ key. Args: key: key whose property name is requested. Returns: property specified by key, or None if the key specified only a kind. """ if key.kind() == Kind.KIND_NAME: return None else: return key.name()
[docs]class EntityGroup(BaseMetadata): """Model for __entity_group__ metadata (available in HR datastore only). This metadata contains a numeric __version__ property that is guaranteed to increase on every change to the entity group. The version may increase even in the absence of user-visible changes to the entity group. The __entity_group__ entity may not exist None if the entity group was never written to. """ KIND_NAME = '__entity_group__' ID = 1 version = db.IntegerProperty(name='__version__')
[docs] @classmethod def key_for_entity(cls, entity_or_key): """Return the metadata key for the entity group containing entity_or_key. Use this key to get() the __entity_group__ metadata entity for the entity group containing entity_or_key. Args: entity_or_key: a key or entity whose __entity_group__ key you want. Returns: The __entity_group__ key for the entity group containing entity_or_key. """ if isinstance(entity_or_key, db.Model): key = entity_or_key.key() else: key = entity_or_key while key.parent(): key = key.parent() return db.Key.from_path(cls.KIND_NAME, cls.ID, parent=key)
[docs]def get_namespaces(start=None, end=None): """Return all namespaces in the specified range. Args: start: only return namespaces >= start if start is not None. end: only return namespaces < end if end is not None. Returns: A list of namespace names between the (optional) start and end values. """ q = Namespace.all() if start is not None: q.filter('__key__ >=', Namespace.key_for_namespace(start)) if end is not None: q.filter('__key__ <', Namespace.key_for_namespace(end)) return [x.namespace_name for x in q.run()]
[docs]def get_kinds(start=None, end=None): """Return all kinds in the specified range. Args: start: only return kinds >= start if start is not None. end: only return kinds < end if end is not None. Returns: A list of kind names between the (optional) start and end values. """ q = Kind.all() if start is not None and start != '': q.filter('__key__ >=', Kind.key_for_kind(start)) if end is not None: if end == '': return [] q.filter('__key__ <', Kind.key_for_kind(end)) return [x.kind_name for x in q.run()]
[docs]def get_properties_of_kind(kind, start=None, end=None): """Return all properties of kind in the specified range. NOTE: This function does not return unindexed properties. Args: kind: name of kind whose properties you want. start: only return properties >= start if start is not None. end: only return properties < end if end is not None. Returns: A list of property names of kind between the (optional) start and end values. """ q = Property.all(keys_only=True) q.ancestor(Property.key_for_kind(kind)) if start is not None and start != '': q.filter('__key__ >=', Property.key_for_property(kind, start)) if end is not None: if end == '': return [] q.filter('__key__ <', Property.key_for_property(kind, end)) return [Property.key_to_property(x) for x in q.run()]
[docs]def get_representations_of_kind(kind, start=None, end=None): """Return all representations of properties of kind in the specified range. NOTE: This function does not return unindexed properties. Args: kind: name of kind whose properties you want. start: only return properties >= start if start is not None. end: only return properties < end if end is not None. Returns: A dictionary mapping property names to its list of representations. """ q = Property.all() q.ancestor(Property.key_for_kind(kind)) if start is not None and start != '': q.filter('__key__ >=', Property.key_for_property(kind, start)) if end is not None: if end == '': return {} q.filter('__key__ <', Property.key_for_property(kind, end)) result = {} for property in q.run(): result[property.property_name] = property.property_representation return result
[docs]def get_entity_group_version(entity_or_key): """Return the version of the entity group containing entity_or_key. Args: entity_or_key: a key or entity whose version you want. Returns: The version of the entity group containing entity_or_key. This version is guaranteed to increase on every change to the entity group. The version may increase even in the absence of user-visible changes to the entity group. May return None if the entity group was never written to. On non-HR datatores, this function returns None. """ eg = db.get(EntityGroup.key_for_entity(entity_or_key)) if eg: return eg.version else: return None