def __init__(self, op, value):
    """Constructor.

    Args:
      op: A string representing the operator to use.
      value: A entity_pb.Property, the property and value to compare against.

    Raises:
      BadArgumentError if op has an unsupported value or value is not an
      entity_pb.Property.
    """
    if not op in self._OPERATORS:
      raise datastore_errors.BadArgumentError('unknown operator: %r' % (op,))
    if not isinstance(value, entity_pb.Property):
      raise datastore_errors.BadArgumentError(
          'value argument should be entity_pb.Property (%r)' % (value,))

    super(PropertyFilter, self).__init__()
    self.__filter = datastore_pb.Query_Filter()
    self.__filter.set_op(self._OPERATORS[op])
    self.__filter.add_property().CopyFrom(value)
def Normalize(filters, orders, exists):
    """ Normalizes filter and order query components.

  The resulting components have the same effect as the given components if used
  in a query.

  Args:
    filters: the filters set on the query
    orders: the orders set on the query
    exists: the names of properties that require an exists filter if
      not already specified

  Returns:
    (filter, orders) the reduced set of filters and orders
  """

    eq_properties = set()
    inequality_properties = set()

    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)
        if f.op() in EQUALITY_OPERATORS:
            eq_properties.add(f.property(0).name())
        elif f.op() in INEQUALITY_OPERATORS:
            inequality_properties.add(f.property(0).name())

    eq_properties -= inequality_properties

    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

    remove_set.update(inequality_properties)

    new_filters = []
    for f in filters:
        if f.op() not in EXISTS_OPERATORS:
            new_filters.append(f)
            continue
        name = f.property(0).name()
        if name not in remove_set:
            remove_set.add(name)
            new_filters.append(f)

    for prop in exists:
        if prop not in remove_set:
            remove_set.add(prop)
            new_filter = datastore_pb.Query_Filter()
            new_filter.set_op(datastore_pb.Query_Filter.EXISTS)
            new_prop = new_filter.add_property()
            new_prop.set_name(prop)
            new_prop.set_multiple(False)
            new_prop.mutable_value()
            new_filters.append(new_filter)

    filters = new_filters

    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)