47 |
47 |
48 |
48 |
49 |
49 |
50 |
50 |
51 |
51 |
|
52 from google.appengine.api import datastore_types |
52 from google.appengine.api import validation |
53 from google.appengine.api import validation |
53 from google.appengine.api import yaml_errors |
54 from google.appengine.api import yaml_errors |
54 from google.appengine.api import yaml_object |
55 from google.appengine.api import yaml_object |
55 from google.appengine.datastore import datastore_pb |
56 from google.appengine.datastore import datastore_pb |
56 |
57 |
247 |
248 |
248 Args: |
249 Args: |
249 query: A datastore_pb.Query instance. |
250 query: A datastore_pb.Query instance. |
250 |
251 |
251 Returns: |
252 Returns: |
252 None if no composite index is needed for this query. Otherwise, |
253 A tuple of the form (required, kind, ancestor, (prop1, prop2, ...), neq): |
253 a tuple of the form (kind, ancestor, (prop1, prop2, ...), neq) where: |
254 required: boolean, whether the index is required |
254 kind: the kind or None; |
255 kind: the kind or None; |
255 ancestor: True if this is an ancestor query; |
256 ancestor: True if this is an ancestor query; |
256 prop1, prop2, ...: tuples of the form (name, direction) where: |
257 prop1, prop2, ...: tuples of the form (name, direction) where: |
257 name: a property name; |
258 name: a property name; |
258 direction: datastore_pb.Query_Order.ASCENDING or ...DESCENDING; |
259 direction: datastore_pb.Query_Order.ASCENDING or ...DESCENDING; |
259 neq: the number of prop tuples corresponding to equality filters. |
260 neq: the number of prop tuples corresponding to equality filters. |
260 """ |
261 """ |
|
262 required = True |
|
263 |
261 kind = query.kind() |
264 kind = query.kind() |
262 ancestor = query.has_ancestor() |
265 ancestor = query.has_ancestor() |
263 filters = query.filter_list() |
266 filters = query.filter_list() |
264 orders = query.order_list() |
267 orders = query.order_list() |
265 |
268 |
267 assert filter.op() != datastore_pb.Query_Filter.IN, 'Filter.op()==IN' |
270 assert filter.op() != datastore_pb.Query_Filter.IN, 'Filter.op()==IN' |
268 nprops = len(filter.property_list()) |
271 nprops = len(filter.property_list()) |
269 assert nprops == 1, 'Filter has %s properties, expected 1' % nprops |
272 assert nprops == 1, 'Filter has %s properties, expected 1' % nprops |
270 |
273 |
271 if ancestor and not kind and not filters and not orders: |
274 if ancestor and not kind and not filters and not orders: |
272 return None |
275 required = False |
273 |
276 |
274 eq_filters = [f for f in filters if f.op() in EQUALITY_OPERATORS] |
277 eq_filters = [f for f in filters if f.op() in EQUALITY_OPERATORS] |
275 ineq_filters = [f for f in filters if f.op() in INEQUALITY_OPERATORS] |
278 ineq_filters = [f for f in filters if f.op() in INEQUALITY_OPERATORS] |
276 exists_filters = [f for f in filters if f.op() in EXISTS_OPERATORS] |
279 exists_filters = [f for f in filters if f.op() in EXISTS_OPERATORS] |
277 assert (len(eq_filters) + len(ineq_filters) + |
280 assert (len(eq_filters) + len(ineq_filters) + |
278 len(exists_filters)) == len(filters), 'Not all filters used' |
281 len(exists_filters)) == len(filters), 'Not all filters used' |
279 |
282 |
280 if (kind and eq_filters and not ineq_filters and not exists_filters and |
283 if (kind and eq_filters and not ineq_filters and not exists_filters and |
281 not orders): |
284 not orders): |
282 return None |
285 names = set(f.property(0).name() for f in eq_filters) |
|
286 if not names.intersection(datastore_types._SPECIAL_PROPERTIES): |
|
287 required = False |
283 |
288 |
284 ineq_property = None |
289 ineq_property = None |
285 if ineq_filters: |
290 if ineq_filters: |
286 ineq_property = ineq_filters[0].property(0).name() |
291 ineq_property = ineq_filters[0].property(0).name() |
287 for filter in ineq_filters: |
292 for filter in ineq_filters: |
323 else: |
328 else: |
324 props.append((prop_name, ASCENDING)) |
329 props.append((prop_name, ASCENDING)) |
325 |
330 |
326 if (kind and not ancestor and |
331 if (kind and not ancestor and |
327 (not props or (len(props) == 1 and props[0][1] == ASCENDING))): |
332 (not props or (len(props) == 1 and props[0][1] == ASCENDING))): |
328 return None |
333 required = False |
329 |
334 |
330 unique_names = set(name for name, dir in props) |
335 unique_names = set(name for name, dir in props) |
331 if len(props) > 1 and len(unique_names) == 1: |
336 if len(props) > 1 and len(unique_names) == 1: |
332 return None |
337 required = False |
333 |
338 |
334 return (kind, ancestor, tuple(props), len(eq_filters)) |
339 return (required, kind, ancestor, tuple(props), len(eq_filters)) |
335 |
340 |
336 |
341 |
337 def IndexYamlForQuery(kind, ancestor, props): |
342 def IndexYamlForQuery(kind, ancestor, props): |
338 """Return the composite index definition YAML needed for a query. |
343 """Return the composite index definition YAML needed for a query. |
339 |
344 |