package com.temenos.interaction.odataext.odataparser.data; /* * Classes containing metadata about oData 'relations' (i.e. 'operators' and 'functions') between groups of operands. * * Also contains information to support equivalent relation in other query languages (e.g. SQL/SOLR). * * Each Relation corresponds to an oData4j expression. Where possibly the metadata is recovered from the equivalent * expression. However sometimes the required information is not present, or private, and has to be duplicated here. */ /* * #%L * interaction-odata4j-ext * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import org.odata4j.expression.AddExpression; import org.odata4j.expression.AndExpression; import org.odata4j.expression.BinaryBoolCommonExpression; import org.odata4j.expression.BinaryCommonExpression; import org.odata4j.expression.CeilingMethodCallExpression; import org.odata4j.expression.ConcatMethodCallExpression; import org.odata4j.expression.DayMethodCallExpression; import org.odata4j.expression.DivExpression; import org.odata4j.expression.EndsWithMethodCallExpression; import org.odata4j.expression.EqExpression; import org.odata4j.expression.FloorMethodCallExpression; import org.odata4j.expression.GeExpression; import org.odata4j.expression.GtExpression; import org.odata4j.expression.HourMethodCallExpression; import org.odata4j.expression.IndexOfMethodCallExpression; import org.odata4j.expression.IsofExpression; import org.odata4j.expression.LeExpression; import org.odata4j.expression.LengthMethodCallExpression; import org.odata4j.expression.LtExpression; import org.odata4j.expression.MethodCallExpression; import org.odata4j.expression.MinuteMethodCallExpression; import org.odata4j.expression.ModExpression; import org.odata4j.expression.MonthMethodCallExpression; import org.odata4j.expression.MulExpression; import org.odata4j.expression.NeExpression; import org.odata4j.expression.NotExpression; import org.odata4j.expression.OrExpression; import org.odata4j.expression.ReplaceMethodCallExpression; import org.odata4j.expression.RoundMethodCallExpression; import org.odata4j.expression.SecondMethodCallExpression; import org.odata4j.expression.StartsWithMethodCallExpression; import org.odata4j.expression.SubExpression; import org.odata4j.expression.SubstringMethodCallExpression; import org.odata4j.expression.SubstringOfMethodCallExpression; import org.odata4j.expression.ToLowerMethodCallExpression; import org.odata4j.expression.ToUpperMethodCallExpression; import org.odata4j.expression.TrimMethodCallExpression; import org.odata4j.expression.YearMethodCallExpression; public enum Relation { // Note : The double line spacing here is ugly but necessary to prevent auto // formatting from putting it all on one line. // Operators EQ("eq", "=", EqExpression.class, false), NE("ne", "<>", NeExpression.class, false), LT("lt", "<", LtExpression.class, false), GT("gt", ">", GtExpression.class, false), LE("le", "<=", LeExpression.class, false), GE("ge", ">=", GeExpression.class, false), AND("and", null, AndExpression.class, false), OR("or", null, OrExpression.class, false), NOT("not", null, NotExpression.class, false), ADD("add", null, AddExpression.class, true), SUB("sub", null, SubExpression.class, true), MUL("mul", null, MulExpression.class, true), DIV("div", null, DivExpression.class, true), MOD("mod", null, ModExpression.class, true), // Unary functions. TOUPPER("toupper", null, ToUpperMethodCallExpression.class, false), TOLOWER("tolower", null, ToLowerMethodCallExpression.class, false), LENGTH("length", null, LengthMethodCallExpression.class, false), TRIM("trim", null, TrimMethodCallExpression.class, false), ISOF("isof", null, IsofExpression.class, false), // Unary time related functions YEAR("year", null, YearMethodCallExpression.class, false), MONTH("month", null, MonthMethodCallExpression.class, false), DAY("day", null, DayMethodCallExpression.class, false), HOUR("hour", null, HourMethodCallExpression.class, false), MINUTE("minute", null, MinuteMethodCallExpression.class, false), SECOND("second", null, SecondMethodCallExpression.class, false), // Unary maths functions ROUND("round", null, RoundMethodCallExpression.class, false), FLOOR("floor", null, FloorMethodCallExpression.class, false), CEILING("ceiling", null, CeilingMethodCallExpression.class, false), // Binary functions. SUBSTROF("substringof", null, SubstringOfMethodCallExpression.class, false), ENDSWITH("endswith", null, EndsWithMethodCallExpression.class, false), STARTSWITH("startswith", null, StartsWithMethodCallExpression.class, false), INDEXOF("indexof", null, IndexOfMethodCallExpression.class, false), CONCAT("concat", null, ConcatMethodCallExpression.class, false), // Ternary functions. SUBSTR("substring", null, SubstringMethodCallExpression.class, false), REPLACE("replace", null, ReplaceMethodCallExpression.class, false); // OData equivalent. Should really be string constants from oData4j. But // those are scoped as private so have to redefine here. private final String oDataString; // Equivalent SQL symbol, May also contain a standard format string // indicating how the arguments should be arranged. // // TODO This is retained only for backwards compatibility with the six basic // operands. Equivalent functionality // is now provided by the interaction-jdbc-producer SqlRelation enum. Once // backward compatibility is no longer // required this should be removed. @Deprecated private String sqlSymbol; // Equivalent oData4j expression class. private Class<?> oData4jClass; // Flag indicated only numeric arguments are supported. private boolean isNumeric; private Relation(String oDataString, String sqlSymbol, Class<?> oDataClass, boolean isNumeric) { this.oDataString = oDataString; this.sqlSymbol = sqlSymbol; this.oData4jClass = oDataClass; this.isNumeric = isNumeric; } public String getoDataString() { return (oDataString); } // Return equivalent SQL symbol. Null if not supported. @Deprecated public String getSqlSymbol() { return (sqlSymbol); } public Class<?> getOData4jClass() { return (oData4jClass); } public boolean isBoolean() { // return type == Type.BOOLEAN; return !BinaryCommonExpression.class.isAssignableFrom(getOData4jClass()); } public boolean isNumeric() { return isNumeric; } // Get expected number of arguments public int getExpectedArgumentCount() { if (!isFunctionCall()) { // For operators we can work out the argument count from the // expression type. if (BinaryCommonExpression.class.isAssignableFrom(getOData4jClass()) || BinaryBoolCommonExpression.class.isAssignableFrom(getOData4jClass())) { // It's binary return 2; } if (SubstringMethodCallExpression.class.equals(getOData4jClass())) { // This is the only expression with three arguments. return 3; } // If we get here it's a unary operator. return 1; } else { // For functions there does not appear to be a way to work out // the argument count ... hard code it dependant on the relation // type. switch (this) { case REPLACE: return 3; case SUBSTR: // This one is special. Can be called with 2 or 3 arguments. return 2; case ISOF: // This one is special. Can be called with 1 or 2 arguments. return 1; case SUBSTROF: case ENDSWITH: case STARTSWITH: case INDEXOF: case CONCAT: // Binary functions return 2; case TOUPPER: case TRIM: // Unary functions return 1; default: // Should never get here return 1; } } } // Returns true if a function, e.g. 'fn(a, b...)' rather then an // operator, e.g. 'a op b'. public boolean isFunctionCall() { // ISOF is a special case. Not derived from 'method' but has function // like syntax. if (Relation.ISOF == this) { return true; } // Entries based on 'Method' are functions. return MethodCallExpression.class.isAssignableFrom(getOData4jClass()); } }