Java tutorial
/* * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131 * Karlsruhe, Germany. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.fraunhofer.iosb.ilt.sta.persistence.postgres; import com.querydsl.core.Tuple; import com.querydsl.core.types.Expression; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.QTuple; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.ComparableExpression; import com.querydsl.core.types.dsl.ComparableExpressionBase; import com.querydsl.core.types.dsl.DateExpression; import com.querydsl.core.types.dsl.DateTimeExpression; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.core.types.dsl.NumberPath; import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.core.types.dsl.TimeTemplate; import com.querydsl.spatial.GeometryExpression; import com.querydsl.sql.SQLExpressions; import com.querydsl.sql.SQLQuery; import de.fraunhofer.iosb.ilt.sta.path.CustomProperty; import de.fraunhofer.iosb.ilt.sta.path.EntityProperty; import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty; import de.fraunhofer.iosb.ilt.sta.path.Property; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantDateExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantDateTimeExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantDurationExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantGeometryExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantNumberExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantStringExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ConstantTimeExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.JsonExpressionFactory; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.ListExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.StringCastExpressionFactory; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.TimeExpression; import de.fraunhofer.iosb.ilt.sta.persistence.postgres.expression.TimeIntervalExpression; import de.fraunhofer.iosb.ilt.sta.query.OrderBy; import de.fraunhofer.iosb.ilt.sta.query.expression.ExpressionVisitor; import de.fraunhofer.iosb.ilt.sta.query.expression.Path; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.BooleanConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.DateConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.DateTimeConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.DoubleConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.DurationConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.IntegerConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.IntervalConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.LineStringConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.PointConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.PolygonConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.StringConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.constant.TimeConstant; import de.fraunhofer.iosb.ilt.sta.query.expression.function.arithmetic.Add; import de.fraunhofer.iosb.ilt.sta.query.expression.function.arithmetic.Divide; import de.fraunhofer.iosb.ilt.sta.query.expression.function.arithmetic.Modulo; import de.fraunhofer.iosb.ilt.sta.query.expression.function.arithmetic.Multiply; import de.fraunhofer.iosb.ilt.sta.query.expression.function.arithmetic.Subtract; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.Equal; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.GreaterEqual; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.GreaterThan; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.LessEqual; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.LessThan; import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.NotEqual; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Date; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Day; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.FractionalSeconds; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Hour; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.MaxDateTime; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.MinDateTime; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Minute; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Month; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Now; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Second; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Time; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.TotalOffsetMinutes; import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Year; import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoDistance; import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoIntersects; import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoLength; import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.And; import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Not; import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Or; import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Ceiling; import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Floor; import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Round; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STContains; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STCrosses; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STDisjoint; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STEquals; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STIntersects; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STOverlaps; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STRelate; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STTouches; import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STWithin; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.Concat; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.EndsWith; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.IndexOf; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.Length; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.StartsWith; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.Substring; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.SubstringOf; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.ToLower; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.ToUpper; import de.fraunhofer.iosb.ilt.sta.query.expression.function.string.Trim; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.After; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Before; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.During; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Finishes; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Meets; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Overlaps; import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Starts; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; import org.geolatte.geom.Geometry; import org.geolatte.geom.codec.Wkt; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; import org.joda.time.LocalDate; import org.joda.time.LocalTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Hylke van der Schaaf */ public class PgExpressionHandler implements ExpressionVisitor<Expression<?>> { /** * The logger for this class. */ private static final Logger LOGGER = LoggerFactory.getLogger(PgExpressionHandler.class); private final PathSqlBuilder psb; /** * The table reference for the main table of the request. */ private final PathSqlBuilder.TableRef tableRef; public PgExpressionHandler(PathSqlBuilder psb, PathSqlBuilder.TableRef tableRef) { this.psb = psb; this.tableRef = tableRef; } public void addFilterToQuery(de.fraunhofer.iosb.ilt.sta.query.expression.Expression filter, SQLQuery<Tuple> sqlQuery) { Expression<?> filterExpression = filter.accept(this); if (filterExpression instanceof Predicate) { Predicate predicate = (Predicate) filterExpression; sqlQuery.where(predicate); return; } else if (filterExpression instanceof ListExpression) { ListExpression listExpression = (ListExpression) filterExpression; for (Expression<?> expression : listExpression.getExpressions().values()) { if (expression instanceof Predicate) { Predicate predicate = (Predicate) expression; sqlQuery.where(predicate); return; } } } LOGGER.error("Filter is not a predicate but a {}.", filterExpression.getClass().getName()); throw new IllegalArgumentException( "Filter is not a predicate but a " + filterExpression.getClass().getName()); } public void addOrderbyToQuery(OrderBy orderBy, SQLQuery<Tuple> sqlQuery) { Expression<?> resultExpression = orderBy.getExpression().accept(this); if (resultExpression instanceof TimeIntervalExpression) { TimeIntervalExpression ti = (TimeIntervalExpression) resultExpression; addToQuery(orderBy, ti.getStart(), sqlQuery); addToQuery(orderBy, ti.getEnd(), sqlQuery); } if (resultExpression instanceof ConstantDurationExpression) { ConstantDurationExpression duration = (ConstantDurationExpression) resultExpression; addToQuery(orderBy, duration.getDuration(), sqlQuery); } if (resultExpression instanceof ListExpression) { for (Expression<?> sqlExpression : ((ListExpression) resultExpression).getExpressionsForOrder() .values()) { addToQuery(orderBy, sqlExpression, sqlQuery); } } else { addToQuery(orderBy, resultExpression, sqlQuery); } } public void addToQuery(OrderBy orderBy, Expression<?> sqlExpression, SQLQuery<Tuple> sqlQuery) { if (sqlExpression instanceof ComparableExpressionBase) { ComparableExpressionBase comparable = (ComparableExpressionBase) sqlExpression; Expression<?> projection = sqlQuery.getMetadata().getProjection(); if (projection instanceof QTuple) { QTuple qTuple = (QTuple) projection; List<Expression<?>> args = new ArrayList<>(qTuple.getArgs()); args.add(comparable); sqlQuery.select(args.toArray(new Expression[args.size()])); } if (orderBy.getType() == OrderBy.OrderType.Ascending) { sqlQuery.orderBy(comparable.asc()); } else { sqlQuery.orderBy(comparable.desc()); } } } public static <T extends Expression<?>> T checkType(Class<T> expectedClazz, Expression<?> input, boolean canCast) { if (expectedClazz.isAssignableFrom(input.getClass())) { LOGGER.debug("Is {}: {} ({} -- {})", expectedClazz.getName(), input, input.getClass().getName(), input.getType().getName()); return expectedClazz.cast(input); } else { if (canCast && StringExpression.class.equals(expectedClazz) && input instanceof NumberPath) { NumberPath numberPath = (NumberPath) input; return (T) numberPath.stringValue(); } LOGGER.debug("Not a {}: {} ({} -- {})", expectedClazz.getName(), input, input.getClass().getName(), input.getType().getName()); throw new IllegalArgumentException("Could not convert parameter of type " + input.getClass().getName() + " to type " + expectedClazz.getName()); } } public static <T extends Expression<?>> T getSingleOfType(Class<T> expectedClazz, Expression<?> input) { if (input instanceof TimeIntervalExpression) { TimeIntervalExpression ti = (TimeIntervalExpression) input; return checkType(expectedClazz, ti.getStart(), true); } if (input instanceof ListExpression) { ListExpression listExpression = (ListExpression) input; Map<String, Expression<?>> expressions = listExpression.getExpressions(); Collection<Expression<?>> values = expressions.values(); // Two passes, first do an exact check (no casting allowed) for (Expression<?> subResult : values) { try { return checkType(expectedClazz, subResult, false); } catch (IllegalArgumentException e) { LOGGER.trace("Parameter not of type {}.", expectedClazz.getName()); LOGGER.trace("", e); } } // No exact check. Now check again, but allow casting. for (Expression<?> subResult : values) { try { return checkType(expectedClazz, subResult, true); } catch (IllegalArgumentException e) { LOGGER.trace("Parameter not of type {}.", expectedClazz.getName()); LOGGER.trace("", e); } } throw new IllegalArgumentException( "Non of the entries could be converted to type " + expectedClazz.getName()); } else { return checkType(expectedClazz, input, true); } } @Override public Expression<?> visit(Path path) { PathSqlBuilder.TableRef pathTableRef = tableRef.copy(); List<Property> elements = path.getElements(); int pathLength = elements.size(); Expression<?> finalExpression = null; for (int i = 0; i < pathLength; i++) { Property element = elements.get(i); if (element instanceof CustomProperty) { if (finalExpression == null) { throw new IllegalArgumentException("CustomProperty must follow an EntityProperty: " + path); } // generate finalExpression::jsonb#>>'{x,y,z}' JsonExpressionFactory jsonFactory = new JsonExpressionFactory(finalExpression); for (; i < pathLength; i++) { jsonFactory.addToPath(elements.get(i).getName()); } return jsonFactory.build(); } else if (element instanceof EntityProperty) { if (finalExpression != null) { throw new IllegalArgumentException( "EntityProperty can not follow an other EntityProperty: " + path); } EntityProperty entityProperty = (EntityProperty) element; Map<String, Expression<?>> pathExpressions = PropertyResolver.expressionsForProperty(entityProperty, pathTableRef.qPath, new LinkedHashMap<>()); if (pathExpressions.size() == 1) { finalExpression = pathExpressions.values().iterator().next(); } else { finalExpression = getSubExpression(elements, i, pathExpressions); } } else if (element instanceof NavigationProperty) { if (finalExpression != null) { throw new IllegalArgumentException( "NavigationProperty can not follow an EntityProperty: " + path); } NavigationProperty navigationProperty = (NavigationProperty) element; psb.queryEntityType(navigationProperty.getType(), null, pathTableRef); } } if (finalExpression == null) { throw new IllegalArgumentException("Path does not end in an EntityProperty: " + path); } return finalExpression; } private Expression<?> getSubExpression(List<Property> elements, int curIdx, Map<String, Expression<?>> pathExpressions) { int nextIdx = curIdx + 1; if (elements.size() > nextIdx) { Property subProperty = elements.get(nextIdx); return pathExpressions.get(subProperty.getName()); } else { if (pathExpressions.containsKey(PropertyResolver.KEY_TIME_INTERVAL_START) && pathExpressions.containsKey(PropertyResolver.KEY_TIME_INTERVAL_END)) { return new TimeIntervalExpression(pathExpressions); } return new ListExpression(pathExpressions); } } public Expression<?>[] findPair(Expression<?> p1, Expression<?> p2) { Expression<?>[] result = new Expression<?>[2]; try { result[0] = getSingleOfType(NumberExpression.class, p1); result[1] = getSingleOfType(NumberExpression.class, p2); return result; } catch (IllegalArgumentException e) { } try { result[0] = getSingleOfType(BooleanExpression.class, p1); result[1] = getSingleOfType(BooleanExpression.class, p2); return result; } catch (IllegalArgumentException e) { } boolean firstIsString = false; try { result[0] = getSingleOfType(StringExpression.class, p1); firstIsString = true; result[1] = getSingleOfType(StringExpression.class, p2); return result; } catch (IllegalArgumentException e) { } // If one of the two is a string, cast the other if (firstIsString) { result[1] = StringCastExpressionFactory.build(p2); return result; } else { try { result[1] = getSingleOfType(StringExpression.class, p2); result[0] = StringCastExpressionFactory.build(p1); return result; } catch (IllegalArgumentException e) { } } result[0] = getSingleOfType(ComparableExpression.class, p1); result[1] = getSingleOfType(ComparableExpression.class, p2); return result; } @Override public Expression<?> visit(BooleanConstant node) { return node.getValue() ? Expressions.TRUE : Expressions.FALSE; } @Override public Expression<?> visit(DateConstant node) { LocalDate date = node.getValue(); Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("GMT")); instance.set(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth()); ConstantDateExpression constant = new ConstantDateExpression(new java.sql.Date(instance.getTimeInMillis())); return constant; } @Override public Expression<?> visit(DateTimeConstant node) { DateTime value = node.getValue(); DateTimeZone zone = value.getZone(); return new ConstantDateTimeExpression(new Timestamp(value.getMillis()), zone == DateTimeZone.UTC); } @Override public Expression<?> visit(DoubleConstant node) { return new ConstantNumberExpression(node.getValue()); } @Override public Expression<?> visit(DurationConstant node) { return new ConstantDurationExpression(node); } @Override public Expression<?> visit(IntervalConstant node) { Interval value = node.getValue(); return new TimeIntervalExpression( new ConstantDateTimeExpression(new Timestamp(value.getStartMillis()), true), new ConstantDateTimeExpression(new Timestamp(value.getEndMillis()), true)); } @Override public Expression<?> visit(IntegerConstant node) { ConstantNumberExpression constant = new ConstantNumberExpression(node.getValue()); return constant; } @Override public Expression<?> visit(LineStringConstant node) { Geometry geom = Wkt.fromWkt(node.getSource()); return new ConstantGeometryExpression(geom); } @Override public Expression<?> visit(PointConstant node) { Geometry geom = Wkt.fromWkt(node.getSource()); return new ConstantGeometryExpression(geom); } @Override public Expression<?> visit(PolygonConstant node) { Geometry geom = Wkt.fromWkt(node.getSource()); return new ConstantGeometryExpression(geom); } @Override public Expression<?> visit(StringConstant node) { ConstantStringExpression constant = new ConstantStringExpression(node.getValue()); return constant; } @Override public Expression<?> visit(TimeConstant node) { LocalTime time = node.getValue(); Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("GMT")); instance.set(1970, 1, 1, time.getHourOfDay(), time.getMinuteOfHour(), time.getSecondOfMinute()); ConstantTimeExpression constant = new ConstantTimeExpression(new java.sql.Time(instance.getTimeInMillis())); return constant; } @Override public Expression<?> visit(Before node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.before(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.after(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.before(d2); } @Override public Expression<?> visit(After node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.after(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.before(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.after(d2); } @Override public Expression<?> visit(Meets node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.meets(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.meets(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.eq(d2); } @Override public Expression<?> visit(During node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.contains(p1); } else { throw new IllegalArgumentException("Second parameter of 'during' has to be an interval."); } } @Override public Expression<?> visit(Overlaps node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.overlaps(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.overlaps(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.eq(d2); } @Override public Expression<?> visit(Starts node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.starts(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.starts(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.eq(d2); } @Override public Expression<?> visit(Finishes node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeIntervalExpression) { TimeIntervalExpression ti1 = (TimeIntervalExpression) p1; return ti1.finishes(p2); } if (p2 instanceof TimeIntervalExpression) { TimeIntervalExpression ti2 = (TimeIntervalExpression) p2; return ti2.finishes(p1); } DateTimeExpression d1 = getSingleOfType(DateTimeExpression.class, p1); DateTimeExpression d2 = getSingleOfType(DateTimeExpression.class, p2); return d1.eq(d2); } @Override public Expression<?> visit(Add node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.add(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.add(p1); } NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); NumberExpression n2 = getSingleOfType(NumberExpression.class, p2); return n1.add(n2); } @Override public Expression<?> visit(Divide node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.div(p2); } if (p2 instanceof TimeExpression) { throw new UnsupportedOperationException("Can not devide by a TimeExpression."); } NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); NumberExpression n2 = getSingleOfType(NumberExpression.class, p2); return n1.divide(n2); } @Override public Expression<?> visit(Modulo node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); NumberExpression n2 = getSingleOfType(NumberExpression.class, p2); return n1.castToNum(BigDecimal.class).mod(n2.castToNum(BigDecimal.class)); } @Override public Expression<?> visit(Multiply node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.mul(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.mul(p1); } NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); NumberExpression n2 = getSingleOfType(NumberExpression.class, p2); return n1.multiply(n2); } @Override public Expression<?> visit(Subtract node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.sub(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.subi(p1); } NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); NumberExpression n2 = getSingleOfType(NumberExpression.class, p2); return n1.subtract(n2); } @Override public Expression<?> visit(Equal node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.eq(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.eq(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).eq(pair[1]); } return ((ComparableExpression) pair[0]).eq(pair[1]); } @Override public Expression<?> visit(GreaterEqual node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.ge(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.le(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).goe(pair[1]); } return ((ComparableExpression) pair[0]).goe(pair[1]); } @Override public Expression<?> visit(GreaterThan node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.gt(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.lt(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).gt(pair[1]); } return ((ComparableExpression) pair[0]).gt(pair[1]); } @Override public Expression<?> visit(LessEqual node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.le(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.ge(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).loe(pair[1]); } return ((ComparableExpression) pair[0]).loe(pair[1]); } @Override public Expression<?> visit(LessThan node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.lt(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.gt(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).lt(pair[1]); } return ((ComparableExpression) pair[0]).lt(pair[1]); } @Override public Expression<?> visit(NotEqual node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); if (p1 instanceof TimeExpression) { TimeExpression ti1 = (TimeExpression) p1; return ti1.neq(p2); } if (p2 instanceof TimeExpression) { TimeExpression ti2 = (TimeExpression) p2; return ti2.neq(p1); } Expression<?>[] pair = findPair(p1, p2); if (pair[0] instanceof NumberExpression) { return ((NumberExpression) pair[0]).ne(pair[1]); } return ((ComparableExpression) pair[0]).ne(pair[1]); } @Override public Expression<?> visit(Date node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); DateExpression date = SQLExpressions.date(inExp); return date; } @Override public Expression<?> visit(Day node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.dayOfMonth(); } @Override public Expression<?> visit(FractionalSeconds node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.milliSecond(); } @Override public Expression<?> visit(Hour node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.hour(); } @Override public Expression<?> visit(MaxDateTime node) { return new ConstantDateTimeExpression(new Timestamp(PostgresPersistenceManager.DATETIME_MAX.getMillis()), true); } @Override public Expression<?> visit(MinDateTime node) { return new ConstantDateTimeExpression(new Timestamp(PostgresPersistenceManager.DATETIME_MIN.getMillis()), true); } @Override public Expression<?> visit(Minute node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.minute(); } @Override public Expression<?> visit(Month node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.month(); } @Override public Expression<?> visit(Now node) { return DateTimeExpression.currentTimestamp(); } @Override public Expression<?> visit(Second node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.second(); } @Override public Expression<?> visit(Time node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); if (inExp instanceof ConstantDateTimeExpression) { ConstantDateTimeExpression constant = (ConstantDateTimeExpression) inExp; if (!constant.isUtc()) { throw new IllegalArgumentException("Constants passed to the time() function have to be in UTC."); } } TimeTemplate<java.sql.Time> time = Expressions.timeTemplate(java.sql.Time.class, "pg_catalog.time({0})", inExp); return time; } @Override public Expression<?> visit(TotalOffsetMinutes node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); NumberExpression<Integer> offset = Expressions.numberTemplate(Integer.class, "timezone({0})", inExp) .divide(60); return offset; } @Override public Expression<?> visit(Year node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); DateTimeExpression inExp = getSingleOfType(DateTimeExpression.class, input); return inExp.year(); } @Override public Expression<?> visit(GeoDistance node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.distance(g2); } @Override public Expression<?> visit(GeoIntersects node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.intersects(g2); } @Override public Expression<?> visit(GeoLength node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); Expression<?> e1 = p1.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); return Expressions.numberTemplate(Double.class, "ST_Length({0})", g1); } @Override public Expression<?> visit(And node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); BooleanExpression b1 = getSingleOfType(BooleanExpression.class, p1); BooleanExpression b2 = getSingleOfType(BooleanExpression.class, p2); return b1.and(b2); } @Override public Expression<?> visit(Not node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); BooleanExpression b1 = getSingleOfType(BooleanExpression.class, p1); return b1.not(); } @Override public Expression<?> visit(Or node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); Expression<?> p2 = params.get(1).accept(this); BooleanExpression b1 = getSingleOfType(BooleanExpression.class, p1); BooleanExpression b2 = getSingleOfType(BooleanExpression.class, p2); return b1.or(b2); } @Override public Expression<?> visit(Ceiling node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); return n1.ceil(); } @Override public Expression<?> visit(Floor node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); return n1.floor(); } @Override public Expression<?> visit(Round node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); Expression<?> p1 = params.get(0).accept(this); NumberExpression n1 = getSingleOfType(NumberExpression.class, p1); return n1.round(); } @Override public Expression<?> visit(STContains node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.contains(g2); } @Override public Expression<?> visit(STCrosses node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.crosses(g2); } @Override public Expression<?> visit(STDisjoint node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.disjoint(g2); } @Override public Expression<?> visit(STEquals node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.eq(g2); } @Override public Expression<?> visit(STIntersects node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.intersects(g2); } @Override public Expression<?> visit(STOverlaps node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.overlaps(g2); } @Override public Expression<?> visit(STRelate node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p3 = node.getParameters().get(2); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); if (p3 instanceof StringConstant) { StringConstant e3 = (StringConstant) p3; String s3 = e3.getValue(); return g1.relate(g2, s3); } throw new IllegalArgumentException("ST_RELATE can only be used with a string constant as third parameter."); } @Override public Expression<?> visit(STTouches node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.touches(g2); } @Override public Expression<?> visit(STWithin node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); GeometryExpression g1 = getSingleOfType(GeometryExpression.class, e1); GeometryExpression g2 = getSingleOfType(GeometryExpression.class, e2); return g1.within(g2); } @Override public Expression<?> visit(Concat node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); StringExpression s2 = getSingleOfType(StringExpression.class, e2); return s1.concat(s2); } @Override public Expression<?> visit(EndsWith node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); StringExpression s2 = getSingleOfType(StringExpression.class, e2); return s1.endsWith(s2); } @Override public Expression<?> visit(IndexOf node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); StringExpression s2 = getSingleOfType(StringExpression.class, e2); return s1.indexOf(s2); } @Override public Expression<?> visit(Length node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); StringExpression inExp = getSingleOfType(StringExpression.class, input); return inExp.length(); } @Override public Expression<?> visit(StartsWith node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); StringExpression s2 = getSingleOfType(StringExpression.class, e2); return s1.startsWith(s2); } @Override public Expression<?> visit(Substring node) { List<de.fraunhofer.iosb.ilt.sta.query.expression.Expression> params = node.getParameters(); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); NumberExpression n2 = getSingleOfType(NumberExpression.class, e2); if (params.size() > 2) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p3 = node.getParameters().get(2); Expression<?> e3 = p3.accept(this); NumberExpression n3 = getSingleOfType(NumberExpression.class, e3); return s1.substring(n2, n3); } return s1.substring(n2); } @Override public Expression<?> visit(SubstringOf node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression p1 = node.getParameters().get(0); de.fraunhofer.iosb.ilt.sta.query.expression.Expression p2 = node.getParameters().get(1); Expression<?> e1 = p1.accept(this); Expression<?> e2 = p2.accept(this); StringExpression s1 = getSingleOfType(StringExpression.class, e1); StringExpression s2 = getSingleOfType(StringExpression.class, e2); return s2.contains(s1); } @Override public Expression<?> visit(ToLower node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); StringExpression inExp = getSingleOfType(StringExpression.class, input); return inExp.toLowerCase(); } @Override public Expression<?> visit(ToUpper node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); StringExpression inExp = getSingleOfType(StringExpression.class, input); return inExp.toUpperCase(); } @Override public Expression<?> visit(Trim node) { de.fraunhofer.iosb.ilt.sta.query.expression.Expression param = node.getParameters().get(0); Expression<?> input = param.accept(this); StringExpression inExp = getSingleOfType(StringExpression.class, input); return inExp.trim(); } }