package eu.leads.processor.utils.math; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import eu.leads.processor.execute.Tuple; import eu.leads.processor.query.QueryContext; import eu.leads.processor.utils.SQLUtils; import net.sf.jsqlparser.schema.Column; import java.io.IOException; import static eu.leads.processor.utils.math.MathOperatorTreeNode.NodeType.EXPRESSION; /** * Created with IntelliJ IDEA. * User: vagvaz * Date: 10/29/13 * Time: 5:17 AM * To change this template use File | Settings | File Templates. */ //Basic Class needed to create the tree node. @JsonAutoDetect @JsonDeserialize(converter = MathTreeOperatorNodeConverter.class) public class MathOperatorTreeNode { public enum NodeType {EXPRESSION, OPERAND} private MathOperatorTreeNode left; private MathOperatorTreeNode right; private String operand; private String expressionFunction; private boolean not; private NodeType type; private String valueType; private String value; public String getValueType() { return valueType; } public void setValueType(String valueType) { this.valueType = valueType; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public MathOperatorTreeNode(JsonNode jsonNode) { if (jsonNode.has("stringExpression") || jsonNode.has("expression")) { type = EXPRESSION; expressionFunction = jsonNode.path("stringExpression").asText(); not = jsonNode.path("not").asBoolean(); JsonNode node = null; if (!jsonNode.has("leftExpression")) node = jsonNode.path("expression"); else node = jsonNode; left = new MathOperatorTreeNode(node.path("leftExpression")); right = new MathOperatorTreeNode((node.path("rightExpression"))); operand = null; } else { type = NodeType.OPERAND; left = null; right = null; expressionFunction = ""; ObjectMapper mapper = new ObjectMapper(); try { operand = mapper.writeValueAsString(jsonNode); } catch (JsonProcessingException e) { e.printStackTrace(); } } } public MathOperatorTreeNode(String operand) { type = NodeType.OPERAND; left = null; right = null; expressionFunction = ""; setOperand(operand); setNot(false); } public MathOperatorTreeNode(MathOperatorTreeNode left, MathOperatorTreeNode right, boolean isNot, String expressionFunction) { setLeft(left); setRight(right); setNot(isNot); setExpressionFunction(expressionFunction); operand = null; type = EXPRESSION; } @JsonIgnore public boolean accept(Tuple tuple, QueryContext context) { if (type == NodeType.EXPRESSION) { if (left.accept(tuple, context) && right.accept(tuple, context)) { // String leftValue = left.getValue(); // String rightValue = right.getValue(); return calculate(left, right, expressionFunction); } return false; } else { ObjectMapper mapper = new ObjectMapper(); try { JsonNode jsonNode = mapper.readTree(operand); if (jsonNode.has("columnName")) { Column c = mapper.readValue(jsonNode.toString(), Column.class); String columnType = context.getColumnType(c.getColumnName(), context.resolveTableName(c.getColumnName())); valueType = "column." + c.getColumnName() + "." + columnType; value = tuple.getAttribute(c.getColumnName()); } else if (jsonNode.has("value")) { if (jsonNode.has("stringValue")) { value = jsonNode.path("stringValue").asText(); valueType = ".string"; } else { value = jsonNode.path("value").asText(); valueType = ".constant"; } } else if (jsonNode.has("name")) { String c = SQLUtils.extractFunction(jsonNode).toString(); valueType = "column." + c + ".double"; value = tuple.getAttribute(c.toString()); } else { valueType = "null"; value = "NULL"; } } catch (IOException e) { e.printStackTrace(); } return true; } } private boolean calculate(MathOperatorTreeNode left, MathOperatorTreeNode right, String expression) { boolean result = true; valueType = "intermediate.boolean"; if (expression.equals("LIKE")) { result = left.getValue().toLowerCase().contains(right.getValue().toLowerCase()); } else if (expression.equals("<")) { if (left.getValueType().startsWith("column")) { String leftType = left.getValueType(); String c = leftType.substring(leftType.lastIndexOf('.') + 1); if (c.equalsIgnoreCase("double") || c.equalsIgnoreCase("long") || c.equalsIgnoreCase("int")) { Double l = Double.valueOf(left.getValue()); Double r = Double.valueOf(right.getValue()); result = l < r; } else if (c.equals("string")) { result = left.getValue().compareTo(right.getValue()) < 0; } else if (c.equals("date")) { //TODO Long l = Long.valueOf(left.getValue()); Long r = Long.valueOf(right.getValue()); result = l < r; } else if (c.equals("NULL")) { result = true; } else if (c.equals("constant")) { String rightType = right.getValueType(); String r = rightType.substring(rightType.lastIndexOf('.') + 1); if (!r.equals("constant")) { result = calculate(right, left, ">"); } else result = left.getValue().compareTo(right.getValue()) < 0; } } } else if (expression.equals(">")) { String leftType = left.getValueType(); String c = leftType.substring(leftType.lastIndexOf('.') + 1); if (c.equalsIgnoreCase("double") || c.equalsIgnoreCase("long") || c.equalsIgnoreCase("int")) { Double l = Double.valueOf(left.getValue()); Double r = Double.valueOf(right.getValue()); result = l > r; } else if (c.equals("string")) { result = left.getValue().compareTo(right.getValue()) > 0; } else if (c.equals("date")) { //TODO Long l = Long.valueOf(left.getValue()); Long r = Long.valueOf(right.getValue()); result = l > r; } else if (c.equals("NULL")) { result = true; } else if (c.equals("constant")) { String rightType = right.getValueType(); String r = rightType.substring(rightType.lastIndexOf('.') + 1); if (!r.equals("constant")) { result = calculate(right, left, "<"); } else result = left.getValue().compareTo(right.getValue()) > 0; } } else if (expression.equalsIgnoreCase("OR")) { if (left.getValueType().endsWith("boolean") && right.getValueType().endsWith("boolean")) { result = Boolean.valueOf(left.getValue()) || Boolean.valueOf(right.getValue()); } result = true; } else if ((expression.equalsIgnoreCase("AND"))) { if (left.getValueType().endsWith("boolean") && right.getValueType().endsWith("boolean")) { result = Boolean.valueOf(left.getValue()) && Boolean.valueOf(right.getValue()); } result = true; } value = Boolean.toString(result); return result; } public MathOperatorTreeNode getLeft() { return left; } public void setLeft(MathOperatorTreeNode left) { this.left = left; } public MathOperatorTreeNode getRight() { return right; } public void setRight(MathOperatorTreeNode right) { this.right = right; } public String getOperand() { return operand; } public void setOperand(String operand) { this.operand = operand; } public String getExpressionFunction() { return expressionFunction; } public void setExpressionFunction(String expressionFunction) { this.expressionFunction = expressionFunction; } public boolean isNot() { return not; } public void setNot(boolean not) { this.not = not; } public NodeType getType() { return type; } public void setType(NodeType type) { this.type = type; } @Override public String toString() { String result = ""; if (type == NodeType.OPERAND && operand != null) { // result += "\ntype: operand " + operand.toString(); ObjectMapper mapper = new ObjectMapper(); try { JsonNode jsonNode = mapper.readTree(operand); if (jsonNode.has("columnName")) { Column c = mapper.readValue(jsonNode.toString(), Column.class); result += c.toString(); } else if (jsonNode.has("value")) { if (jsonNode.has("stringValue")) { result += jsonNode.path("stringValue").asText(); } else { result += jsonNode.path("value").asText(); } } else if (jsonNode.has("name")) { result += SQLUtils.extractFunction(jsonNode).toString(); } else { result += "NULL"; } } catch (IOException e) { e.printStackTrace(); } } else if (type == EXPRESSION) { // result += "\ntype: expression \n\t\tleft: " + left.toString() + " \n\\t\t" + right.toString(); result += "( " + left.toString() + " " + this.expressionFunction + " " + right.toString() + " ) "; } return result; } }