@Override
  public QueryBuilders.QueryBuilder visit(Call call) {
    final Operator op = call.operator();
    final List<Expression> args = call.arguments();

    if (op == OptionalOperators.IS_PRESENT || op == OptionalOperators.IS_ABSENT) {
      final String field = pathNaming.name(Visitors.toPath(args.get(0)));

      QueryBuilders.QueryBuilder builder = QueryBuilders.existsQuery(field);

      if (op == OptionalOperators.IS_ABSENT) {
        builder = QueryBuilders.boolQuery().mustNot(builder);
      }

      return builder;
    }

    if (op == Operators.AND || op == Operators.OR) {
      Preconditions.checkArgument(!args.isEmpty(), "Size should be >=1 for %s but was %s", op, args.size());

      final QueryBuilders.BoolQueryBuilder builder = args.stream()
              .map(a -> a.accept(this))
              .reduce(QueryBuilders.boolQuery(), (a, b) -> op == Operators.AND ? a.must(b) : a.should(b), (a, b) -> b);

      return builder;
    }

    if (op == Operators.NOT) {
      Preconditions.checkArgument(args.size() == 1, "Size should be 1 for %s but was %s", op, args.size());
      final QueryBuilders.QueryBuilder builder = args.get(0).accept(this);
      return QueryBuilders.boolQuery().mustNot(builder);
    }

    if (op.arity() == Operator.Arity.BINARY) {
      return binaryCall(call);
    }

    throw new UnsupportedOperationException("Don't know how to handle " + call);
  }
Evaluating expression into <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html">Elastic Query DSL</a>
criteria/elasticsearch/src/org/immutables/criteria/elasticsearch/ElasticsearchQueryVisitor.java