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 |
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 |
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 |
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))) |
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 |