private <A> Collection<BooleanExpression> exprFilters(
      SimpleExpression<A> expr, SimpleExpression<A> other, A knownValue) {
    HashSet<BooleanExpression> rv = new HashSet<BooleanExpression>();
    rv.add(expr.eq(other));
    rv.add(expr.eq(knownValue));

    rv.add(expr.ne(other));
    rv.add(expr.ne(knownValue));
    return ImmutableList.copyOf(rv);
  }
  @SuppressWarnings("unchecked")
  public Collection<Predicate> string(
      StringExpression expr, StringExpression other, String knownValue) {
    List<Predicate> rv = new ArrayList<Predicate>();
    if (expr instanceof Path && other instanceof Path) {
      rv.addAll(pathFilters(expr, other, knownValue));
    }
    rv.addAll(comparable(expr, other, knownValue));
    for (SimpleExpression<String> eq : projections.string(expr, other, knownValue)) {
      rv.add(eq.eq(other));
    }
    rv.add(expr.between("A", "Z"));

    rv.add(expr.charAt(0).eq(knownValue.charAt(0)));

    rv.add(expr.notBetween("A", "Z"));

    rv.add(expr.contains(other));
    rv.add(expr.contains(knownValue.substring(0, 1)));
    rv.add(expr.contains(knownValue.substring(1, 2)));

    rv.add(expr.containsIgnoreCase(other));
    rv.add(expr.containsIgnoreCase(knownValue.substring(0, 1)));
    rv.add(expr.containsIgnoreCase(knownValue.substring(1, 2)));

    rv.add(expr.endsWith(other));
    rv.add(expr.endsWith(knownValue.substring(1)));
    rv.add(expr.endsWith(knownValue.substring(2)));

    rv.add(expr.equalsIgnoreCase(other));
    rv.add(expr.equalsIgnoreCase(knownValue));

    rv.add(expr.in(Arrays.asList(knownValue)));

    rv.add(expr.indexOf(other).gt(0));
    rv.add(expr.indexOf("X", 1).gt(0));
    rv.add(expr.indexOf(knownValue).gt(0));

    rv.add(expr.locate(other).gt(1));
    if (!target.equals(Target.FIREBIRD)) { // FIXME
      rv.add(expr.locate("X", 2).gt(1));
    }
    rv.add(expr.locate(knownValue).gt(1));

    //        if (!module.equals(Module.HQL) && !module.equals(Module.JDOQL) &&
    // !module.equals(Module.SQL)) {
    //            rv.add(expr.lastIndexOf(other).gt(0));
    //            rv.add(expr.lastIndexOf(knownValue).gt(0));
    //        }

    rv.add(expr.in("A", "B", "C"));

    rv.add(expr.isEmpty());
    rv.add(expr.isNotEmpty());

    rv.add(expr.length().gt(0));

    rv.add(expr.like(knownValue.substring(0, 1) + "%"));
    rv.add(expr.like("%" + knownValue.substring(1)));
    rv.add(expr.like("%" + knownValue.substring(1, 2) + "%"));

    rv.add(expr.like(knownValue.substring(0, 1) + "%", '!'));
    rv.add(expr.like("%" + knownValue.substring(1), '!'));
    rv.add(expr.like("%" + knownValue.substring(1, 2) + "%", '!'));

    rv.add(expr.notLike(knownValue.substring(0, 1) + "%"));
    rv.add(expr.notLike("%" + knownValue.substring(1)));
    rv.add(expr.notLike("%" + knownValue.substring(1, 2) + "%"));

    if (!target.equals(Target.DERBY)
        && !target.equals(Target.FIREBIRD)
        && !target.equals(Target.HSQLDB)
        && !target.equals(Target.H2)
        && !target.equals(Target.SQLITE)
        && !target.equals(Target.SQLSERVER)) {
      rv.add(expr.matches(knownValue.substring(0, 1) + ".*"));
      rv.add(expr.matches(".*" + knownValue.substring(1)));
      rv.add(expr.matches(".*" + knownValue.substring(1, 2) + ".*"));
    }

    rv.add(expr.notIn("A", "B", "C"));

    rv.add(expr.notBetween("A", "Z"));
    rv.add(expr.notBetween(other, other));

    if (!target.equals(Target.DERBY) && !module.equals(Module.JDO)) {
      // https://issues.apache.org/jira/browse/DERBY-4389
      rv.add(new Coalesce<String>(String.class, expr, other).getValue().eq("xxx"));
    }

    //        rv.add(expr.in(IntervalImpl.create("A", "Z")));

    return ImmutableList.copyOf(rv);
  }