HHH-14808 Basic SpatialPredicates

This commit is contained in:
Karel Maesen 2021-09-04 13:07:23 +02:00
parent 2bdd10389b
commit 5bae2d8196
17 changed files with 372 additions and 74 deletions

View File

View File

@ -13,7 +13,6 @@ package org.hibernate.spatial;
* @author Karel Maesen, Geovise BVBA * @author Karel Maesen, Geovise BVBA
* creation-date: 4/18/13 * creation-date: 4/18/13
*/ */
@Deprecated
public interface Spatial { public interface Spatial {
} }

View File

@ -13,12 +13,14 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.spatial.GeolatteGeometryJavaTypeDescriptor;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BasicBinder; import org.hibernate.type.descriptor.jdbc.BasicBinder;
import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.geolatte.geom.ByteBuffer; import org.geolatte.geom.ByteBuffer;
@ -29,6 +31,7 @@ import org.geolatte.geom.codec.WkbDecoder;
import org.geolatte.geom.codec.WkbEncoder; import org.geolatte.geom.codec.WkbEncoder;
import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.Wkt;
import org.geolatte.geom.codec.WktDecoder; import org.geolatte.geom.codec.WktDecoder;
import org.geolatte.geom.jts.JTS;
import org.postgresql.util.PGobject; import org.postgresql.util.PGobject;
/** /**
@ -46,6 +49,18 @@ public class PGGeometryTypeDescriptor implements JdbcTypeDescriptor {
// Type descriptor instance using EWKB v2 (postgis versions >= 2.2.2, see: https://trac.osgeo.org/postgis/ticket/3181) // Type descriptor instance using EWKB v2 (postgis versions >= 2.2.2, see: https://trac.osgeo.org/postgis/ticket/3181)
public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_2 ); public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_2 );
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
if ( javaTypeDescriptor instanceof GeolatteGeometryJavaTypeDescriptor ) {
return (value, dialect, wrapperOptions) -> "ST_GeomFromEWKT('" + value + "')";
}
return (value, dialect, wrapperOptions) -> "ST_GeomFromEWKT('" + jts2Gl( value ) + "')";
}
private <T> Geometry<?> jts2Gl(T value) {
return JTS.from( (org.locationtech.jts.geom.Geometry) value );
}
private PGGeometryTypeDescriptor(Wkb.Dialect dialect) { private PGGeometryTypeDescriptor(Wkb.Dialect dialect) {
wkbDialect = dialect; wkbDialect = dialect;
} }
@ -78,14 +93,13 @@ public class PGGeometryTypeDescriptor implements JdbcTypeDescriptor {
} }
@Override @Override
public int getJdbcTypeCode() { public int getJdbcTypeCode() {
return Types.OTHER; return Types.OTHER;
} }
@Override @Override
public int getDefaultSqlTypeCode(){ public int getDefaultSqlTypeCode() {
return 5432; return 5432;
} }

View File

@ -10,11 +10,20 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression; import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.spatial.SpatialFunction; import org.hibernate.spatial.SpatialFunction;
import org.geolatte.geom.Envelope;
import org.geolatte.geom.Geometry; import org.geolatte.geom.Geometry;
import static org.hibernate.spatial.CommonSpatialFunction.ST_CONTAINS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_CROSSES;
import static org.hibernate.spatial.CommonSpatialFunction.ST_DISJOINT;
import static org.hibernate.spatial.CommonSpatialFunction.ST_EQUALS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_INTERSECTS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_OVERLAPS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_TOUCHES;
import static org.hibernate.spatial.CommonSpatialFunction.ST_WITHIN;
/** /**
* {@link JTSSpatialPredicates}, but for geolatte-geom. * {@link JTSSpatialPredicates}, but for geolatte-geom.
* *
@ -41,7 +50,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.equals.toString(), boolean.class, criteriaBuilder.function( ST_EQUALS.name(), boolean.class,
geometry1, geometry2 geometry1, geometry2
) )
); );
@ -82,9 +91,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.within.toString(), boolean.class, criteriaBuilder.function( ST_WITHIN.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -102,8 +109,7 @@ public class GeolatteSpatialPredicates {
public static Predicate within( public static Predicate within(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return within( criteriaBuilder, geometry1, return within( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }
@ -123,7 +129,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.contains.toString(), boolean.class, criteriaBuilder.function( ST_CONTAINS.name(), boolean.class,
geometry1, geometry2 geometry1, geometry2
) )
); );
@ -164,7 +170,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.crosses.toString(), boolean.class, criteriaBuilder.function( ST_CROSSES.name(), boolean.class,
geometry1, geometry2 geometry1, geometry2
) )
); );
@ -205,9 +211,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.disjoint.toString(), boolean.class, criteriaBuilder.function( ST_DISJOINT.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -246,9 +250,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.intersects.toString(), boolean.class, criteriaBuilder.function( ST_INTERSECTS.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -266,8 +268,7 @@ public class GeolatteSpatialPredicates {
public static Predicate intersects( public static Predicate intersects(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return intersects( criteriaBuilder, geometry1, return intersects( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }
@ -287,9 +288,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.overlaps.toString(), boolean.class, criteriaBuilder.function( ST_OVERLAPS.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -307,8 +306,7 @@ public class GeolatteSpatialPredicates {
public static Predicate overlaps( public static Predicate overlaps(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return overlaps( criteriaBuilder, geometry1, return overlaps( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }
@ -328,9 +326,7 @@ public class GeolatteSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.touches.toString(), boolean.class, criteriaBuilder.function( ST_TOUCHES.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -348,8 +344,7 @@ public class GeolatteSpatialPredicates {
public static Predicate touches( public static Predicate touches(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return touches( criteriaBuilder, geometry1, return touches( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }

View File

@ -10,12 +10,20 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression; import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.spatial.SpatialFunction; import org.hibernate.spatial.SpatialFunction;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
import static org.hibernate.spatial.CommonSpatialFunction.ST_CONTAINS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_CROSSES;
import static org.hibernate.spatial.CommonSpatialFunction.ST_DISJOINT;
import static org.hibernate.spatial.CommonSpatialFunction.ST_EQUALS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_INTERSECTS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_OVERLAPS;
import static org.hibernate.spatial.CommonSpatialFunction.ST_TOUCHES;
import static org.hibernate.spatial.CommonSpatialFunction.ST_WITHIN;
/** /**
* A factory for spatial JPA Criteria API {@link Predicate}s. * A factory for spatial JPA Criteria API {@link Predicate}s.
* *
@ -40,7 +48,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.equals.toString(), boolean.class, geometry1, geometry2 ) criteriaBuilder.function( ST_EQUALS.name(), boolean.class, geometry1, geometry2 )
); );
} }
@ -75,7 +83,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.within.toString(), boolean.class, geometry1, geometry2 ) criteriaBuilder.function( ST_WITHIN.name(), boolean.class, geometry1, geometry2 )
); );
} }
@ -110,9 +118,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.contains.toString(), boolean.class, criteriaBuilder.function( ST_CONTAINS.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -149,7 +155,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.crosses.toString(), boolean.class, criteriaBuilder.function( ST_CROSSES.name(), boolean.class,
geometry1, geometry2 geometry1, geometry2
) )
); );
@ -188,9 +194,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.disjoint.toString(), boolean.class, criteriaBuilder.function( ST_DISJOINT.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -227,9 +231,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.intersects.toString(), boolean.class, criteriaBuilder.function( ST_INTERSECTS.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -247,8 +249,7 @@ public class JTSSpatialPredicates {
public static Predicate intersects( public static Predicate intersects(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return intersects( criteriaBuilder, geometry1, return intersects( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }
@ -266,8 +267,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.overlaps.toString(), boolean.class, criteriaBuilder.function( ST_OVERLAPS.name(), boolean.class, geometry1, geometry2
geometry1, geometry2
) )
); );
} }
@ -286,8 +286,7 @@ public class JTSSpatialPredicates {
public static Predicate overlaps( public static Predicate overlaps(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return overlaps( criteriaBuilder, geometry1, return overlaps( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 )
criteriaBuilder.literal( geometry2 )
); );
} }
@ -305,9 +304,7 @@ public class JTSSpatialPredicates {
Expression<? extends Geometry> geometry2) { Expression<? extends Geometry> geometry2) {
return booleanExpressionToPredicate( return booleanExpressionToPredicate(
criteriaBuilder, criteriaBuilder,
criteriaBuilder.function( SpatialFunction.touches.toString(), boolean.class, criteriaBuilder.function( ST_TOUCHES.name(), boolean.class, geometry1, geometry2 )
geometry1, geometry2
)
); );
} }
@ -325,11 +322,11 @@ public class JTSSpatialPredicates {
public static Predicate touches( public static Predicate touches(
CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1, CriteriaBuilder criteriaBuilder, Expression<? extends Geometry> geometry1,
Geometry geometry2) { Geometry geometry2) {
return touches( criteriaBuilder, geometry1, return touches( criteriaBuilder, geometry1, criteriaBuilder.literal( geometry2 ) );
criteriaBuilder.literal( geometry2 )
);
} }
// /** // /**
// * Create a predicate for testing the arguments for bounding box overlap constraint. // * Create a predicate for testing the arguments for bounding box overlap constraint.
// * // *

View File

@ -5,7 +5,14 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.spatial.integration.functions; /*
* 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;
import java.util.function.Function; import java.util.function.Function;
@ -21,36 +28,45 @@ import org.geolatte.geom.jts.JTS;
* T * T
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
enum Model { public enum Model {
JTSMODEL( JTSMODEL(
JtsGeomEntity.class, JtsGeomEntity.class,
JTS::to JTS::to,
org.locationtech.jts.geom.Geometry.class
), ),
GLMODEL( GLMODEL(
GeomEntity.class, GeomEntity.class,
geom -> geom geom -> geom,
Geometry.class
); );
/** /**
* Test Entity class * Test Entity class
*/ */
final Class<?> entityClass; public final Class<?> entityClass;
/** /**
* How to translate from Geolatte Geometry class to the object class * How to translate from Geolatte Geometry to the geometry type
* expected by the entity geom property * expected by the entity in this model
*/ */
final Function<Geometry, Object> from; public final Function<Geometry, Object> from;
/**
* The geometry type in this model
*/
public final Class<?> geometryClass;
Model( Model(
Class<?> entityClass, Class<?> entityClass,
Function<Geometry, Object> from Function<Geometry, Object> from,
Class<?> geometryClass
) { ) {
this.entityClass = entityClass; this.entityClass = entityClass;
this.from = from; this.from = from;
this.geometryClass = geometryClass;
} }
} }

View File

@ -18,6 +18,7 @@ import org.hibernate.spatial.testing.datareader.TestData;
import org.hibernate.spatial.testing.datareader.TestDataElement; import org.hibernate.spatial.testing.datareader.TestDataElement;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
import org.hibernate.spatial.testing.dialects.NativeSQLTemplates; import org.hibernate.spatial.testing.dialects.NativeSQLTemplates;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.hibernate.spatial.testing.domain.GeomEntityLike; import org.hibernate.spatial.testing.domain.GeomEntityLike;
import org.hibernate.testing.orm.junit.DialectContext; import org.hibernate.testing.orm.junit.DialectContext;
@ -29,6 +30,7 @@ import static org.hibernate.spatial.testing.datareader.TestSupport.TestDataPurpo
public class SpatialTestDataProvider { public class SpatialTestDataProvider {
protected final static String JTS = "jts"; protected final static String JTS = "jts";
protected final NativeSQLTemplates templates; protected final NativeSQLTemplates templates;
protected final PredicateRegexes predicateRegexes;
protected final Map<CommonSpatialFunction, String> hqlOverrides; protected final Map<CommonSpatialFunction, String> hqlOverrides;
private final TestData funcTestData; private final TestData funcTestData;
protected TestData testData; protected TestData testData;
@ -38,6 +40,7 @@ public class SpatialTestDataProvider {
try { try {
TestSupport support = TestSupportFactories.instance().getTestSupportFactory( DialectContext.getDialect() ); TestSupport support = TestSupportFactories.instance().getTestSupportFactory( DialectContext.getDialect() );
templates = support.templates(); templates = support.templates();
predicateRegexes = support.predicateRegexes();
hqlOverrides = support.hqlOverrides(); hqlOverrides = support.hqlOverrides();
codec = support.codec(); codec = support.codec();
testData = support.createTestData( StoreRetrieveData ); testData = support.createTestData( StoreRetrieveData );

View File

@ -16,8 +16,10 @@ package org.hibernate.spatial.integration.functions;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.hibernate.spatial.integration.Model;
import org.hibernate.spatial.testing.IsSupportedBySpatial; import org.hibernate.spatial.testing.IsSupportedBySpatial;
import org.hibernate.spatial.testing.SpatialTestBase; import org.hibernate.spatial.testing.SpatialTestBase;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
@ -42,14 +44,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
* </ul> * </ul>
* </p> * </p>
*/ */
@SuppressWarnings("ALL")
@SuppressWarnings("rawtypes")
@RequiresDialectFeature(feature = IsSupportedBySpatial.class) @RequiresDialectFeature(feature = IsSupportedBySpatial.class)
@SessionFactory @SessionFactory
public class CommonFunctionTests extends SpatialTestBase { public class CommonFunctionTests extends SpatialTestBase {
public final static TestSupport.TestDataPurpose PURPOSE = TestSupport.TestDataPurpose.SpatialFunctionsData; public final static TestSupport.TestDataPurpose PURPOSE = TestSupport.TestDataPurpose.SpatialFunctionsData;
List received; List received;
List expected; List expected;
@ -58,7 +60,6 @@ public class CommonFunctionTests extends SpatialTestBase {
return PURPOSE; return PURPOSE;
} }
@TestFactory @TestFactory
public Stream<DynamicTest> testFunction() { public Stream<DynamicTest> testFunction() {
@ -73,13 +74,12 @@ public class CommonFunctionTests extends SpatialTestBase {
} }
protected Stream<DynamicTest> buildTests(FunctionTestTemplate template) { protected Stream<DynamicTest> buildTests(FunctionTestTemplate template) {
return Stream.of( return Stream.of(
template.getFunctionName(), template.getFunctionName(),
template.getAltFunctionName() template.getAltFunctionName()
) )
.filter( s -> s != null ) .filter( Objects::nonNull )
.map( fn -> DynamicTest.dynamicTest( .map( fn -> DynamicTest.dynamicTest(
displayName( template, fn ), executableTest( template, fn ) displayName( template, fn ), executableTest( template, fn )
) ); ) );
@ -94,12 +94,11 @@ public class CommonFunctionTests extends SpatialTestBase {
); );
} }
protected <T> Executable executableTest(FunctionTestTemplate template, String fnName) { protected Executable executableTest(FunctionTestTemplate template, String fnName) {
Executable testF = () -> { return () -> {
expected = template.executeNativeQuery( scope ); expected = template.executeNativeQuery( scope );
received = template.executeHQL( scope, fnName ); received = template.executeHQL( scope, fnName );
assertEquals( expected, received ); assertEquals( expected, received );
}; };
return testF;
} }
} }

View File

@ -25,6 +25,7 @@ import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hibernate.spatial.CommonSpatialFunction; import org.hibernate.spatial.CommonSpatialFunction;
import org.hibernate.spatial.GeomCodec; import org.hibernate.spatial.GeomCodec;
import org.hibernate.spatial.integration.Model;
import org.hibernate.spatial.testing.HQLTemplate; import org.hibernate.spatial.testing.HQLTemplate;
import org.hibernate.spatial.testing.NativeSQLTemplate; import org.hibernate.spatial.testing.NativeSQLTemplate;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;

View File

@ -0,0 +1,154 @@
/*
* 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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Root;
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.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;
import org.junit.platform.commons.JUnitException;
import org.geolatte.geom.G2D;
import org.geolatte.geom.Polygon;
import static org.geolatte.geom.builder.DSL.g;
import static org.geolatte.geom.builder.DSL.polygon;
import static org.geolatte.geom.builder.DSL.ring;
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 {
public final static TestSupport.TestDataPurpose PURPOSE = TestSupport.TestDataPurpose.SpatialFunctionsData;
static final Polygon<G2D> filter = polygon(
WGS84,
ring( g( 0, 0 ), g( 0, 10 ), g( 10, 10 ), g( 10, 0 ), g( 0, 0 ) )
);
@Override
public TestSupport.TestDataPurpose purpose() {
return PURPOSE;
}
@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 )
) )
.map( args -> DynamicTest.dynamicTest(
displayName( args ),
testPredicate(
args.method,
args.regex,
args.model
)
) );
}
@SuppressWarnings("rawtypes")
public Executable testPredicate(final String key, final String regex, Model model) {
return () -> scope.inSession( session -> {
SQLStatementInspector inspector = SQLStatementInspector.extractFromSession( session );
inspector.clear();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery query = getCriteriaQuery(
key,
criteriaBuilder,
model
);
List resultList = session.createQuery( query ).getResultList();
String stmt = inspector.getSqlQueries()
.get( 0 )
.toLowerCase( Locale.ROOT );
//TODO -- can't we use a (hamcrest) matcher here?
assertTrue( stmt.matches( regex ) );
} );
}
private CriteriaQuery getCriteriaQuery(
String key,
CriteriaBuilder criteriaBuilder, Model model) {
CriteriaQuery query = criteriaBuilder.createQuery( model.entityClass );
Root root = query.from( model.entityClass );
Method method = predicateMethod( key, model );
finalizeQuery( criteriaBuilder, model, query, root, method );
return query;
}
private void finalizeQuery(
CriteriaBuilder criteriaBuilder,
Model model,
CriteriaQuery query,
Root root,
Method method) {
try {
query.select( root )
.where( (Expression<Boolean>) method.invoke(
null, criteriaBuilder, root.get( "geom" ), model.from.apply( filter ) ) );
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new JUnitException( "Failure to invoke Geometry Predicate", e );
}
}
@SuppressWarnings("rawtypes")
private Method predicateMethod(String key, Model model) {
Class predicateFactoryClass = model == Model.JTSMODEL ?
JTSSpatialPredicates.class :
GeolatteSpatialPredicates.class;
return HSReflectionUtil.getStaticMethod(
predicateFactoryClass,
key,
CriteriaBuilder.class, Expression.class, model.geometryClass
);
}
private String displayName(Args args) {
return String.format( "Predicate %s on %s", args.method, args.model.entityClass.getSimpleName() );
}
}
class Args {
final String method;
final String regex;
final Model model;
public Args(String method, String regex, Model model) {
this.method = method;
this.regex = regex;
this.model = model;
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.testing;
import java.lang.reflect.Method;
//TODO -- fold this into ReflectionUtil
public class HSReflectionUtil {
/**
* Get target method
*
* @param target target class
* @param methodName method name
* @param parameterTypes method parameter types
*
* @return return value
*/
public static Method getStaticMethod(Class target, String methodName, Class... parameterTypes) {
try {
return target.getMethod( methodName, parameterTypes );
}
catch (NoSuchMethodException e) {
throw new IllegalArgumentException( e );
}
}
}

View File

@ -13,6 +13,13 @@ import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.testing.orm.junit.DialectFeatureCheck; import org.hibernate.testing.orm.junit.DialectFeatureCheck;
/**
* Checks if the Dialect is actually supported by Spatial
*
* Note: the tests in this module need to be explicitly enabled in the gradle build config. So this check is
* maybe no longer needed.
*
*/
public class IsSupportedBySpatial implements DialectFeatureCheck { public class IsSupportedBySpatial implements DialectFeatureCheck {
@Override @Override
public boolean apply(Dialect dialect) { public boolean apply(Dialect dialect) {

View File

@ -22,6 +22,7 @@ import org.hibernate.spatial.CommonSpatialFunction;
import org.hibernate.spatial.GeomCodec; import org.hibernate.spatial.GeomCodec;
import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.AbstractExpectationsFactory;
import org.hibernate.spatial.testing.dialects.NativeSQLTemplates; import org.hibernate.spatial.testing.dialects.NativeSQLTemplates;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
/** /**
@ -36,6 +37,11 @@ public abstract class TestSupport {
return null; return null;
} }
//TODO -- make this abstract
public PredicateRegexes predicateRegexes() {
return null;
}
public Map<CommonSpatialFunction, String> hqlOverrides() { public Map<CommonSpatialFunction, String> hqlOverrides() {
return new HashMap<>(); return new HashMap<>();
} }

View File

@ -0,0 +1,61 @@
/*
* 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.testing.dialects;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class PredicateRegexes {
protected final Map<String, String> 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(
"overlaps",
"select .* from .* where st_overlaps\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"intersects",
"select .* from .* where st_intersects\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"crosses",
"select .* from .* where st_crosses\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"contains",
"select .* from .* where st_contains\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"disjoint",
"select .* from .* where st_disjoint\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"touches",
"select .* from .* where st_touches\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"within",
"select .* from .* where st_within\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
regexes.put(
"eq",
"select .* from .* where st_equals\\(.*geom\\s*,.*st_geomfromewkt\\(.*\\)\\s*=\\?.*"
);
}
public Stream<Map.Entry<String, String>> all() {
return this.regexes.entrySet().stream();
}
}

View File

@ -13,6 +13,7 @@ import org.hibernate.spatial.testing.AbstractExpectationsFactory;
import org.hibernate.spatial.testing.datareader.TestData; import org.hibernate.spatial.testing.datareader.TestData;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
import org.hibernate.spatial.testing.dialects.NativeSQLTemplates; import org.hibernate.spatial.testing.dialects.NativeSQLTemplates;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.hibernate.spatial.testing.dialects.postgis.PostgisNativeSQLTemplates; import org.hibernate.spatial.testing.dialects.postgis.PostgisNativeSQLTemplates;
import org.geolatte.geom.Geometry; import org.geolatte.geom.Geometry;
@ -25,6 +26,11 @@ public class CockroachDBTestSupport extends TestSupport {
return new PostgisNativeSQLTemplates(); return new PostgisNativeSQLTemplates();
} }
@Override
public PredicateRegexes predicateRegexes() {
return new CrPredicateRegexes();
}
@Override @Override
public TestData createTestData(TestDataPurpose purpose) { public TestData createTestData(TestDataPurpose purpose) {
switch ( purpose ) { switch ( purpose ) {
@ -50,3 +56,5 @@ public class CockroachDBTestSupport extends TestSupport {
} }
} }
class CrPredicateRegexes extends PredicateRegexes{ }

View File

@ -18,6 +18,7 @@ import org.hibernate.spatial.testing.AbstractExpectationsFactory;
import org.hibernate.spatial.testing.datareader.TestData; import org.hibernate.spatial.testing.datareader.TestData;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
import org.hibernate.spatial.testing.dialects.NativeSQLTemplates; import org.hibernate.spatial.testing.dialects.NativeSQLTemplates;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.geolatte.geom.Geometry; import org.geolatte.geom.Geometry;
import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.Wkt;
@ -35,6 +36,9 @@ public class PostgisTestSupport extends TestSupport {
return new PostgisNativeSQLTemplates(); return new PostgisNativeSQLTemplates();
} }
@Override
public PredicateRegexes predicateRegexes(){ return new PostgisPredicateRegexes();}
//TODO put this in its own class (analogous to NativeSQLTemplates) //TODO put this in its own class (analogous to NativeSQLTemplates)
@Override @Override
public Map<CommonSpatialFunction, String> hqlOverrides() { public Map<CommonSpatialFunction, String> hqlOverrides() {
@ -68,3 +72,5 @@ public class PostgisTestSupport extends TestSupport {
} }
} }
class PostgisPredicateRegexes extends PredicateRegexes { }

View File

@ -34,7 +34,6 @@ hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFa
#hibernate.connection.username hibernate_orm_test #hibernate.connection.username hibernate_orm_test
#hibernate.connection.password hibernate_orm_test #hibernate.connection.password hibernate_orm_test
>>>>>>> 5aae4945cb (Update CockroachDB support for 6)
## GeoDb (H2 spatial extension) ## GeoDb (H2 spatial extension)
## ##
#hibernate.dialect org.hibernate.spatial.dialect.h2geodb.GeoDBDialect #hibernate.dialect org.hibernate.spatial.dialect.h2geodb.GeoDBDialect