/* * Copyright (c) 2006-2011 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit.emulation.hibernate3.ast.whereClause; import java.math.*; import java.util.*; import mockit.emulation.hibernate3.ast.*; final class RelationalExpr extends Expr { final Expr lhsExpr; final Expr rhsExpr; final String operator; final boolean negated; RelationalExpr(Expr lhsExpr, Expr rhsExpr, String operator, boolean negated) { this.lhsExpr = lhsExpr; this.rhsExpr = rhsExpr; this.operator = operator; this.negated = negated; } public static Expr parse(Tokens tokens) { Expr lhsExpr = ConcatenationExpr.parse(tokens); if (!tokens.hasNext()) { return lhsExpr; } String operator = tokens.next().toLowerCase(); boolean negated = false; if ("not".equals(operator)) { negated = true; operator = tokens.next().toLowerCase(); } Expr rhsExpr; if (isRelationalOperator(operator)) { rhsExpr = !negated ? AdditiveExpr.parse(tokens) : null; // TODO: allow repetition } else if ("in".equals(operator)) { rhsExpr = InList.parse(tokens); } else if ("between".equals(operator)) { rhsExpr = BetweenList.parse(tokens); } else if ("like".equals(operator)) { rhsExpr = ConcatenationExpr.parse(tokens); // TODO: likeEscape } else if ("member".equals(operator)) { rhsExpr = parseMemberOf(tokens); } else { tokens.pushback(); return lhsExpr; } if (rhsExpr == null) { throw new QuerySyntaxException(tokens); } return new RelationalExpr(lhsExpr, rhsExpr, operator, negated); } private static boolean isRelationalOperator(String operator) { return "<".equals(operator) || "<=".equals(operator) || ">".equals(operator) || ">=".equals(operator); } private static Expr parseMemberOf(Tokens tokens) { if (!"of".equalsIgnoreCase(tokens.next())) { tokens.pushback(); } return AccessPathExpr.parse(tokens); } @Override public Boolean evaluate(QueryEval eval) { Object value1 = lhsExpr.evaluate(eval); Object value2 = rhsExpr.evaluate(eval); boolean result; if ("in".equals(operator)) { Collection<?> values = (Collection<?>) value2; result = values.contains(value1); } else if ("between".equals(operator)) { return evaluateBetweenValues(value1, value2); } else if ("like".equals(operator)) { result = evaluateLikeOperator(value1, value2); } else if ("member".equals(operator)) { return ((Collection<?>) value2).contains(value1); } else { result = evaluateRelationalOperator(value1, value2); } return negated ? !result : result; } private Boolean evaluateBetweenValues(Object value1, Object value2) { Object[] values = (Object[]) value2; Comparable<Object> cmpVal = (Comparable<Object>) value1; Comparable<Object> cmpVal1 = (Comparable<Object>) values[0]; Comparable<Object> cmpVal2 = (Comparable<Object>) values[1]; return cmpVal.compareTo(cmpVal1) >= 0 && cmpVal.compareTo(cmpVal2) <= 0; } private boolean evaluateRelationalOperator(Object value1, Object value2) { if (value1 instanceof Number && value2 instanceof Number) { value1 = new BigDecimal(value1.toString()); value2 = new BigDecimal(value2.toString()); } Comparable<Object> cmpVal1 = (Comparable<Object>) value1; Comparable<Object> cmpVal2 = (Comparable<Object>) value2; int cmp = cmpVal1.compareTo(cmpVal2); char operator = this.operator.charAt(0); if (this.operator.length() == 1) { return operator == '<' ? cmp < 0 : cmp > 0; } else { return operator == '<' ? cmp <= 0 : cmp >= 0; } } private Boolean evaluateLikeOperator(Object value1, Object value2) { String strVal1 = (String) value1; String strVal2 = (String) value2; String regex = strVal2.replace("%", ".*"); return strVal1.matches(regex); } }