diff -r 27971a13089f -r 2e0b0af889be thirdparty/google_appengine/google/appengine/datastore/datastore_index.py --- 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: