@Override
 public Query apply(Function input, Context context) {
   assert input != null;
   BooleanQuery query = new BooleanQuery();
   for (Symbol symbol : input.arguments()) {
     query.add(process(symbol, context), BooleanClause.Occur.MUST);
   }
   return query;
 }
 @Override
 public Query apply(Function input, Context context) {
   assert input != null;
   BooleanQuery query = new BooleanQuery();
   query.setMinimumNumberShouldMatch(1);
   for (Symbol symbol : input.arguments()) {
     query.add(process(symbol, context), BooleanClause.Occur.SHOULD);
   }
   return query;
 }
      @Override
      public Query apply(Function input, Context context) {
        assert input != null;
        assert input.arguments().size() == 1;
        BooleanQuery query = new BooleanQuery();

        query.add(process(input.arguments().get(0), context), BooleanClause.Occur.MUST_NOT);
        query.add(Queries.newMatchAllQuery(), BooleanClause.Occur.MUST);

        return query;
      }
 @Override
 protected Query applyArrayLiteral(Reference reference, Literal arrayLiteral, Context context)
     throws IOException {
   // col like ANY (['a', 'b']) --> or(like(col, 'a'), like(col, 'b'))
   BooleanQuery booleanQuery = new BooleanQuery();
   booleanQuery.setMinimumNumberShouldMatch(1);
   for (Object value : toIterable(arrayLiteral.value())) {
     booleanQuery.add(
         likeQuery.toQuery(reference, value, context), BooleanClause.Occur.SHOULD);
   }
   return booleanQuery;
 }
 @Override
 protected Query applyArrayLiteral(Reference reference, Literal arrayLiteral, Context context)
     throws IOException {
   // col < ANY ([1,2,3]) --> or(col<1, col<2, col<3)
   BooleanQuery booleanQuery = new BooleanQuery();
   booleanQuery.setMinimumNumberShouldMatch(1);
   for (Object value : toIterable(arrayLiteral.value())) {
     booleanQuery.add(
         inverseRangeQuery.toQuery(reference, reference.valueType(), value),
         BooleanClause.Occur.SHOULD);
   }
   return booleanQuery;
 }
      @Override
      protected Query applyArrayReference(
          Reference arrayReference, Literal literal, Context context) throws IOException {
        // 1 != any ( col ) -->  gt 1 or lt 1
        String columnName = arrayReference.info().ident().columnIdent().fqn();
        Object value = literal.value();

        QueryBuilderHelper builder = QueryBuilderHelper.forType(arrayReference.valueType());
        BooleanQuery query = new BooleanQuery();
        query.setMinimumNumberShouldMatch(1);
        query.add(
            builder.rangeQuery(columnName, value, null, false, false), BooleanClause.Occur.SHOULD);
        query.add(
            builder.rangeQuery(columnName, null, value, false, false), BooleanClause.Occur.SHOULD);
        return query;
      }
 @Override
 public Query apply(Function parent, Function inner, Context context) throws IOException {
   FunctionLiteralPair outerPair = new FunctionLiteralPair(parent);
   if (!outerPair.isValid()) {
     return null;
   }
   Query query = getQuery(inner, context);
   if (query == null) return null;
   Boolean negate = !(Boolean) outerPair.input().value();
   if (negate) {
     BooleanQuery booleanQuery = new BooleanQuery();
     booleanQuery.add(query, BooleanClause.Occur.MUST_NOT);
     return booleanQuery;
   } else {
     return query;
   }
 }
      @Override
      protected Query applyArrayLiteral(Reference reference, Literal arrayLiteral, Context context)
          throws IOException {
        // col not like ANY (['a', 'b']) --> not(and(like(col, 'a'), like(col, 'b')))
        BooleanQuery query = new BooleanQuery();
        BooleanQuery notQuery = new BooleanQuery();

        String columnName = reference.ident().columnIdent().fqn();
        QueryBuilderHelper builder = QueryBuilderHelper.forType(reference.valueType());
        for (Object value : toIterable(arrayLiteral.value())) {
          notQuery.add(
              builder.like(columnName, value, context.indexCache.filter()),
              BooleanClause.Occur.MUST);
        }
        query.add(notQuery, BooleanClause.Occur.MUST_NOT);
        return query;
      }
  @Test
  public void testAnyOnArrayLiteral() throws Exception {
    Reference ref = createReference("d", DataTypes.STRING);
    Literal stringArrayLiteral =
        Literal.newLiteral(
            new Object[] {new BytesRef("a"), new BytesRef("b"), new BytesRef("c")},
            new ArrayType(DataTypes.STRING));

    // col != ANY (1,2,3)
    Query neqQuery = convert(whereClause(AnyNeqOperator.NAME, ref, stringArrayLiteral));
    assertThat(neqQuery, instanceOf(FilteredQuery.class));
    assertThat(((FilteredQuery) neqQuery).getFilter(), instanceOf(BooleanFilter.class));
    BooleanFilter filter = (BooleanFilter) ((FilteredQuery) neqQuery).getFilter();
    assertThat(filter.toString(), is("BooleanFilter(-BooleanFilter(+d:a +d:b +d:c))"));

    // col like any (1,2,3)
    Query likeQuery = convert(whereClause(AnyLikeOperator.NAME, ref, stringArrayLiteral));
    assertThat(likeQuery, instanceOf(BooleanQuery.class));
    BooleanQuery likeBQuery = (BooleanQuery) likeQuery;
    assertThat(likeBQuery.clauses().size(), is(3));
    for (int i = 0; i < 2; i++) {
      // like --> XConstantScoreQuery with regexp-filter
      Query filteredQuery = likeBQuery.clauses().get(i).getQuery();
      assertThat(filteredQuery, instanceOf(XConstantScoreQuery.class));
      assertThat(((XConstantScoreQuery) filteredQuery).getFilter(), instanceOf(RegexpFilter.class));
    }

    // col not like any (1,2,3)
    Query notLikeQuery = convert(whereClause(AnyNotLikeOperator.NAME, ref, stringArrayLiteral));
    assertThat(notLikeQuery, instanceOf(BooleanQuery.class));
    BooleanQuery notLikeBQuery = (BooleanQuery) notLikeQuery;
    assertThat(notLikeBQuery.clauses(), hasSize(1));
    BooleanClause clause = notLikeBQuery.clauses().get(0);
    assertThat(clause.getOccur(), is(BooleanClause.Occur.MUST_NOT));
    assertThat(((BooleanQuery) clause.getQuery()).clauses(), hasSize(3));
    for (BooleanClause innerClause : ((BooleanQuery) clause.getQuery()).clauses()) {
      assertThat(innerClause.getOccur(), is(BooleanClause.Occur.MUST));
      assertThat(innerClause.getQuery(), instanceOf(XConstantScoreQuery.class));
      assertThat(
          ((XConstantScoreQuery) innerClause.getQuery()).getFilter(),
          instanceOf(RegexpFilter.class));
    }

    // col < any (1,2,3)
    Query ltQuery2 = convert(whereClause(AnyLtOperator.NAME, ref, stringArrayLiteral));
    assertThat(ltQuery2, instanceOf(BooleanQuery.class));
    BooleanQuery ltBQuery = (BooleanQuery) ltQuery2;
    assertThat(ltBQuery.toString(), is("(d:{* TO a} d:{* TO b} d:{* TO c})~1"));
  }