--- a/thirdparty/google_appengine/google/appengine/api/datastore_file_stub.py Fri Oct 10 06:56:56 2008 +0000
+++ b/thirdparty/google_appengine/google/appengine/api/datastore_file_stub.py Fri Oct 10 13:14:24 2008 +0000
@@ -64,6 +64,25 @@
datastore_pb.Query.__hash__ = lambda self: hash(self.Encode())
+class _StoredEntity(object):
+ """Simple wrapper around an entity stored by the stub.
+
+ Public properties:
+ native: Native protobuf Python object, entity_pb.EntityProto.
+ encoded: Encoded binary representation of above protobuf.
+ """
+
+ def __init__(self, entity):
+ """Create a _StoredEntity object and store an entity.
+
+ Args:
+ entity: entity_pb.EntityProto to store.
+ """
+ self.native = entity
+
+ self.encoded = entity.Encode()
+
+
class DatastoreFileStub(object):
""" Persistent stub for the Python datastore API.
@@ -72,6 +91,29 @@
and is backed by files on disk.
"""
+ _PROPERTY_TYPE_TAGS = {
+ datastore_types.Blob: entity_pb.PropertyValue.kstringValue,
+ bool: entity_pb.PropertyValue.kbooleanValue,
+ datastore_types.Category: entity_pb.PropertyValue.kstringValue,
+ datetime.datetime: entity_pb.PropertyValue.kint64Value,
+ datastore_types.Email: entity_pb.PropertyValue.kstringValue,
+ float: entity_pb.PropertyValue.kdoubleValue,
+ datastore_types.GeoPt: entity_pb.PropertyValue.kPointValueGroup,
+ datastore_types.IM: entity_pb.PropertyValue.kstringValue,
+ int: entity_pb.PropertyValue.kint64Value,
+ datastore_types.Key: entity_pb.PropertyValue.kReferenceValueGroup,
+ datastore_types.Link: entity_pb.PropertyValue.kstringValue,
+ long: entity_pb.PropertyValue.kint64Value,
+ datastore_types.PhoneNumber: entity_pb.PropertyValue.kstringValue,
+ datastore_types.PostalAddress: entity_pb.PropertyValue.kstringValue,
+ datastore_types.Rating: entity_pb.PropertyValue.kint64Value,
+ str: entity_pb.PropertyValue.kstringValue,
+ datastore_types.Text: entity_pb.PropertyValue.kstringValue,
+ type(None): 0,
+ unicode: entity_pb.PropertyValue.kstringValue,
+ users.User: entity_pb.PropertyValue.kUserValueGroup,
+ }
+
def __init__(self, app_id, datastore_file, history_file,
require_indexes=False):
"""Constructor.
@@ -159,7 +201,7 @@
last_path = entity.key().path().element_list()[-1]
app_kind = (entity.key().app(), last_path.type())
kind_dict = self.__entities.setdefault(app_kind, {})
- kind_dict[entity.key()] = entity
+ kind_dict[entity.key()] = _StoredEntity(entity)
if last_path.has_id() and last_path.id() >= self.__next_id:
self.__next_id = last_path.id() + 1
@@ -192,7 +234,7 @@
encoded = []
for kind_dict in self.__entities.values():
for entity in kind_dict.values():
- encoded.append(entity.Encode())
+ encoded.append(entity.encoded)
self.__WritePickled(encoded, self.__datastore_file)
@@ -303,7 +345,7 @@
for clone in clones:
last_path = clone.key().path().element_list()[-1]
kind_dict = self.__entities.setdefault((app, last_path.type()), {})
- kind_dict[clone.key()] = clone
+ kind_dict[clone.key()] = _StoredEntity(clone)
finally:
self.__entities_lock.release()
@@ -320,7 +362,7 @@
group = get_response.add_entity()
try:
- entity = self.__entities[app, last_path.type()][key]
+ entity = self.__entities[app, last_path.type()][key].native
except KeyError:
entity = None
@@ -390,7 +432,7 @@
try:
query.set_app(app)
results = self.__entities[app, query.kind()].values()
- results = [datastore.Entity._FromPb(pb) for pb in results]
+ results = [datastore.Entity._FromPb(entity.native) for entity in results]
except KeyError:
results = []
@@ -432,7 +474,15 @@
for filter_prop in filt.property_list():
filter_val = datastore_types.FromPropertyPb(filter_prop)
- comp = u'%r %s %r' % (fixed_entity_val, op, filter_val)
+ fixed_entity_type = self._PROPERTY_TYPE_TAGS.get(
+ fixed_entity_val.__class__)
+ filter_type = self._PROPERTY_TYPE_TAGS.get(filter_val.__class__)
+ if fixed_entity_type == filter_type:
+ comp = u'%r %s %r' % (fixed_entity_val, op, filter_val)
+ elif op != '==':
+ comp = '%r %s %r' % (fixed_entity_type, op, filter_type)
+ else:
+ continue
logging.log(logging.DEBUG - 1,
'Evaling filter expression "%s"', comp)
@@ -463,7 +513,7 @@
prop = order.property().decode('utf-8')
results = [entity for entity in results if has_prop_indexed(entity, prop)]
- def order_compare(a, b):
+ def order_compare_entities(a, b):
""" Return a negative, zero or positive number depending on whether
entity a is considered smaller than, equal to, or larger than b,
according to the query's orderings. """
@@ -471,36 +521,51 @@
for o in query.order_list():
prop = o.property().decode('utf-8')
- if o.direction() is datastore_pb.Query_Order.ASCENDING:
- selector = min
- else:
- selector = max
+ reverse = (o.direction() is datastore_pb.Query_Order.DESCENDING)
a_val = a[prop]
if isinstance(a_val, list):
- a_val = selector(a_val)
+ a_val = sorted(a_val, order_compare_properties, reverse=reverse)[0]
b_val = b[prop]
if isinstance(b_val, list):
- b_val = selector(b_val)
+ b_val = sorted(b_val, order_compare_properties, reverse=reverse)[0]
- try:
- cmped = cmp(a_val, b_val)
- except TypeError:
- cmped = NotImplementedError
-
- if cmped == NotImplementedError:
- cmped = cmp(type(a_val), type(b_val))
+ cmped = order_compare_properties(a_val, b_val)
if o.direction() is datastore_pb.Query_Order.DESCENDING:
cmped = -cmped
if cmped != 0:
return cmped
+
if cmped == 0:
return cmp(a.key(), b.key())
- results.sort(order_compare)
+ def order_compare_properties(x, y):
+ """Return a negative, zero or positive number depending on whether
+ property value x is considered smaller than, equal to, or larger than
+ property value y. If x and y are different types, they're compared based
+ on the type ordering used in the real datastore, which is based on the
+ tag numbers in the PropertyValue PB.
+ """
+ if isinstance(x, datetime.datetime):
+ x = datastore_types.DatetimeToTimestamp(x)
+ if isinstance(y, datetime.datetime):
+ y = datastore_types.DatetimeToTimestamp(y)
+
+ x_type = self._PROPERTY_TYPE_TAGS.get(x.__class__)
+ y_type = self._PROPERTY_TYPE_TAGS.get(y.__class__)
+
+ if x_type == y_type:
+ try:
+ return cmp(x, y)
+ except TypeError:
+ return 0
+ else:
+ return cmp(x_type, y_type)
+
+ results.sort(order_compare_entities)
offset = 0
limit = len(results)
@@ -614,7 +679,7 @@
props = {}
for entity in self.__entities[(app, kind)].values():
- for prop in entity.property_list():
+ for prop in entity.native.property_list():
if prop.name() not in props:
props[prop.name()] = entity_pb.PropertyValue()
props[prop.name()].MergeFrom(prop.value())