def CheckQuery()

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')