thirdparty/google_appengine/google/appengine/datastore/datastore_index.py
changeset 2864 2e0b0af889be
parent 1278 a7766286a7be
--- a/thirdparty/google_appengine/google/appengine/datastore/datastore_index.py	Sat Sep 05 14:04:24 2009 +0200
+++ b/thirdparty/google_appengine/google/appengine/datastore/datastore_index.py	Sun Sep 06 23:31:53 2009 +0200
@@ -192,6 +192,74 @@
                         ))
 
 
+def Normalize(filters, orders):
+  """ Normalizes filter and order query components.
+
+  The resulting components have the same effect as the given components if used
+  in a query.
+
+  Returns:
+    (filter, orders) the reduced set of filters and orders
+  """
+
+  for f in filters:
+    if f.op() == datastore_pb.Query_Filter.IN and f.property_size() == 1:
+      f.set_op(datastore_pb.Query_Filter.EQUAL);
+
+  eq_properties = set([f.property(0).name() for f in filters if f.op() == datastore_pb.Query_Filter.EQUAL]);
+
+  remove_set = eq_properties.copy()
+  new_orders = []
+  for o in orders:
+    if o.property() not in remove_set:
+      remove_set.add(o.property())
+      new_orders.append(o)
+  orders = new_orders
+
+
+  if datastore_types._KEY_SPECIAL_PROPERTY in eq_properties:
+    orders = []
+
+  new_orders = []
+  for o in orders:
+    if o.property() == datastore_types._KEY_SPECIAL_PROPERTY:
+      new_orders.append(o)
+      break
+    new_orders.append(o)
+  orders = new_orders
+
+  return (filters, orders)
+
+
+def RemoveNativelySupportedComponents(filters, orders):
+  """ Removes query components that are natively supported by the datastore.
+
+  The resulting filters and orders should not be used in an actual query.
+
+  Returns
+    (filters, orders) the reduced set of filters and orders
+  """
+  (filters, orders) = Normalize(filters, orders)
+
+  has_key_desc_order = False
+  if orders and orders[-1].property() == datastore_types._KEY_SPECIAL_PROPERTY:
+    if orders[-1].direction() == ASCENDING:
+      orders = orders[:-1]
+    else:
+      has_key_desc_order = True
+
+  if not has_key_desc_order:
+    for f in filters:
+      if (f.op() in INEQUALITY_OPERATORS and
+          f.property(0).name() != datastore_types._KEY_SPECIAL_PROPERTY):
+        break
+    else:
+      filters = [f for f in filters
+          if f.property(0).name() != datastore_types._KEY_SPECIAL_PROPERTY]
+
+  return (filters, orders)
+
+
 def CompositeIndexForQuery(query):
   """Return the composite index needed for a query.
 
@@ -213,12 +281,18 @@
     can be at most one of these.
 
   - After that come all the (property, direction) pairs for the Order
-    entries, in the order given in the query.  Exceptions: (a) if
-    there is a Filter entry with an inequality operator that matches
-    the first Order entry, the first order pair is omitted (or,
-    equivalently, in this case the inequality pair is omitted); (b) if
-    an Order entry corresponds to an equality filter, it is ignored
-    (since there will only ever be one value returned).
+    entries, in the order given in the query.  Exceptions:
+      (a) if there is a Filter entry with an inequality operator that matches
+          the first Order entry, the first order pair is omitted (or,
+          equivalently, in this case the inequality pair is omitted).
+      (b) if an Order entry corresponds to an equality filter, it is ignored
+          (since there will only ever be one value returned).
+      (c) if there is an equality filter on __key__ all orders are dropped
+          (since there will be at most one result returned).
+      (d) if there is an order on __key__ all further orders are dropped (since
+          keys are unique).
+      (e) orders on __key__ ASCENDING are dropped (since this is supported
+          natively by the datastore).
 
   - Finally, if there are Filter entries whose operator is EXISTS, and
     whose property names are not already listed, they are added, with
@@ -271,16 +345,18 @@
     nprops = len(filter.property_list())
     assert nprops == 1, 'Filter has %s properties, expected 1' % nprops
 
-  if ancestor and not kind and not filters and not orders:
+  if not kind:
     required = False
 
+  (filters, orders) = RemoveNativelySupportedComponents(filters, orders)
+
   eq_filters = [f for f in filters if f.op() in EQUALITY_OPERATORS]
   ineq_filters = [f for f in filters if f.op() in INEQUALITY_OPERATORS]
   exists_filters = [f for f in filters if f.op() in EXISTS_OPERATORS]
   assert (len(eq_filters) + len(ineq_filters) +
           len(exists_filters)) == len(filters), 'Not all filters used'
 
-  if (kind and eq_filters and not ineq_filters and not exists_filters and
+  if (kind and not ineq_filters and not exists_filters and
       not orders):
     names = set(f.property(0).name() for f in eq_filters)
     if not names.intersection(datastore_types._SPECIAL_PROPERTIES):
@@ -292,16 +368,6 @@
     for filter in ineq_filters:
       assert filter.property(0).name() == ineq_property
 
-  new_orders = []
-  for order in orders:
-    name = order.property()
-    for filter in eq_filters:
-      if filter.property(0).name() == name:
-        break
-    else:
-      new_orders.append(order)
-  orders = new_orders
-
   props = []
 
   for f in eq_filters: