Skip to content

Commit

Permalink
Merge pull request #677 from lat-lon/applyTemporalOperator-365
Browse files Browse the repository at this point in the history
Implemented Temporal Filter After, Before, During, TEquals for PostgreSQL
  • Loading branch information
copierrj authored Jul 5, 2019
2 parents adfda8a + 497b832 commit 83ec513
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import org.deegree.filter.sort.SortProperty;
import org.deegree.filter.spatial.BBOX;
import org.deegree.filter.spatial.SpatialOperator;
import org.deegree.filter.temporal.TemporalOperator;
import org.deegree.geometry.Geometry;
import org.deegree.sqldialect.SQLDialect;
import org.deegree.sqldialect.filter.expression.SQLArgument;
Expand Down Expand Up @@ -313,6 +314,9 @@ protected SQLExpression toProtoSQL( Operator op )
sql = toProtoSQL( (SpatialOperator) op );
break;
}
case TEMPORAL: {
sql = toProtoSQL( (TemporalOperator) op );
}
}
return sql;
}
Expand Down Expand Up @@ -487,7 +491,7 @@ protected SQLExpression toProtoSQL( ComparisonOperator op )
return sqlOper;
}

private void inferType( SQLExpression expr1, SQLExpression expr2 ) {
protected void inferType( SQLExpression expr1, SQLExpression expr2 ) {
PrimitiveType pt1 = expr1.getPrimitiveType();
PrimitiveType pt2 = expr2.getPrimitiveType();
if ( pt1 == null && pt2 != null ) {
Expand All @@ -501,7 +505,7 @@ private void inferType( SQLExpression expr1, SQLExpression expr2 ) {
}
}

private void inferType( SQLExpression expr1, SQLExpression expr2, SQLExpression expr3 ) {
protected void inferType( SQLExpression expr1, SQLExpression expr2, SQLExpression expr3 ) {
PrimitiveType pt1 = expr1.getPrimitiveType();
PrimitiveType pt2 = expr2.getPrimitiveType();
PrimitiveType pt3 = expr3.getPrimitiveType();
Expand Down Expand Up @@ -537,6 +541,10 @@ private PropertyIsLike buildIsLike( Expression propName, Expression literal, boo
matchCase, null );
}

protected void addExpression( SQLOperationBuilder builder, SQLExpression expr ) {
addExpression( builder, expr, true );
}

protected void addExpression( SQLOperationBuilder builder, SQLExpression expr, Boolean matchCase ) {
if ( matchCase == null || matchCase ) {
builder.add( expr );
Expand Down Expand Up @@ -658,6 +666,23 @@ protected SQLOperation toProtoSQL( LogicalOperator op )
protected abstract SQLOperation toProtoSQL( SpatialOperator op )
throws UnmappableException, FilterEvaluationException;

/**
* Translates the given {@link TemporalOperator} into an {@link SQLOperation}.
*
* @param op
* temporal operator to be translated, must not be <code>null</code>
* @return corresponding SQL expression, may be <code>null</code>
* @throws UnmappableException
* if translation is not possible (usually due to unmappable property names)
* @throws FilterEvaluationException
* if the filter contains invalid {@link ValueReference}s
*/
protected SQLOperation toProtoSQL( TemporalOperator op )
throws UnmappableException, FilterEvaluationException {
LOG.warn( "Mapping of temporal operators to SQL is not implemented (and probably not possible)." );
return null;
}

/**
* Translates the given {@link Expression} into an {@link SQLExpression}.
*
Expand Down Expand Up @@ -837,7 +862,8 @@ protected SQLExpression toProtoSQL( Literal<?> literal )
throw new UnmappableException( "Only primitive valued literals are currently supported." );
}
}
PrimitiveParticleConverter converter = new DefaultPrimitiveConverter( new PrimitiveType( STRING ), null, false );
PrimitiveParticleConverter converter = new DefaultPrimitiveConverter( new PrimitiveType( STRING ), null,
false );
return new SQLArgument( null, converter );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@
package org.deegree.sqldialect.postgis;

import static java.sql.Types.BOOLEAN;
import static org.deegree.commons.tom.primitive.BaseType.DATE_TIME;
import static org.deegree.commons.tom.primitive.BaseType.DECIMAL;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.deegree.commons.tom.TypedObjectNode;
import org.deegree.commons.tom.datetime.ISO8601Converter;
import org.deegree.commons.tom.primitive.PrimitiveType;
import org.deegree.commons.tom.primitive.PrimitiveValue;
import org.deegree.commons.tom.sql.DefaultPrimitiveConverter;
Expand All @@ -68,6 +71,7 @@
import org.deegree.filter.spatial.SpatialOperator;
import org.deegree.filter.spatial.Touches;
import org.deegree.filter.spatial.Within;
import org.deegree.filter.temporal.TemporalOperator;
import org.deegree.geometry.Geometry;
import org.deegree.sqldialect.filter.AbstractWhereBuilder;
import org.deegree.sqldialect.filter.PropertyNameMapper;
Expand All @@ -77,6 +81,10 @@
import org.deegree.sqldialect.filter.expression.SQLOperation;
import org.deegree.sqldialect.filter.expression.SQLOperationBuilder;
import org.deegree.sqldialect.filter.islike.IsLikeString;
import org.deegree.time.position.IndeterminateValue;
import org.deegree.time.position.TimePosition;
import org.deegree.time.primitive.GenericTimeInstant;
import org.deegree.time.primitive.GenericTimePeriod;

/**
* {@link AbstractWhereBuilder} implementation for PostGIS databases.
Expand Down Expand Up @@ -113,7 +121,7 @@ public class PostGISWhereBuilder extends AbstractWhereBuilder {
*/
public PostGISWhereBuilder( PostGISDialect dialect, PropertyNameMapper mapper, OperatorFilter filter,
SortProperty[] sortCrit, boolean allowPartialMappings, boolean useLegacyPredicates )
throws FilterEvaluationException, UnmappableException {
throws FilterEvaluationException, UnmappableException {
super( dialect, mapper, filter, sortCrit );
this.useLegacyPredicates = useLegacyPredicates;
build( allowPartialMappings );
Expand Down Expand Up @@ -157,8 +165,7 @@ protected String getStringValueFromFunction( Expression pattern )
appendParamsFromFunction( function, params );
TypedObjectNode value = evaluateFunction( function, params );
if ( !( value instanceof PrimitiveValue ) ) {
throw new UnsupportedOperationException(
"SQL IsLike request with a function evaluating to a non-primitive value is not supported!" );
throw new UnsupportedOperationException( "SQL IsLike request with a function evaluating to a non-primitive value is not supported!" );
}
String valueAsString = ( (PrimitiveValue) value ).getAsText();
return valueAsString;
Expand Down Expand Up @@ -385,6 +392,96 @@ protected SQLOperation toProtoSQL( SpatialOperator op )
return builder.toOperation();
}

protected SQLOperation toProtoSQL( TemporalOperator op )
throws UnmappableException, FilterEvaluationException {
SQLOperation sql = null;
switch ( op.getSubType() ) {
case AFTER: {
SQLExpression first = toProtoSQL( op.getParameter1() );
Expression parameter2 = op.getParameter2();
SQLExpression second;
if ( isTimeInstant( parameter2 ) ) {
TimePosition timePosition = ( (GenericTimeInstant) ( (Literal<?>) parameter2 ).getValue() ).getPosition();
second = createDateExpression( timePosition );
} else if ( isTimePeriod( parameter2 ) ) {
TimePosition end = ( (GenericTimePeriod) ( (Literal<?>) parameter2 ).getValue() ).getEndPosition();
second = createDateExpression( end );
} else {
second = toProtoSQL( parameter2 );
}
inferType( first, second );
sql = createSqlAfter( first, second );
break;
}
case BEFORE: {
SQLExpression first = toProtoSQL( op.getParameter1() );
Expression parameter2 = op.getParameter2();
SQLExpression second;
if ( isTimeInstant( parameter2 ) ) {
TimePosition timePosition = ( (GenericTimeInstant) ( (Literal<?>) parameter2 ).getValue() ).getPosition();
second = createDateExpression( timePosition );
} else if ( isTimePeriod( parameter2 ) ) {
TimePosition begin = ( (GenericTimePeriod) ( (Literal<?>) parameter2 ).getValue() ).getBeginPosition();
second = createDateExpression( begin );
} else {
second = toProtoSQL( parameter2 );
}
inferType( first, second );
sql = createSqlBefore( first, second );
break;
}
case TEQUALS: {
SQLExpression first = toProtoSQL( op.getParameter1() );
Expression parameter2 = op.getParameter2();
SQLExpression second;
if ( isTimeInstant( parameter2 ) ) {
TimePosition timePosition = ( (GenericTimeInstant) ( (Literal<?>) parameter2 ).getValue() ).getPosition();
second = createDateExpression( timePosition );
} else {
second = toProtoSQL( parameter2 );
}
inferType( first, second );
sql = createSqlEquals( first, second );
break;
}
case DURING: {
Expression parameter2 = op.getParameter2();
if ( isTimePeriod( parameter2 ) ) {
TimePosition begin = ( (GenericTimePeriod) ( (Literal<?>) parameter2 ).getValue() ).getBeginPosition();
TimePosition end = ( (GenericTimePeriod) ( (Literal<?>) parameter2 ).getValue() ).getEndPosition();
SQLExpression valueReference = toProtoSQL( op.getParameter1() );
SQLExpression beginExpr = createDateExpression( begin );
SQLExpression endExpr = createDateExpression( end );
sql = createSqlDuring( valueReference, beginExpr, endExpr );
}
break;
}
default:
sql = super.toProtoSQL( op );
}
return sql;
}

private SQLExpression createDateExpression( TimePosition timePosition ) {
if ( timePosition.getIndeterminatePosition() != null ) {
if ( timePosition.getIndeterminatePosition().equals( IndeterminateValue.NOW ) ) {
String encodedTemporal = ISO8601Converter.formatDateTime( new Date() );
TimePosition now = new TimePosition( null, null, null, encodedTemporal );
return createDateExpressionFromTimePosition( now );
} else {
return null;
}
}
return createDateExpressionFromTimePosition( timePosition );
}

private SQLExpression createDateExpressionFromTimePosition( TimePosition now ) {
PrimitiveValue value = new PrimitiveValue( now.getValue(), new PrimitiveType( DATE_TIME ) );
DefaultPrimitiveConverter converter = new DefaultPrimitiveConverter( new PrimitiveType( DATE_TIME ), null,
false );
return new SQLArgument( value, converter );
}

@Override
protected void addExpression( SQLOperationBuilder builder, SQLExpression expr, Boolean matchCase ) {
if ( matchCase == null || matchCase ) {
Expand All @@ -400,4 +497,79 @@ private SQLExpression toProtoSQL( Geometry geom, ICRS targetCRS, int srid )
throws FilterEvaluationException {
return new SQLArgument( geom, new PostGISGeometryConverter( null, targetCRS, "" + srid, useLegacyPredicates ) );
}

private SQLOperation createSqlDuring( SQLExpression valueReference, SQLExpression beginExpr,
SQLExpression endExpr ) {
if ( beginExpr == null && endExpr == null )
return null;
if ( beginExpr != null && endExpr == null ) {
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, valueReference );
builder.add( " >= " );
addExpression( builder, beginExpr );
builder.add( ")" );
return builder.toOperation();
}
if ( beginExpr == null && endExpr != null ) {
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, valueReference );
builder.add( " <= " );
addExpression( builder, endExpr );
builder.add( ")" );
return builder.toOperation();
}
inferType( valueReference, beginExpr, endExpr );
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, valueReference );
builder.add( " >= " );
addExpression( builder, beginExpr );
builder.add( " AND " );
addExpression( builder, valueReference );
builder.add( " <= " );
addExpression( builder, endExpr );
builder.add( ")" );
return builder.toOperation();
}

private SQLOperation createSqlEquals( SQLExpression first, SQLExpression second ) {
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, first );
builder.add( " = " );
addExpression( builder, second );
builder.add( ")" );
return builder.toOperation();
}

private SQLOperation createSqlBefore( SQLExpression first, SQLExpression second ) {
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, first );
builder.add( " < " );
addExpression( builder, second );
builder.add( ")" );
return builder.toOperation();
}

private SQLOperation createSqlAfter( SQLExpression first, SQLExpression second ) {
SQLOperationBuilder builder = new SQLOperationBuilder( BOOLEAN );
builder.add( "(" );
addExpression( builder, first );
builder.add( " > " );
addExpression( builder, second );
builder.add( ")" );
return builder.toOperation();
}

private boolean isTimePeriod( Expression parameter2 ) {
return parameter2 instanceof Literal && ( (Literal<?>) parameter2 ).getValue() instanceof GenericTimePeriod;
}

private boolean isTimeInstant( Expression parameter2 ) {
return parameter2 instanceof Literal && ( (Literal<?>) parameter2 ).getValue() instanceof GenericTimeInstant;
}

}

0 comments on commit 83ec513

Please sign in to comment.