in src/google/appengine/datastore/datastore_stub_util.py [0:0]
def CheckQuery(query, filters, orders, max_query_components):
"""Check a datastore query with normalized filters, orders.
Raises an ApplicationError when any of the following conditions are violated:
- transactional queries have an ancestor
- queries that are not too large
(sum of filters, orders, ancestor <= max_query_components)
- ancestor (if any) app and namespace match query app and namespace
- kindless queries only filter on __key__ and only sort on __key__ ascending
- multiple inequality (<, <=, >, >=) filters all applied to the same property
- filters on __key__ compare to a reference in the same app and namespace as
the query
- if an inequality filter on prop X is used, the first order (if any) must
be on X
Args:
query: query to validate
filters: normalized (by datastore_index.Normalize) filters from query
orders: normalized (by datastore_index.Normalize) orders from query
max_query_components: limit on query complexity
"""
Check(not query.property_name or not query.keys_only,
'projection and keys_only cannot both be set')
projected_properties = set(query.property_name)
for prop_name in query.property_name:
Check(not datastore_types.RESERVED_PROPERTY_NAME.match(prop_name),
'projections are not supported for the property: ' + prop_name)
Check(
len(projected_properties) == len(query.property_name),
'cannot project a property multiple times')
key_prop_name = datastore_types.KEY_SPECIAL_PROPERTY
unapplied_log_timestamp_us_name = (
datastore_types._UNAPPLIED_LOG_TIMESTAMP_SPECIAL_PROPERTY)
if query.HasField('transaction'):
Check(
query.HasField('ancestor'),
'Only ancestor queries are allowed inside transactions.')
num_components = len(filters) + len(orders)
if query.HasField('ancestor'):
num_components += 1
Check(num_components <= max_query_components,
'query is too large. may not have more than %s filters'
' + sort orders ancestor total' % max_query_components)
if query.HasField('ancestor'):
ancestor = query.ancestor
Check(query.app == ancestor.app,
'query app is %s but ancestor app is %s' % (query.app, ancestor.app))
Check(
query.name_space == ancestor.name_space,
'query namespace is %s but ancestor namespace is %s' %
(query.name_space, ancestor.name_space))
if query.group_by_property_name:
group_by_set = set(query.group_by_property_name)
for order in orders:
if not group_by_set:
break
Check(
order.property in group_by_set,
'items in the group by clause must be specified first '
'in the ordering')
group_by_set.remove(order.property)
ineq_prop_name = None
for filter in filters:
Check(
len(filter.property) == 1,
'Filter has %d properties, expected 1' % len(filter.property))
prop = filter.property[0]
prop_name = prop.name
if prop_name == key_prop_name:
Check(
prop.value.HasField('referencevalue'),
'%s filter value must be a Key' % key_prop_name)
ref_val = prop.value.referencevalue
Check(
ref_val.app == query.app, '%s filter app is %s but query app is %s' %
(key_prop_name, ref_val.app, query.app))
Check(
ref_val.name_space == query.name_space,
'%s filter namespace is %s but query namespace is %s' %
(key_prop_name, ref_val.name_space, query.name_space))
if filter.op in datastore_index.EQUALITY_OPERATORS:
Check(prop_name not in projected_properties,
'cannot use projection on a property with an equality filter')
if (filter.op in datastore_index.INEQUALITY_OPERATORS and
prop_name != unapplied_log_timestamp_us_name):
if ineq_prop_name is None:
ineq_prop_name = prop_name
else:
Check(ineq_prop_name == prop_name,
'Only one inequality filter per query is supported. '
'Encountered both %s and %s' % (ineq_prop_name, prop_name))
if ineq_prop_name is not None and query.group_by_property_name and not orders:
Check(ineq_prop_name in group_by_set,
'Inequality filter on %s must also be a group by '
'property when group by properties are set.'
% (ineq_prop_name))
if ineq_prop_name is not None and orders:
first_order_prop = _Decode(orders[0].property)
Check(first_order_prop == ineq_prop_name,
'The first sort property must be the same as the property '
'to which the inequality filter is applied. In your query '
'the first sort property is %s but the inequality filter '
'is on %s' % (first_order_prop, ineq_prop_name))
if not query.HasField('kind'):
for filter in filters:
prop_name = _Decode(filter.property[0].name)
Check(prop_name == key_prop_name or
prop_name == unapplied_log_timestamp_us_name,
'kind is required for non-__key__ filters')
for order in orders:
prop_name = _Decode(order.property)
Check(
prop_name == key_prop_name and
order.direction is datastore_pb.Query.Order.ASCENDING,
'kind is required for all orders except __key__ ascending')