HHH-14808 SpatialPredicates use value() method for literal expressions

This commit is contained in:
Karel Maesen 2021-09-20 21:02:46 +02:00
parent 9de428ac1a
commit b88596df6a
7 changed files with 193 additions and 67 deletions

View File

@ -20,6 +20,7 @@ import org.geolatte.geom.crs.CoordinateReferenceSystem;
/**
* {@link JTSFilterPredicate}, but for geolatte-geom.
*/
//TODO update class to H6
public class GeolatteFilterPredicate {
private final Expression<? extends Geometry> geometry;

View File

@ -10,6 +10,7 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.spatial.SpatialFunction;
import org.geolatte.geom.Geometry;
@ -28,6 +29,7 @@ import static org.hibernate.spatial.CommonSpatialFunction.ST_WITHIN;
*
* @author Daniel Shuy
*/
@SuppressWarnings("rawtypes")
public class GeolatteSpatialPredicates {
protected GeolatteSpatialPredicates() {
@ -68,7 +70,8 @@ public class GeolatteSpatialPredicates {
public static Predicate eq(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return eq( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return eq( cb, geometry1, cb.value( geometry2 )
);
}
@ -106,7 +109,8 @@ public class GeolatteSpatialPredicates {
public static Predicate within(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return within( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return within( cb, geometry1, cb.value( geometry2 )
);
}
@ -145,7 +149,8 @@ public class GeolatteSpatialPredicates {
public static Predicate contains(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return contains( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return contains( cb, geometry1, cb.value( geometry2 )
);
}
@ -184,8 +189,8 @@ public class GeolatteSpatialPredicates {
public static Predicate crosses(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return crosses( criteriaBuilder, geometry1,
criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return crosses( cb, geometry1, cb.value( geometry2 )
);
}
@ -223,7 +228,8 @@ public class GeolatteSpatialPredicates {
public static Predicate disjoint(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return disjoint( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return disjoint( cb, geometry1, cb.value( geometry2 ) );
}
/**
@ -260,7 +266,8 @@ public class GeolatteSpatialPredicates {
public static Predicate intersects(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return intersects( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return intersects( cb, geometry1, cb.value( geometry2 )
);
}
@ -298,7 +305,8 @@ public class GeolatteSpatialPredicates {
public static Predicate overlaps(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return overlaps( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return overlaps( cb, geometry1, cb.value( geometry2 )
);
}
@ -336,7 +344,8 @@ public class GeolatteSpatialPredicates {
public static Predicate touches(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return touches( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return touches( cb, geometry1, cb.value( geometry2 )
);
}
@ -349,8 +358,6 @@ public class GeolatteSpatialPredicates {
*
* @return bounding box overlap predicate
*
* @see GeolatteFilterPredicate
* @see JTSSpatialPredicates#filter(CriteriaBuilder, Expression, Expression)
*/
public static Predicate filter(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
@ -444,7 +451,8 @@ public class GeolatteSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2, Expression<Double> distance) {
return distanceWithin( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ), distance
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin( cb, geometry1, cb.value( geometry2 ), distance
);
}
@ -463,11 +471,12 @@ public class GeolatteSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2, double distance) {
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin(
criteriaBuilder,
cb,
geometry1,
criteriaBuilder.literal( geometry2 ),
criteriaBuilder.literal( distance )
cb.value( geometry2 ),
cb.value( distance )
);
}
@ -486,7 +495,8 @@ public class GeolatteSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Expression<? extends Geometry> geometry2, double distance) {
return distanceWithin( criteriaBuilder, geometry1, geometry2, criteriaBuilder.literal( distance )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin( cb, geometry1, geometry2, cb.value( distance )
);
}
@ -524,7 +534,8 @@ public class GeolatteSpatialPredicates {
public static Predicate havingSRID(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry,
int srid) {
return havingSRID( criteriaBuilder, geometry, criteriaBuilder.literal( srid ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return havingSRID( cb, geometry, cb.value( srid ) );
}
/**

View File

@ -10,6 +10,7 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.spatial.SpatialFunction;
import org.locationtech.jts.geom.Geometry;
@ -65,7 +66,8 @@ public class JTSSpatialPredicates {
public static Predicate eq(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return eq( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return eq( cb, geometry1, cb.value( geometry2 ) );
}
/**
@ -100,7 +102,8 @@ public class JTSSpatialPredicates {
public static Predicate within(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return within( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return within( cb, geometry1, cb.value( geometry2 ) );
}
/**
@ -135,7 +138,8 @@ public class JTSSpatialPredicates {
public static Predicate contains(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return contains( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return contains( cb, geometry1, cb.value( geometry2 ) );
}
/**
@ -170,8 +174,9 @@ public class JTSSpatialPredicates {
public static Predicate crosses(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return crosses( criteriaBuilder, geometry1,
criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return crosses( cb, geometry1,
cb.value( geometry2 )
);
}
@ -207,7 +212,8 @@ public class JTSSpatialPredicates {
public static Predicate disjoint(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return disjoint( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return disjoint( cb, geometry1, cb.value( geometry2 ) );
}
/**
@ -242,7 +248,8 @@ public class JTSSpatialPredicates {
public static Predicate intersects(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return intersects( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return intersects( cb, geometry1, cb.value( geometry2 )
);
}
@ -279,7 +286,8 @@ public class JTSSpatialPredicates {
public static Predicate overlaps(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return overlaps( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return overlaps( cb, geometry1, cb.value( geometry2 )
);
}
@ -309,13 +317,12 @@ public class JTSSpatialPredicates {
* @param geometry2 geometry value
*
* @return "spatially touches" predicate
*
* @return "spatially touches" predicate
*/
public static Predicate touches(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) {
return touches( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return touches( cb, geometry1, cb.value( geometry2 ) );
}
@ -416,7 +423,8 @@ public class JTSSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2, Expression<Double> distance) {
return distanceWithin( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ), distance );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin( cb, geometry1, cb.value( geometry2 ), distance );
}
/**
@ -434,11 +442,12 @@ public class JTSSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2, double distance) {
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin(
criteriaBuilder,
geometry1,
criteriaBuilder.literal( geometry2 ),
criteriaBuilder.literal( distance )
cb.value( geometry2 ),
cb.value( distance )
);
}
@ -457,7 +466,8 @@ public class JTSSpatialPredicates {
public static Predicate distanceWithin(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Expression<? extends Geometry> geometry2, double distance) {
return distanceWithin( criteriaBuilder, geometry1, geometry2, criteriaBuilder.literal( distance ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return distanceWithin( cb, geometry1, geometry2, cb.value( distance ) );
}
/**
@ -492,7 +502,8 @@ public class JTSSpatialPredicates {
public static Predicate havingSRID(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry,
int srid) {
return havingSRID( criteriaBuilder, geometry, criteriaBuilder.literal( srid ) );
HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) criteriaBuilder;
return havingSRID( criteriaBuilder, geometry, cb.value( srid ) );
}
/**

View File

@ -21,13 +21,11 @@ import org.hibernate.spatial.integration.Model;
import org.hibernate.spatial.predicate.GeolatteSpatialPredicates;
import org.hibernate.spatial.predicate.JTSSpatialPredicates;
import org.hibernate.spatial.testing.HSReflectionUtil;
import org.hibernate.spatial.testing.IsSupportedBySpatial;
import org.hibernate.spatial.testing.SpatialTestBase;
import org.hibernate.spatial.testing.datareader.TestSupport;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.Executable;
@ -43,9 +41,7 @@ import static org.geolatte.geom.crs.CoordinateReferenceSystems.WGS84;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SuppressWarnings({ "unchecked", "rawtypes" })
@RequiresDialectFeature(feature = IsSupportedBySpatial.class)
@SessionFactory
public class GeolatteSpatialPredicatesTest extends SpatialTestBase {
abstract public class SpatialPredicatesTest extends SpatialTestBase {
public final static TestSupport.TestDataPurpose PURPOSE = TestSupport.TestDataPurpose.SpatialFunctionsData;
@ -59,13 +55,15 @@ public class GeolatteSpatialPredicatesTest extends SpatialTestBase {
return PURPOSE;
}
abstract public Stream<PredicateRegexes.PredicateRegex> getTestRegexes();
@TestFactory
public Stream<DynamicTest> testFactory() {
return
predicateRegexes.all()
.flatMap( entry -> Stream.of(
new Args( entry.getKey(), entry.getValue(), Model.GLMODEL ),
new Args( entry.getKey(), entry.getValue(), Model.JTSMODEL )
getTestRegexes()
.flatMap( rp -> Stream.of(
new Args( rp.predicate, rp.regex, Model.GLMODEL ),
new Args( rp.predicate, rp.regex, Model.JTSMODEL )
) )
.map( args -> DynamicTest.dynamicTest(
displayName( args ),
@ -92,8 +90,11 @@ public class GeolatteSpatialPredicatesTest extends SpatialTestBase {
String stmt = inspector.getSqlQueries()
.get( 0 )
.toLowerCase( Locale.ROOT );
//TODO -- can't we use a (hamcrest) matcher here?
assertTrue( stmt.matches( regex ) );
assertTrue(
stmt.matches( regex ),
String.format( Locale.ROOT, "Statement didn't match regex:\n%s\n%s\n", stmt, regex )
);
} );
}
@ -151,4 +152,4 @@ class Args {
this.model = model;
}
}
}

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.spatial.integration.predicates;
import java.util.stream.Stream;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.spatial.testing.IsSupportedBySpatial;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.Setting;
@RequiresDialectFeature(feature = IsSupportedBySpatial.class)
@ServiceRegistry(settings = {
@Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "BIND")
})
@SessionFactory
public class SpatialPredicatesTestBindingMode extends SpatialPredicatesTest {
@Override
public Stream<PredicateRegexes.PredicateRegex> getTestRegexes() {
return super.predicateRegexes.bindingModeRegexes();
}
}

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.spatial.integration.predicates;
import java.util.stream.Stream;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.spatial.testing.IsSupportedBySpatial;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.Setting;
@RequiresDialectFeature(feature = IsSupportedBySpatial.class)
@ServiceRegistry(settings = {
@Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "INLINE")
})
@SessionFactory
public class SpatialPredicatesTestInlineMode extends SpatialPredicatesTest{
@Override
public Stream<PredicateRegexes.PredicateRegex> getTestRegexes() {
return super.predicateRegexes.inlineModeRegexes();
}
}

View File

@ -9,53 +9,93 @@ package org.hibernate.spatial.testing.dialects;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
public class PredicateRegexes {
protected final Map<String, String> regexes = new HashMap<>();
protected final Map<String, RegexPair> regexes = new HashMap<>();
// Note that we alias the function invocation so that
// we can map the return value to the required type
public PredicateRegexes() {
regexes.put(
add(
"overlaps",
"select .* from .* where st_overlaps\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_overlaps\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_overlaps\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
"intersects",
"select .* from .* where st_intersects\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
add(
"crosses",
"select .* from .* where st_crosses\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_crosses\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_crosses\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
add(
"contains",
"select .* from .* where st_contains\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_contains\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_contains\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
add(
"disjoint",
"select .* from .* where st_disjoint\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_disjoint\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_disjoint\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
add(
"touches",
"select .* from .* where st_touches\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_touches\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_touches\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
add(
"within",
"select .* from .* where st_within\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_within\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_within\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
regexes.put(
add(
"eq",
"select .* from .* where st_equals\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
"select .* from .* where st_equals\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=true.*",
"select .* from .* where st_equals\\(.*geom\\s*,.s*?\\)\\s*=\\s*?.*"
);
}
public Stream<Map.Entry<String, String>> all() {
return this.regexes.entrySet().stream();
public Stream<PredicateRegex> inlineModeRegexes() {
return extractForMode( entry -> new PredicateRegex( entry.getKey(), entry.getValue().inlineMode ) );
}
public Stream<PredicateRegex> bindingModeRegexes() {
return extractForMode( entry -> new PredicateRegex( entry.getKey(), entry.getValue().bindingMode ) );
}
private Stream<PredicateRegex> extractForMode(Function<Map.Entry<String, RegexPair>, PredicateRegex> mkPredRegex) {
return this.regexes
.entrySet()
.stream()
.map( mkPredRegex );
}
private void add(String predicate, String inlineRegex, String bindingRegex) {
regexes.put( predicate, new RegexPair( inlineRegex, bindingRegex ) );
}
static public class PredicateRegex {
public final String predicate;
public final String regex;
PredicateRegex(String predicate, String regex) {
this.predicate = predicate;
this.regex = regex;
}
}
static class RegexPair {
final String inlineMode;
final String bindingMode;
private RegexPair(String inline, String binding) {
inlineMode = inline;
bindingMode = binding;
}
}
}