thirdparty/google_appengine/google/appengine/api/datastore.py
changeset 2309 be1b94099f2d
parent 1278 a7766286a7be
child 2413 d0b7dac5325c
equal deleted inserted replaced
2307:81c128f487e6 2309:be1b94099f2d
   272   """A datastore entity.
   272   """A datastore entity.
   273 
   273 
   274   Includes read-only accessors for app id, kind, and primary key. Also
   274   Includes read-only accessors for app id, kind, and primary key. Also
   275   provides dictionary-style access to properties.
   275   provides dictionary-style access to properties.
   276   """
   276   """
   277   def __init__(self, kind, parent=None, _app=None, name=None):
   277   def __init__(self, kind, parent=None, _app=None, name=None,
       
   278                unindexed_properties=[]):
   278     """Constructor. Takes the kind and transaction root, which cannot be
   279     """Constructor. Takes the kind and transaction root, which cannot be
   279     changed after the entity is constructed, and an optional parent. Raises
   280     changed after the entity is constructed, and an optional parent. Raises
   280     BadArgumentError or BadKeyError if kind is invalid or parent is not an
   281     BadArgumentError or BadKeyError if kind is invalid or parent is not an
   281     existing Entity or Key in the datastore.
   282     existing Entity or Key in the datastore.
   282 
   283 
   285       kind: string
   286       kind: string
   286       # if provided, this entity's parent. Its key must be complete.
   287       # if provided, this entity's parent. Its key must be complete.
   287       parent: Entity or Key
   288       parent: Entity or Key
   288       # if provided, this entity's name.
   289       # if provided, this entity's name.
   289       name: string
   290       name: string
       
   291       # if provided, a sequence of property names that should not be indexed
       
   292       # by the built-in single property indices.
       
   293       unindexed_properties: list or tuple of strings
   290     """
   294     """
   291     ref = entity_pb.Reference()
   295     ref = entity_pb.Reference()
   292     _app = datastore_types.ResolveAppId(_app)
   296     _app = datastore_types.ResolveAppId(_app)
   293     ref.set_app(_app)
   297     ref.set_app(_app)
   294 
   298 
   309       datastore_types.ValidateString(name, 'name')
   313       datastore_types.ValidateString(name, 'name')
   310       if name[0] in string.digits:
   314       if name[0] in string.digits:
   311         raise datastore_errors.BadValueError('name cannot begin with a digit')
   315         raise datastore_errors.BadValueError('name cannot begin with a digit')
   312       last_path.set_name(name.encode('utf-8'))
   316       last_path.set_name(name.encode('utf-8'))
   313 
   317 
       
   318     unindexed_properties, multiple = NormalizeAndTypeCheck(unindexed_properties, basestring)
       
   319     if not multiple:
       
   320       raise datastore_errors.BadArgumentError(
       
   321         'unindexed_properties must be a sequence; received %s (a %s).' %
       
   322         (unindexed_properties, typename(unindexed_properties)))
       
   323     for prop in unindexed_properties:
       
   324       datastore_types.ValidateProperty(prop, None)
       
   325     self.__unindexed_properties = frozenset(unindexed_properties)
       
   326 
   314     self.__key = Key._FromPb(ref)
   327     self.__key = Key._FromPb(ref)
   315 
   328 
   316   def app(self):
   329   def app(self):
   317     """Returns the name of the application that created this entity, a
   330     """Returns the name of the application that created this entity, a
   318     string.
   331     string.
   334     returns None.
   347     returns None.
   335     """
   348     """
   336     return self.key().parent()
   349     return self.key().parent()
   337 
   350 
   338   def entity_group(self):
   351   def entity_group(self):
   339     """Returns this entitys's entity group as a Key.
   352     """Returns this entity's entity group as a Key.
   340 
   353 
   341     Note that the returned Key will be incomplete if this is a a root entity
   354     Note that the returned Key will be incomplete if this is a a root entity
   342     and its key is incomplete.
   355     and its key is incomplete.
   343     """
   356     """
   344     return self.key().entity_group()
   357     return self.key().entity_group()
       
   358 
       
   359   def unindexed_properties(self):
       
   360     """Returns this entity's unindexed properties, as a frozenset of strings."""
       
   361     return self.__unindexed_properties
   345 
   362 
   346   def __setitem__(self, name, value):
   363   def __setitem__(self, name, value):
   347     """Implements the [] operator. Used to set property value(s).
   364     """Implements the [] operator. Used to set property value(s).
   348 
   365 
   349     If the property name is the empty string or not a string, raises
   366     If the property name is the empty string or not a string, raises
   490 
   507 
   491       sample = values
   508       sample = values
   492       if isinstance(sample, list):
   509       if isinstance(sample, list):
   493         sample = values[0]
   510         sample = values[0]
   494 
   511 
   495       if isinstance(sample, datastore_types._RAW_PROPERTY_TYPES):
   512       if (isinstance(sample, datastore_types._RAW_PROPERTY_TYPES) or
       
   513           name in self.__unindexed_properties):
   496         pb.raw_property_list().extend(properties)
   514         pb.raw_property_list().extend(properties)
   497       else:
   515       else:
   498         pb.property_list().extend(properties)
   516         pb.property_list().extend(properties)
   499 
   517 
   500     if pb.property_size() > _MAX_INDEXED_PROPERTIES:
   518     if pb.property_size() > _MAX_INDEXED_PROPERTIES:
   528       assert last_path.id() != 0
   546       assert last_path.id() != 0
   529     else:
   547     else:
   530       assert last_path.has_name()
   548       assert last_path.has_name()
   531       assert last_path.name()
   549       assert last_path.name()
   532 
   550 
   533     e = Entity(unicode(last_path.type().decode('utf-8')))
   551     unindexed_properties = [p.name() for p in pb.raw_property_list()]
       
   552 
       
   553     e = Entity(unicode(last_path.type().decode('utf-8')),
       
   554                unindexed_properties=unindexed_properties)
   534     ref = e.__key._Key__reference
   555     ref = e.__key._Key__reference
   535     ref.CopyFrom(pb.key())
   556     ref.CopyFrom(pb.key())
   536 
   557 
   537     temporary_values = {}
   558     temporary_values = {}
   538 
   559 
   539     for prop_list in (pb.property_list(), pb.raw_property_list()):
   560     for prop_list in (pb.property_list(), pb.raw_property_list()):
   540       for prop in prop_list:
   561       for prop in prop_list:
   541         if not prop.has_multiple():
       
   542           raise datastore_errors.Error(
       
   543             'Property %s is corrupt in the datastore; it\'s missing the '
       
   544             'multiple valued field.' % prop.name())
       
   545 
       
   546         try:
   562         try:
   547           value = datastore_types.FromPropertyPb(prop)
   563           value = datastore_types.FromPropertyPb(prop)
   548         except (AssertionError, AttributeError, TypeError, ValueError), e:
   564         except (AssertionError, AttributeError, TypeError, ValueError), e:
   549           raise datastore_errors.Error(
   565           raise datastore_errors.Error(
   550             'Property %s is corrupt in the datastore. %s: %s' %
   566             'Property %s is corrupt in the datastore. %s: %s' %
   682   __filter_counter = 0
   698   __filter_counter = 0
   683 
   699 
   684   __inequality_prop = None
   700   __inequality_prop = None
   685   __inequality_count = 0
   701   __inequality_count = 0
   686 
   702 
   687   def __init__(self, kind, filters={}, _app=None):
   703   def __init__(self, kind, filters={}, _app=None, keys_only=False):
   688     """Constructor.
   704     """Constructor.
   689 
   705 
   690     Raises BadArgumentError if kind is not a string. Raises BadValueError or
   706     Raises BadArgumentError if kind is not a string. Raises BadValueError or
   691     BadFilterError if filters is not a dictionary of valid filters.
   707     BadFilterError if filters is not a dictionary of valid filters.
   692 
   708 
   693     Args:
   709     Args:
   694       # kind is required. filters is optional; if provided, it's used
   710       # kind is required. filters is optional; if provided, it's used
   695       # as an initial set of property filters.
   711       # as an initial set of property filters. keys_only defaults to False.
   696       kind: string
   712       kind: string
   697       filters: dict
   713       filters: dict
       
   714       keys_only: boolean
   698     """
   715     """
   699     datastore_types.ValidateString(kind, 'kind',
   716     datastore_types.ValidateString(kind, 'kind',
   700                                    datastore_errors.BadArgumentError)
   717                                    datastore_errors.BadArgumentError)
   701 
   718 
   702     self.__kind = kind
   719     self.__kind = kind
   703     self.__orderings = []
   720     self.__orderings = []
   704     self.__filter_order = {}
   721     self.__filter_order = {}
   705     self.update(filters)
   722     self.update(filters)
   706 
   723 
   707     self.__app = datastore_types.ResolveAppId(_app)
   724     self.__app = datastore_types.ResolveAppId(_app)
       
   725     self.__keys_only = keys_only
   708 
   726 
   709   def Order(self, *orderings):
   727   def Order(self, *orderings):
   710     """Specify how the query results should be sorted.
   728     """Specify how the query results should be sorted.
   711 
   729 
   712     Result entities will be sorted by the first property argument, then by the
   730     Result entities will be sorted by the first property argument, then by the
   844     """
   862     """
   845     key = _GetCompleteKeyOrError(ancestor)
   863     key = _GetCompleteKeyOrError(ancestor)
   846     self.__ancestor = datastore_pb.Reference()
   864     self.__ancestor = datastore_pb.Reference()
   847     self.__ancestor.CopyFrom(key._Key__reference)
   865     self.__ancestor.CopyFrom(key._Key__reference)
   848     return self
   866     return self
       
   867 
       
   868   def IsKeysOnly(self):
       
   869     """Returns True if this query is keys only, false otherwise."""
       
   870     return self.__keys_only
   849 
   871 
   850   def Run(self):
   872   def Run(self):
   851     """Runs this query.
   873     """Runs this query.
   852 
   874 
   853     If a filter string is invalid, raises BadFilterError. If a filter value is
   875     If a filter string is invalid, raises BadFilterError. If a filter value is
   888         yaml = datastore_index.IndexYamlForQuery(
   910         yaml = datastore_index.IndexYamlForQuery(
   889           *datastore_index.CompositeIndexForQuery(pb)[1:-1])
   911           *datastore_index.CompositeIndexForQuery(pb)[1:-1])
   890         raise datastore_errors.NeedIndexError(
   912         raise datastore_errors.NeedIndexError(
   891           str(exc) + '\nThis query needs this index:\n' + yaml)
   913           str(exc) + '\nThis query needs this index:\n' + yaml)
   892 
   914 
   893     return Iterator._FromPb(result.cursor())
   915     return Iterator._FromPb(result)
   894 
   916 
   895   def Get(self, limit, offset=0):
   917   def Get(self, limit, offset=0):
   896     """Fetches and returns a maximum number of results from the query.
   918     """Fetches and returns a maximum number of results from the query.
   897 
   919 
   898     This method fetches and returns a list of resulting entities that matched
   920     This method fetches and returns a list of resulting entities that matched
  1118       datastore_pb.Query
  1140       datastore_pb.Query
  1119     """
  1141     """
  1120     pb = datastore_pb.Query()
  1142     pb = datastore_pb.Query()
  1121 
  1143 
  1122     pb.set_kind(self.__kind.encode('utf-8'))
  1144     pb.set_kind(self.__kind.encode('utf-8'))
       
  1145     pb.set_keys_only(bool(self.__keys_only))
  1123     if self.__app:
  1146     if self.__app:
  1124       pb.set_app(self.__app.encode('utf-8'))
  1147       pb.set_app(self.__app.encode('utf-8'))
  1125     if limit is not None:
  1148     if limit is not None:
  1126       pb.set_limit(limit)
  1149       pb.set_limit(limit)
  1127     if offset is not None:
  1150     if offset is not None:
  1169 class MultiQuery(Query):
  1192 class MultiQuery(Query):
  1170   """Class representing a query which requires multiple datastore queries.
  1193   """Class representing a query which requires multiple datastore queries.
  1171 
  1194 
  1172   This class is actually a subclass of datastore.Query as it is intended to act
  1195   This class is actually a subclass of datastore.Query as it is intended to act
  1173   like a normal Query object (supporting the same interface).
  1196   like a normal Query object (supporting the same interface).
       
  1197 
       
  1198   Does not support keys only queries, since it needs whole entities in order
       
  1199   to merge sort them. (That's not true if there are no sort orders, or if the
       
  1200   sort order is on __key__, but allowing keys only queries in those cases, but
       
  1201   not in others, would be confusing.)
  1174   """
  1202   """
  1175 
  1203 
  1176   def __init__(self, bound_queries, orderings):
  1204   def __init__(self, bound_queries, orderings):
  1177     if len(bound_queries) > MAX_ALLOWABLE_QUERIES:
  1205     if len(bound_queries) > MAX_ALLOWABLE_QUERIES:
  1178       raise datastore_errors.BadArgumentError(
  1206       raise datastore_errors.BadArgumentError(
  1179           'Cannot satisfy query -- too many subqueries (max: %d, got %d).'
  1207           'Cannot satisfy query -- too many subqueries (max: %d, got %d).'
  1180           ' Probable cause: too many IN/!= filters in query.' %
  1208           ' Probable cause: too many IN/!= filters in query.' %
  1181           (MAX_ALLOWABLE_QUERIES, len(bound_queries)))
  1209           (MAX_ALLOWABLE_QUERIES, len(bound_queries)))
       
  1210 
       
  1211     for query in bound_queries:
       
  1212       if query.IsKeysOnly():
       
  1213         raise datastore_errors.BadQueryError(
       
  1214             'MultiQuery does not support keys_only.')
       
  1215 
  1182     self.__bound_queries = bound_queries
  1216     self.__bound_queries = bound_queries
  1183     self.__orderings = orderings
  1217     self.__orderings = orderings
  1184 
  1218 
  1185   def __str__(self):
  1219   def __str__(self):
  1186     res = 'MultiQuery: '
  1220     res = 'MultiQuery: '
  1292         if result:
  1326         if result:
  1293           return result
  1327           return result
  1294       return 0
  1328       return 0
  1295 
  1329 
  1296     def __GetValueForId(self, sort_order_entity, identifier, sort_order):
  1330     def __GetValueForId(self, sort_order_entity, identifier, sort_order):
  1297       value = sort_order_entity.__entity[identifier]
  1331       value = _GetPropertyValue(sort_order_entity.__entity, identifier)
  1298       entity_key = sort_order_entity.__entity.key()
  1332       entity_key = sort_order_entity.__entity.key()
  1299       if (entity_key, identifier) in self.__min_max_value_cache:
  1333       if (entity_key, identifier) in self.__min_max_value_cache:
  1300         value = self.__min_max_value_cache[(entity_key, identifier)]
  1334         value = self.__min_max_value_cache[(entity_key, identifier)]
  1301       elif isinstance(value, list):
  1335       elif isinstance(value, list):
  1302         if sort_order == Query.DESCENDING:
  1336         if sort_order == Query.DESCENDING:
  1477 
  1511 
  1478   > it = Query('Person').Run()
  1512   > it = Query('Person').Run()
  1479   > for person in it:
  1513   > for person in it:
  1480   >   print 'Hi, %s!' % person['name']
  1514   >   print 'Hi, %s!' % person['name']
  1481   """
  1515   """
  1482   def __init__(self, cursor):
  1516   def __init__(self, cursor, keys_only=False):
  1483     self.__cursor = cursor
  1517     self.__cursor = cursor
  1484     self.__buffer = []
  1518     self.__buffer = []
  1485     self.__more_results = True
  1519     self.__more_results = True
       
  1520     self.__keys_only = keys_only
  1486 
  1521 
  1487   def _Next(self, count):
  1522   def _Next(self, count):
  1488     """Returns the next result(s) of the query.
  1523     """Returns the next result(s) of the query.
  1489 
  1524 
  1490     Not intended to be used by application developers. Use the python
  1525     Not intended to be used by application developers. Use the python
  1491     iterator protocol instead.
  1526     iterator protocol instead.
  1492 
  1527 
  1493     This method returns the next entities from the list of resulting
  1528     This method returns the next entities or keys from the list of matching
  1494     entities that matched the query. If the query specified a sort
  1529     results. If the query specified a sort order, results are returned in that
  1495     order, entities are returned in that order. Otherwise, the order
  1530     order. Otherwise, the order is undefined.
  1496     is undefined.
  1531 
  1497 
  1532     The argument specifies the number of results to return. If it's greater
  1498     The argument specifies the number of entities to return. If it's
  1533     than the number of remaining results, all of the remaining results are
  1499     greater than the number of remaining entities, all of the
  1534     returned. In that case, the length of the returned list will be smaller
  1500     remaining entities are returned. In that case, the length of the
  1535     than count.
  1501     returned list will be smaller than count.
  1536 
  1502 
  1537     There is an internal buffer for use with the next() method. If this buffer
  1503     There is an internal buffer for use with the next() method.  If
  1538     is not empty, up to 'count' values are removed from this buffer and
  1504     this buffer is not empty, up to 'count' values are removed from
  1539     returned. It's best not to mix _Next() and next().
  1505     this buffer and returned.  It's best not to mix _Next() and
  1540 
  1506     next().
  1541     The results are always returned as a list. If there are no results left,
  1507 
  1542     an empty list is returned.
  1508     The results are always returned as a list. If there are no results
       
  1509     left, an empty list is returned.
       
  1510 
  1543 
  1511     Args:
  1544     Args:
  1512       # the number of entities to return; must be >= 1
  1545       # the number of results to return; must be >= 1
  1513       count: int or long
  1546       count: int or long
  1514 
  1547 
  1515     Returns:
  1548     Returns:
  1516       # a list of entities
  1549       # a list of entities or keys
  1517       [Entity, ...]
  1550       [Entity or Key, ...]
  1518     """
  1551     """
  1519     if not isinstance(count, (int, long)) or count <= 0:
  1552     if not isinstance(count, (int, long)) or count <= 0:
  1520       raise datastore_errors.BadArgumentError(
  1553       raise datastore_errors.BadArgumentError(
  1521         'Argument to _Next must be an int greater than 0; received %s (a %s)' %
  1554         'Argument to _Next must be an int greater than 0; received %s (a %s)' %
  1522         (count, typename(count)))
  1555         (count, typename(count)))
  1537     except apiproxy_errors.ApplicationError, err:
  1570     except apiproxy_errors.ApplicationError, err:
  1538       raise _ToDatastoreError(err)
  1571       raise _ToDatastoreError(err)
  1539 
  1572 
  1540     self.__more_results = result.more_results()
  1573     self.__more_results = result.more_results()
  1541 
  1574 
  1542     ret = [Entity._FromPb(r) for r in result.result_list()]
  1575     if self.__keys_only:
  1543     return ret
  1576       return [Key._FromPb(e.key()) for e in result.result_list()]
       
  1577     else:
       
  1578       return [Entity._FromPb(e) for e in result.result_list()]
  1544 
  1579 
  1545   _BUFFER_SIZE = 20
  1580   _BUFFER_SIZE = 20
  1546 
  1581 
  1547   def next(self):
  1582   def next(self):
  1548     if not self.__buffer:
  1583     if not self.__buffer:
  1568     return pb
  1603     return pb
  1569 
  1604 
  1570   @staticmethod
  1605   @staticmethod
  1571   def _FromPb(pb):
  1606   def _FromPb(pb):
  1572     """Static factory method. Returns the Iterator representation of the given
  1607     """Static factory method. Returns the Iterator representation of the given
  1573     protocol buffer (datastore_pb.Cursor). Not intended to be used by
  1608     protocol buffer (datastore_pb.QueryResult). Not intended to be used by
  1574     application developers. Enforced by not hiding the datastore_pb classes.
  1609     application developers. Enforced by hiding the datastore_pb classes.
  1575 
  1610 
  1576     Args:
  1611     Args:
  1577       # a protocol buffer Cursor
  1612       pb: datastore_pb.QueryResult
  1578       pb: datastore_pb.Cursor
       
  1579 
  1613 
  1580     Returns:
  1614     Returns:
  1581       # the Iterator representation of the argument
       
  1582       Iterator
  1615       Iterator
  1583     """
  1616     """
  1584     return Iterator(pb.cursor())
  1617     return Iterator(pb.cursor().cursor(), keys_only=pb.keys_only())
  1585 
  1618 
  1586 
  1619 
  1587 class _Transaction(object):
  1620 class _Transaction(object):
  1588   """Encapsulates a transaction currently in progress.
  1621   """Encapsulates a transaction currently in progress.
  1589 
  1622 
  1918     raise datastore_errors.BadKeyError('Key %r is not complete.' % key)
  1951     raise datastore_errors.BadKeyError('Key %r is not complete.' % key)
  1919 
  1952 
  1920   return key
  1953   return key
  1921 
  1954 
  1922 
  1955 
       
  1956 def _GetPropertyValue(entity, property):
       
  1957   """Returns an entity's value for a given property name.
       
  1958 
       
  1959   Handles special properties like __key__ as well as normal properties.
       
  1960 
       
  1961   Args:
       
  1962     entity: datastore.Entity
       
  1963     property: str; the property name
       
  1964 
       
  1965   Returns:
       
  1966     property value. For __key__, a datastore_types.Key.
       
  1967 
       
  1968   Raises:
       
  1969     KeyError, if the entity does not have the given property.
       
  1970   """
       
  1971   if property in datastore_types._SPECIAL_PROPERTIES:
       
  1972     assert property == datastore_types._KEY_SPECIAL_PROPERTY
       
  1973     return entity.key()
       
  1974   else:
       
  1975     return entity[property]
       
  1976 
       
  1977 
  1923 def _AddOrAppend(dictionary, key, value):
  1978 def _AddOrAppend(dictionary, key, value):
  1924   """Adds the value to the existing values in the dictionary, if any.
  1979   """Adds the value to the existing values in the dictionary, if any.
  1925 
  1980 
  1926   If dictionary[key] doesn't exist, sets dictionary[key] to value.
  1981   If dictionary[key] doesn't exist, sets dictionary[key] to value.
  1927 
  1982