protected Query between(Operation<?> operation, QueryMetadata metadata) {
   verifyArguments(operation);
   Path<?> path = getPath(operation.getArg(0));
   // TODO Phrase not properly supported
   return range(
       path, toField(path), operation.getArg(1), operation.getArg(2), true, true, metadata);
 }
 private Query toQuery(Operation<?> operation, QueryMetadata metadata) {
   Operator op = operation.getOperator();
   if (op == Ops.OR) {
     return toTwoHandSidedQuery(operation, Occur.SHOULD, metadata);
   } else if (op == Ops.AND) {
     return toTwoHandSidedQuery(operation, Occur.MUST, metadata);
   } else if (op == Ops.NOT) {
     BooleanQuery bq = new BooleanQuery();
     bq.add(new BooleanClause(toQuery(operation.getArg(0), metadata), Occur.MUST_NOT));
     bq.add(new BooleanClause(new MatchAllDocsQuery(), Occur.MUST));
     return bq;
   } else if (op == Ops.LIKE) {
     return like(operation, metadata);
   } else if (op == Ops.LIKE_IC) {
     throw new IgnoreCaseUnsupportedException();
   } else if (op == Ops.EQ) {
     return eq(operation, metadata, false);
   } else if (op == Ops.EQ_IGNORE_CASE) {
     throw new IgnoreCaseUnsupportedException();
   } else if (op == Ops.NE) {
     return ne(operation, metadata, false);
   } else if (op == Ops.STARTS_WITH) {
     return startsWith(metadata, operation, false);
   } else if (op == Ops.STARTS_WITH_IC) {
     throw new IgnoreCaseUnsupportedException();
   } else if (op == Ops.ENDS_WITH) {
     return endsWith(operation, metadata, false);
   } else if (op == Ops.ENDS_WITH_IC) {
     throw new IgnoreCaseUnsupportedException();
   } else if (op == Ops.STRING_CONTAINS) {
     return stringContains(operation, metadata, false);
   } else if (op == Ops.STRING_CONTAINS_IC) {
     throw new IgnoreCaseUnsupportedException();
   } else if (op == Ops.BETWEEN) {
     return between(operation, metadata);
   } else if (op == Ops.IN) {
     return in(operation, metadata, false);
   } else if (op == Ops.NOT_IN) {
     return notIn(operation, metadata, false);
   } else if (op == Ops.LT) {
     return lt(operation, metadata);
   } else if (op == Ops.GT) {
     return gt(operation, metadata);
   } else if (op == Ops.LOE) {
     return le(operation, metadata);
   } else if (op == Ops.GOE) {
     return ge(operation, metadata);
   } else if (op == LuceneOps.LUCENE_QUERY) {
     @SuppressWarnings("unchecked") // This is the expected type
     Query rv = ((Constant<Query>) operation.getArg(0)).getConstant();
     return rv;
   }
   throw new UnsupportedOperationException("Illegal operation " + operation);
 }
 private Path<?> getPath(Expression<?> leftHandSide) {
   if (leftHandSide instanceof Path<?>) {
     return (Path<?>) leftHandSide;
   } else if (leftHandSide instanceof Operation<?>) {
     Operation<?> operation = (Operation<?>) leftHandSide;
     if (operation.getOperator() == Ops.LOWER || operation.getOperator() == Ops.UPPER) {
       return (Path<?>) operation.getArg(0);
     }
   }
   throw new IllegalArgumentException("Unable to transform " + leftHandSide + " to path");
 }
  protected Query eq(Operation<?> operation, QueryMetadata metadata, boolean ignoreCase) {
    verifyArguments(operation);
    Path<?> path = getPath(operation.getArg(0));
    String field = toField(path);

    if (Number.class.isAssignableFrom(operation.getArg(1).getType())) {
      @SuppressWarnings("unchecked") // guarded by previous check
      Constant<? extends Number> rightArg = (Constant<? extends Number>) operation.getArg(1);
      return new TermQuery(new Term(field, convertNumber(rightArg.getConstant())));
    }

    return eq(field, convert(path, operation.getArg(1), metadata), ignoreCase);
  }
 protected Query like(Operation<?> operation, QueryMetadata metadata) {
   verifyArguments(operation);
   Path<?> path = getPath(operation.getArg(0));
   String field = toField(path);
   String[] terms = convert(path, operation.getArg(1));
   if (terms.length > 1) {
     BooleanQuery bq = new BooleanQuery();
     for (String s : terms) {
       bq.add(new WildcardQuery(new Term(field, "*" + s + "*")), Occur.MUST);
     }
     return bq;
   }
   return new WildcardQuery(new Term(field, terms[0]));
 }
 protected Query endsWith(Operation<?> operation, QueryMetadata metadata, boolean ignoreCase) {
   verifyArguments(operation);
   Path<?> path = getPath(operation.getArg(0));
   String field = toField(path);
   String[] terms = convertEscaped(path, operation.getArg(1), metadata);
   if (terms.length > 1) {
     BooleanQuery bq = new BooleanQuery();
     for (int i = 0; i < terms.length; ++i) {
       String s = i == terms.length - 1 ? "*" + terms[i] : "*" + terms[i] + "*";
       bq.add(new WildcardQuery(new Term(field, s)), Occur.MUST);
     }
     return bq;
   }
   return new WildcardQuery(new Term(field, "*" + terms[0]));
 }
 private Query toTwoHandSidedQuery(Operation<?> operation, Occur occur, QueryMetadata metadata) {
   Query lhs = toQuery(operation.getArg(0), metadata);
   Query rhs = toQuery(operation.getArg(1), metadata);
   BooleanQuery bq = new BooleanQuery();
   bq.add(createBooleanClause(lhs, occur));
   bq.add(createBooleanClause(rhs, occur));
   return bq;
 }
 protected Query in(Operation<?> operation, QueryMetadata metadata, boolean ignoreCase) {
   Path<?> path = getPath(operation.getArg(0));
   String field = toField(path);
   @SuppressWarnings("unchecked") // This is the second argument type
   Constant<Collection<?>> collConstant = (Constant<Collection<?>>) operation.getArg(1);
   Collection<?> values = collConstant.getConstant();
   BooleanQuery bq = new BooleanQuery();
   if (Number.class.isAssignableFrom(path.getType())) {
     for (Object value : values) {
       TermQuery eq = new TermQuery(new Term(field, convertNumber((Number) value)));
       bq.add(eq, Occur.SHOULD);
     }
   } else {
     for (Object value : values) {
       String[] str = convert(path, value);
       bq.add(eq(field, str, ignoreCase), Occur.SHOULD);
     }
   }
   return bq;
 }
 private void verifyArguments(Operation<?> operation) {
   List<Expression<?>> arguments = operation.getArgs();
   for (int i = 1; i < arguments.size(); ++i) {
     if (!(arguments.get(i) instanceof Constant<?>)
         && !(arguments.get(i) instanceof ParamExpression<?>)
         && !(arguments.get(i) instanceof PhraseElement)
         && !(arguments.get(i) instanceof TermElement)) {
       throw new IllegalArgumentException(
           "operand was of unsupported type " + arguments.get(i).getClass().getName());
     }
   }
 }
  /**
   * template method
   *
   * @param leftHandSide left hand side
   * @param rightHandSide right hand side
   * @return results
   */
  protected String[] convert(
      Path<?> leftHandSide, Expression<?> rightHandSide, QueryMetadata metadata) {
    if (rightHandSide instanceof Operation) {
      Operation<?> operation = (Operation<?>) rightHandSide;
      if (operation.getOperator() == LuceneOps.PHRASE) {
        return Iterables.toArray(WS_SPLITTER.split(operation.getArg(0).toString()), String.class);
      } else if (operation.getOperator() == LuceneOps.TERM) {
        return new String[] {operation.getArg(0).toString()};
      } else {
        throw new IllegalArgumentException(rightHandSide.toString());
      }
    } else if (rightHandSide instanceof ParamExpression<?>) {
      Object value = metadata.getParams().get(rightHandSide);
      if (value == null) {
        throw new ParamNotSetException((ParamExpression<?>) rightHandSide);
      }
      return convert(leftHandSide, value);

    } else if (rightHandSide instanceof Constant<?>) {
      return convert(leftHandSide, ((Constant<?>) rightHandSide).getConstant());
    } else {
      throw new IllegalArgumentException(rightHandSide.toString());
    }
  }
  /**
   * Create an Evaluator for the given sources and the given optional filter
   *
   * @param metadata query metadata
   * @param joins joins
   * @param filter where condition
   * @return evaluator
   */
  @SuppressWarnings("unchecked")
  public Evaluator<List<Object[]>> createEvaluator(
      QueryMetadata metadata, List<JoinExpression> joins, @Nullable Predicate filter) {
    List<String> sourceNames = new ArrayList<String>();
    List<Type> sourceTypes = new ArrayList<Type>();
    List<Class<?>> sourceClasses = new ArrayList<Class<?>>();
    StringBuilder vars = new StringBuilder();
    CollQuerySerializer ser = new CollQuerySerializer(templates);
    ser.append("java.util.List<Object[]> rv = new java.util.ArrayList<Object[]>();\n");

    List<String> anyJoinMatchers = new ArrayList<String>();

    // creating context
    for (JoinExpression join : joins) {
      Expression<?> target = join.getTarget();
      String typeName = com.mysema.codegen.support.ClassUtils.getName(target.getType());
      if (vars.length() > 0) {
        vars.append(",");
      }
      switch (join.getType()) {
        case DEFAULT:
          ser.append("for (" + typeName + " " + target + " : " + target + "_) {\n");
          vars.append(target);
          sourceNames.add(target + "_");
          sourceTypes.add(
              new SimpleType(Types.ITERABLE, new ClassType(TypeCategory.SIMPLE, target.getType())));
          sourceClasses.add(Iterable.class);
          break;

        case INNERJOIN:
        case LEFTJOIN:
          Operation<?> alias = (Operation<?>) join.getTarget();
          boolean colAnyJoin =
              join.getCondition() != null && join.getCondition().toString().equals("any");
          boolean leftJoin = join.getType() == JoinType.LEFTJOIN;
          String matcher = null;
          if (colAnyJoin) {
            matcher = alias.getArg(1).toString() + "_matched";
            ser.append("boolean " + matcher + " = false;\n");
            anyJoinMatchers.add(matcher);
          }
          ser.append("for (" + typeName + " " + alias.getArg(1) + " : ");
          if (leftJoin) {
            ser.append(CollQueryFunctions.class.getName() + ".leftJoin(");
          }
          if (colAnyJoin) {
            Context context = new Context();
            Expression<?> replacement = alias.getArg(0).accept(collectionAnyVisitor, context);
            ser.handle(replacement);
          } else {
            ser.handle(alias.getArg(0));
          }
          if (alias.getArg(0).getType().equals(Map.class)) {
            ser.append(".values()");
          }
          if (leftJoin) {
            ser.append(")");
          }
          ser.append(") {\n");
          if (matcher != null) {
            ser.append("if (!" + matcher + ") {\n");
          }
          vars.append(alias.getArg(1));
          break;

        default:
          throw new IllegalArgumentException("Illegal join expression " + join);
      }
    }

    // filter
    if (filter != null) {
      ser.append("try {\n");
      ser.append("if (");
      ser.handle(filter).append(") {\n");
      for (String matcher : anyJoinMatchers) {
        ser.append("    " + matcher + " = true;\n");
      }
      ser.append("    rv.add(new Object[]{" + vars + "});\n");
      ser.append("}\n");
      ser.append("} catch (NullPointerException npe) { }\n");
    } else {
      ser.append("rv.add(new Object[]{" + vars + "});\n");
    }

    // closing context
    int amount = joins.size() + anyJoinMatchers.size();
    for (int i = 0; i < amount; i++) {
      ser.append("}\n");
    }
    ser.append("return rv;");

    Map<Object, String> constantToLabel = ser.getConstantToLabel();
    Map<String, Object> constants = getConstants(metadata, constantToLabel);

    ClassType projectionType = new ClassType(TypeCategory.LIST, List.class, Types.OBJECTS);
    return factory.createEvaluator(
        ser.toString(),
        projectionType,
        sourceNames.toArray(new String[sourceNames.size()]),
        sourceTypes.toArray(new Type[sourceTypes.size()]),
        sourceClasses.toArray(new Class[sourceClasses.size()]),
        constants);
  }
 protected Query ge(Operation<?> operation, QueryMetadata metadata) {
   verifyArguments(operation);
   Path<?> path = getPath(operation.getArg(0));
   return range(path, toField(path), operation.getArg(1), null, true, true, metadata);
 }