docs: def remove_index(self, index):
          """
          This one takes some explanation. When we do a query with a WHERE
          statement, it may end up being a scan and it may end up being a query.
          If it is a query, we need to remove the hash and range key constraints
          from the expression and return that as the query_constraints. The
          remaining constraints, if any, are returned as the filter_constraints.
  
          """
          # We can only be doing this if all of the joining ops are AND (no OR),
          # so we don't even need to worry about OR's
          query = []
          remainder = []
          for i in range(0, len(self.pieces), 2):
              const = self.pieces[i]
              if const.hash_field == index.hash_key:
                  query.append(const)
              elif index.range_key is not None and const.range_field == index.range_key:
                  query.append(const)
              else:
                  remainder.append(const)
          if len(query) == 1:
              query_constraints = query[0]
          else:
              query_constraints = Conjunction.and_(query)
          if not remainder:
              filter_constraints = None
          elif len(remainder) == 1:
              filter_constraints = remainder[0]
          else:
              filter_constraints = Conjunction.and_(remainder)
          return (query_constraints, filter_constraints)