package eu.stratosphere.sopremo.expressions; import eu.stratosphere.sopremo.EvaluationContext; import eu.stratosphere.sopremo.type.AbstractNumericNode; import eu.stratosphere.sopremo.type.BooleanNode; import eu.stratosphere.sopremo.type.IJsonNode; /** * Represents basic binary comparative expressions covering all operators specified in {@link BinaryOperator}. */ @OptimizerHints(scope = Scope.ANY, minNodes = 2, maxNodes = 2) public class ComparativeExpression extends BinaryBooleanExpression { /** * */ private static final long serialVersionUID = 4684417232092074534L; private EvaluationExpression expr1; private EvaluationExpression expr2; private final BinaryOperator binaryOperator; /** * Initializes a ComparativeExpression with the given binaryOperator and both expressions. * * @param expr1 * the first expression for the comparison * @param binaryOperator * the {@link BinaryOperator} that should be used for comparison * @param expr2 * the second expression for the comparison */ public ComparativeExpression(final EvaluationExpression expr1, final BinaryOperator binaryOperator, final EvaluationExpression expr2) { this.expr1 = expr1; this.binaryOperator = binaryOperator; this.expr2 = expr2; } @Override public boolean equals(final Object obj) { if (!super.equals(obj)) return false; final ComparativeExpression other = (ComparativeExpression) obj; return this.binaryOperator == other.binaryOperator && this.expr1.equals(other.expr1) && this.expr2.equals(other.expr2); } /* * (non-Javadoc) * @see eu.stratosphere.sopremo.expressions.EvaluationExpression#clone() */ @Override public ComparativeExpression clone() { final ComparativeExpression klone = (ComparativeExpression) super.clone(); klone.expr1 = klone.expr1.clone(); klone.expr2 = klone.expr2.clone(); return klone; } // @Override // public Iterator<IJsonNode> evaluate(Iterator<IJsonNode> input) { // return binaryOperator.evaluate(expr1.evaluate(input), expr2.evaluate(input)); // } @Override public IJsonNode evaluate(final IJsonNode node, final IJsonNode target, final EvaluationContext context) { // // we can ignore 'target' because no new Object is created return BooleanNode.valueOf(this.binaryOperator.evaluate(this.expr1.evaluate(node, null, context), this.expr2.evaluate(node, null, context))); } /* * (non-Javadoc) * @see * eu.stratosphere.sopremo.expressions.EvaluationExpression#transformRecursively(eu.stratosphere.sopremo.expressions * .TransformFunction) */ @Override public EvaluationExpression transformRecursively(final TransformFunction function) { this.expr1 = this.expr1.transformRecursively(function); this.expr2 = this.expr2.transformRecursively(function); return function.call(this); } /** * Returns the binaryOperator. * * @return the binaryOperator */ public BinaryOperator getBinaryOperator() { return this.binaryOperator; } /** * Returns the first expression. * * @return the first expression */ public EvaluationExpression getExpr1() { return this.expr1; } /** * Returns the second expression. * * @return the second expression */ public EvaluationExpression getExpr2() { return this.expr2; } @Override public int hashCode() { final int prime = 47; int result = super.hashCode(); result = prime * result + this.binaryOperator.hashCode(); result = prime * result + this.expr1.hashCode(); result = prime * result + this.expr2.hashCode(); return result; } @Override public void toString(final StringBuilder builder) { builder.append(this.expr1).append(this.binaryOperator).append(this.expr2); } /** * All supported binary operators. */ public static enum BinaryOperator { EQUAL("=") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult == 0; } // @Override // public boolean evaluate(IJsonNode e1, IJsonNode e2) { // return e1.equals(e2); // }; }, NOT_EQUAL("<>") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult != 0; } // @Override // public boolean evaluate(IJsonNode e1, IJsonNode e2) { // return !e1.equals(e2); // }; }, LESS("<") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult < 0; } // @Override // public <T extends java.lang.Comparable<T>> boolean evaluateComparable(final T e1, final T e2) { // return e1.compareTo(e2) < 0; // }; }, LESS_EQUAL("<=") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult <= 0; } // @Override // public <T extends java.lang.Comparable<T>> boolean evaluateComparable(final T e1, final T e2) { // return e1.compareTo(e2) <= 0; // }; }, GREATER(">") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult > 0; } // @Override // public <T extends java.lang.Comparable<T>> boolean evaluateComparable(final T e1, final T e2) { // return e1.compareTo(e2) > 0; // }; }, GREATER_EQUAL(">=") { @Override public boolean isTrue(final int comparisonResult) { return comparisonResult >= 0; } // @Override // public <T extends java.lang.Comparable<T>> boolean evaluateComparable(final T e1, final T e2) { // return e1.compareTo(e2) >= 0; // }; }; private final String sign; /** * Initializes a BinaryOperator with the given sign. * * @param sign * the string representation of this operator */ BinaryOperator(final String sign) { this.sign = sign; } public boolean evaluate(final IJsonNode e1, final IJsonNode e2) { if (e1.getClass() != e2.getClass()) { if (e1 instanceof AbstractNumericNode && e2 instanceof AbstractNumericNode) return this.isTrue(e1.compareTo(e2)); // throw new EvaluationException(String.format("Cannot compare %s %s %s", e1, this, e2)); return false; } return this.isTrue(e1.compareToSameType(e2)); } public abstract boolean isTrue(final int comparisonResult); // // public boolean evaluateComparable(final T e1, final T e2) { // return false; // } @Override public String toString() { return this.sign; } /** * Returns the BinaryOperator for the given sign. * * @param sign * the sign of the operator that should be returned * @return the operator or null if no operator has been found for the given sign */ public static BinaryOperator valueOfSymbol(final String sign) { for (final BinaryOperator operator : BinaryOperator.values()) if (operator.sign.equals(sign)) return operator; return null; } } }