This is an automated email from the ASF dual-hosted git repository. amanin pushed a commit to branch refactor/sql-store in repository https://gitbox.apache.org/repos/asf/sis.git
commit 5d783cef6c5121a217e445dbb40bba14704117d7 Author: Alexis Manin <[email protected]> AuthorDate: Mon Nov 4 18:08:52 2019 +0100 refactor(SQLStore): prepare module for dialect specific syntax. --- .../apache/sis/internal/feature/Geometries.java | 14 ++- .../sis/internal/sql/feature/ANSIMapping.java | 105 ++++++++++++++++++++ .../apache/sis/internal/sql/feature/Analyzer.java | 2 +- .../sis/internal/sql/feature/ColumnAdapter.java | 35 +++++++ .../sis/internal/sql/feature/DialectMapping.java | 12 +++ .../sis/internal/sql/feature/FeatureAdapter.java | 2 - .../internal/sql/feature/PostGISInterpreter.java | 19 ++++ .../sis/internal/sql/feature/PostGISMapping.java | 29 ++++++ .../sis/internal/sql/feature/QueryFeatureSet.java | 5 +- .../sis/internal/sql/feature/SQLQueryAdapter.java | 25 ++++- .../sis/internal/sql/feature/SpatialFunctions.java | 107 +++------------------ 11 files changed, 256 insertions(+), 99 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java index f4c6507..3f78d61 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java @@ -310,6 +310,16 @@ public abstract class Geometries<G> { public abstract G createPolyline(int dimension, Vector... coordinates); /** + * Force conversion of input geometry to a polygon. If input is a closed line (e.g: Linear ring), it should be + * converted to polygon object. Otherwise, an error should be thrown. + * + * @param polyline The polyline to see as a polygon. + * @return A polygon object. + * @throws IllegalArgumentException If given object is not a closed line (linear ring). + */ + public abstract G toPolygon(G polyline) throws IllegalArgumentException; + + /** * Merges a sequence of polyline instances if the first instance is an implementation of this library. * * @param first the first instance to merge. @@ -444,7 +454,7 @@ public abstract class Geometries<G> { * it, because in an orthonormal space, I don't see any case where it could be useful. However, in case it * have to be added, we can do it here by amending created ring(s). */ - return mainRect; + return toPolygon(mainRect); } /** @@ -480,7 +490,7 @@ public abstract class Geometries<G> { public abstract double[] getPoints(Object geometry); - abstract Object createMultiPolygonImpl(final Object... polygonsOrLinearRings); + abstract G createMultiPolygonImpl(final Object... polygonsOrLinearRings); public static Object createMultiPolygon(final Object... polygonsOrLinearRings) { return findStrategy(g -> g.createMultiPolygonImpl(polygonsOrLinearRings)); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ANSIMapping.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ANSIMapping.java new file mode 100644 index 0000000..f430e40 --- /dev/null +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ANSIMapping.java @@ -0,0 +1,105 @@ +package org.apache.sis.internal.sql.feature; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; +import java.util.Optional; + +import org.apache.sis.internal.metadata.sql.Dialect; + +public class ANSIMapping implements DialectMapping { + + /** + * Whether {@link Types#TINYINT} is an unsigned integer. Both conventions (-128 … 127 range and + * 0 … 255 range) are found on the web. If unspecified, we conservatively assume unsigned bytes. + * All other integer types are presumed signed. + */ + private final boolean isByteUnsigned; + + public ANSIMapping(boolean isByteUnsigned) { + this.isByteUnsigned = isByteUnsigned; + } + + @Override + public Dialect getDialect() { + return Dialect.ANSI; + } + + @Override + public Optional<ColumnAdapter<?>> getMapping(int sqlType, String sqlTypeName) { + return Optional.ofNullable(getMappingImpl(sqlType, sqlTypeName)); + } + + public ColumnAdapter<?> getMappingImpl(int sqlType, String sqlTypeName) { + switch (sqlType) { + case Types.BIT: + case Types.BOOLEAN: return forceCast(Boolean.class); + case Types.TINYINT: if (!isByteUnsigned) return forceCast(Byte.class); // else fallthrough. + case Types.SMALLINT: return forceCast(Short.class); + case Types.INTEGER: return forceCast(Integer.class); + case Types.BIGINT: return forceCast(Long.class); + case Types.REAL: return forceCast(Float.class); + case Types.FLOAT: // Despite the name, this is implemented as DOUBLE in major databases. + case Types.DOUBLE: return forceCast(Double.class); + case Types.NUMERIC: // Similar to DECIMAL except that it uses exactly the specified precision. + case Types.DECIMAL: return forceCast(BigDecimal.class); + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: return new ColumnAdapter<>(String.class, ResultSet::getString); + case Types.DATE: return new ColumnAdapter<>(Date.class, ResultSet::getDate); + case Types.TIME: return new ColumnAdapter<>(LocalTime.class, ANSIMapping::toLocalTime); + case Types.TIMESTAMP: return new ColumnAdapter<>(Instant.class, ANSIMapping::toInstant); + case Types.TIME_WITH_TIMEZONE: return new ColumnAdapter<>(OffsetTime.class, ANSIMapping::toOffsetTime); + case Types.TIMESTAMP_WITH_TIMEZONE: return new ColumnAdapter<>(OffsetDateTime.class, ANSIMapping::toODT); + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: return new ColumnAdapter<>(byte[].class, ResultSet::getBytes); + case Types.ARRAY: return forceCast(Object[].class); + case Types.OTHER: // Database-specific accessed via getObject and setObject. + case Types.JAVA_OBJECT: return new ColumnAdapter<>(Object.class, ResultSet::getObject); + default: return null; + } + } + + private static LocalTime toLocalTime(ResultSet source, int columnIndex) throws SQLException { + final Time time = source.getTime(columnIndex); + return time == null ? null : time.toLocalTime(); + } + + private static Instant toInstant(ResultSet source, int columnIndex) throws SQLException { + final Timestamp t = source.getTimestamp(columnIndex); + return t == null ? null : t.toInstant(); + } + + private static OffsetDateTime toODT(ResultSet source, int columnIndex) throws SQLException { + final Timestamp t = source.getTimestamp(columnIndex); + final int offsetMinute = t.getTimezoneOffset(); + return t == null ? null : t.toInstant() + .atOffset(ZoneOffset.ofHoursMinutes(offsetMinute / 60, offsetMinute % 60)); + } + + private static OffsetTime toOffsetTime(ResultSet source, int columnIndex) throws SQLException { + final Time t = source.getTime(columnIndex); + final int offsetMinute = t.getTimezoneOffset(); + return t == null ? null : t.toLocalTime() + .atOffset(ZoneOffset.ofHoursMinutes(offsetMinute / 60, offsetMinute % 60)); + } + + private static <T> ColumnAdapter<T> forceCast(final Class<T> targetType) { + return new ColumnAdapter<>(targetType, (r, i) -> forceCast(targetType, r, i)); + } + + private static <T> T forceCast(final Class<T> targetType, ResultSet source, final Integer columnIndex) throws SQLException { + final Object value = source.getObject(columnIndex); + return value == null ? null : targetType.cast(value); + } +} diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Analyzer.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Analyzer.java index 11c9e35..4a9cdd1 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Analyzer.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Analyzer.java @@ -345,7 +345,7 @@ final class Analyzer { int i = 0; for (SQLColumn col : spec.getColumns()) { i++; - final SpatialFunctions.ColumnAdapter<?> colAdapter = functions.toJavaType(col.getType(), col.getTypeName()); + final ColumnAdapter<?> colAdapter = functions.toJavaType(col.getType(), col.getTypeName()); Class<?> type = colAdapter.javaType; final String colName = col.getName().getColumnName(); final String attrName = col.getName().getAttributeName(); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ColumnAdapter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ColumnAdapter.java new file mode 100644 index 0000000..8fdd3a5 --- /dev/null +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/ColumnAdapter.java @@ -0,0 +1,35 @@ +package org.apache.sis.internal.sql.feature; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.function.Function; + +import static org.apache.sis.util.ArgumentChecks.ensureNonNull; + +/** + * Utility to handle conversion of a result set cell value. This object is a bi-function whose input is a result set + * placed on row of interest, and an index specifying which column defines the cell to read on this line. + * + * @param <T> Type of object decoded from cell. + */ +class ColumnAdapter<T> implements SQLBiFunction<ResultSet, Integer, T> { + final Class<T> javaType; + private final SQLBiFunction<ResultSet, Integer, T> fetchValue; + + protected ColumnAdapter(Class<T> javaType, SQLBiFunction<ResultSet, Integer, T> fetchValue) { + ensureNonNull("Result java type", javaType); + ensureNonNull("Function for value retrieval", fetchValue); + this.javaType = javaType; + this.fetchValue = fetchValue; + } + + @Override + public T apply(ResultSet resultSet, Integer integer) throws SQLException { + return fetchValue.apply(resultSet, integer); + } + + @Override + public <V> SQLBiFunction<ResultSet, Integer, V> andThen(Function<? super T, ? extends V> after) { + return fetchValue.andThen(after); + } +} diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/DialectMapping.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/DialectMapping.java new file mode 100644 index 0000000..ce6e403 --- /dev/null +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/DialectMapping.java @@ -0,0 +1,12 @@ +package org.apache.sis.internal.sql.feature; + +import java.util.Optional; + +import org.apache.sis.internal.metadata.sql.Dialect; + +public interface DialectMapping { + + Dialect getDialect(); + + Optional<ColumnAdapter<?>> getMapping(final int sqlType, final String sqlTypeName); +} diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java index e346571..88c7546 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java @@ -10,8 +10,6 @@ import java.util.List; import org.opengis.feature.Feature; import org.opengis.feature.FeatureType; -import org.apache.sis.internal.sql.feature.SpatialFunctions.ColumnAdapter; - import static org.apache.sis.util.ArgumentChecks.ensureNonNull; class FeatureAdapter { diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISInterpreter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISInterpreter.java new file mode 100644 index 0000000..684c1d8 --- /dev/null +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISInterpreter.java @@ -0,0 +1,19 @@ +package org.apache.sis.internal.sql.feature; + +import org.opengis.filter.spatial.BBOX; + +public class PostGISInterpreter extends ANSIInterpreter { + + /** + * Filter encoding specifies bbox as a filter between envelopes. Default ANSI interpreter performs a standard + * intersection between geometries, which is not compliant. PostGIS has its own bbox operator: + * <a href="https://postgis.net/docs/geometry_overlaps.html">Geometry overlapping</a>. + * @param filter BBox filter specifying properties to compare. + * @param extraData A context to handle some corner cases. Not used. Can be null. + * @return A text (sql query) representation of input filter. + */ + @Override + public CharSequence visit(BBOX filter, Object extraData) { + return join(filter, "&&", extraData); + } +} diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISMapping.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISMapping.java new file mode 100644 index 0000000..9c9303d --- /dev/null +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/PostGISMapping.java @@ -0,0 +1,29 @@ +package org.apache.sis.internal.sql.feature; + +import java.sql.Types; +import java.util.Optional; + +import org.apache.sis.internal.metadata.sql.Dialect; + +public class PostGISMapping implements DialectMapping { + @Override + public Dialect getDialect() { + return Dialect.POSTGRESQL; + } + + @Override + public Optional<ColumnAdapter<?>> getMapping(int sqlType, String sqlTypeName) { + switch (sqlType) { + case (Types.OTHER): + } + return Optional.empty(); + } + + private ColumnAdapter<?> forOther(String sqlTypeName) { + switch (sqlTypeName.toLowerCase()) { + case "geometry": + case "geography": + default: return null; + } + } +} diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java index e5d991c..a117b13 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QueryFeatureSet.java @@ -6,7 +6,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Spliterator; -import java.util.StringJoiner; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -226,6 +225,10 @@ public class QueryFeatureSet extends AbstractFeatureSet { class SubsetAdapter extends SQLQueryAdapter { + SubsetAdapter() { + super(queryBuilder.dialect); + } + @Override protected FeatureSet create(CharSequence where, SortBy[] sorting, ColumnRef[] columns) { // TODO: use columns. diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java index 94c2d11..2932c98 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java @@ -3,10 +3,12 @@ package org.apache.sis.internal.sql.feature; import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; import org.opengis.filter.Filter; import org.opengis.filter.sort.SortBy; +import org.apache.sis.internal.metadata.sql.Dialect; import org.apache.sis.internal.storage.SubsetAdapter; import org.apache.sis.internal.storage.query.SimpleQuery; import org.apache.sis.storage.FeatureSet; @@ -18,6 +20,20 @@ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { private CharSequence where; + private final Supplier<? extends ANSIInterpreter> filterInterpreter; + + protected SQLQueryAdapter() { + this(() -> new ANSIInterpreter()); + } + + protected SQLQueryAdapter(final Dialect dbDialect) { + this(forDialect(dbDialect)); + } + + protected SQLQueryAdapter(Supplier<? extends ANSIInterpreter> filterInterpreter) { + this.filterInterpreter = filterInterpreter; + } + /** * No-op implementation. SQL optimisation is dynamically applied through {@link StreamSQL}. * @param offset The offset to handle. @@ -41,7 +57,7 @@ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { @Override public final Filter filter(Filter filter) { try { - final Object result = filter.accept(new ANSIInterpreter(), null); + final Object result = filter.accept(filterInterpreter.get(), null); if (ANSIInterpreter.isNonEmptyText(result)) { where = (CharSequence) result; return Filter.INCLUDE; @@ -88,6 +104,7 @@ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { static class Table extends SQLQueryAdapter { final org.apache.sis.internal.sql.feature.Table parent; public Table(org.apache.sis.internal.sql.feature.Table parent) { + super(parent.createStatement().dialect); this.parent = parent; } @@ -99,4 +116,10 @@ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { } } + public static Supplier<ANSIInterpreter> forDialect(final Dialect dialect) { + switch (dialect) { + case POSTGRESQL: return () -> new PostGISInterpreter(); + default: return () -> new ANSIInterpreter(); + } + } } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java index 2975d95..ca5ff05 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SpatialFunctions.java @@ -16,28 +16,18 @@ */ package org.apache.sis.internal.sql.feature; -import java.math.BigDecimal; import java.sql.DatabaseMetaData; -import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; import java.sql.Types; -import java.time.Instant; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZoneOffset; -import java.util.function.Function; +import java.util.Optional; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.internal.metadata.sql.Dialect; import org.apache.sis.internal.metadata.sql.Reflection; import org.apache.sis.setup.GeometryLibrary; -import static org.apache.sis.util.ArgumentChecks.ensureNonNull; - /** * Access to functions provided by geospatial databases. @@ -64,6 +54,9 @@ class SpatialFunctions { */ final GeometryLibrary library; + private final ANSIMapping defaultMapping; + private final Optional<DialectMapping> specificMapping; + /** * Creates a new accessor to geospatial functions for the database described by given metadata. */ @@ -88,6 +81,10 @@ class SpatialFunctions { * For now use the default library. */ library = null; + + final Dialect dialect = Dialect.guess(metadata); + specificMapping = forDialect(dialect); + defaultMapping = new ANSIMapping(isByteUnsigned); } /** @@ -105,58 +102,8 @@ class SpatialFunctions { */ @SuppressWarnings("fallthrough") protected ColumnAdapter<?> toJavaType(final int sqlType, final String sqlTypeName) { - switch (sqlType) { - case Types.BIT: - case Types.BOOLEAN: return forceCast(Boolean.class); - case Types.TINYINT: if (!isByteUnsigned) return forceCast(Byte.class); // else fallthrough. - case Types.SMALLINT: return forceCast(Short.class); - case Types.INTEGER: return forceCast(Integer.class); - case Types.BIGINT: return forceCast(Long.class); - case Types.REAL: return forceCast(Float.class); - case Types.FLOAT: // Despite the name, this is implemented as DOUBLE in major databases. - case Types.DOUBLE: return forceCast(Double.class); - case Types.NUMERIC: // Similar to DECIMAL except that it uses exactly the specified precision. - case Types.DECIMAL: return forceCast(BigDecimal.class); - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: return new ColumnAdapter<>(String.class, ResultSet::getString); - case Types.DATE: return new ColumnAdapter<>(Date.class, ResultSet::getDate); - case Types.TIME: return new ColumnAdapter<>(LocalTime.class, SpatialFunctions::toLocalTime); - case Types.TIMESTAMP: return new ColumnAdapter<>(Instant.class, SpatialFunctions::toInstant); - case Types.TIME_WITH_TIMEZONE: return new ColumnAdapter<>(OffsetTime.class, SpatialFunctions::toOffsetTime); - case Types.TIMESTAMP_WITH_TIMEZONE: return new ColumnAdapter<>(OffsetDateTime.class, SpatialFunctions::toODT); - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: return new ColumnAdapter<>(byte[].class, ResultSet::getBytes); - case Types.ARRAY: return forceCast(Object[].class); - case Types.OTHER: // Database-specific accessed via getObject and setObject. - case Types.JAVA_OBJECT: return new ColumnAdapter<>(Object.class, ResultSet::getObject); - default: return null; - } - } - - private static LocalTime toLocalTime(ResultSet source, int columnIndex) throws SQLException { - final Time time = source.getTime(columnIndex); - return time == null ? null : time.toLocalTime(); - } - - private static Instant toInstant(ResultSet source, int columnIndex) throws SQLException { - final Timestamp t = source.getTimestamp(columnIndex); - return t == null ? null : t.toInstant(); - } - - private static OffsetDateTime toODT(ResultSet source, int columnIndex) throws SQLException { - final Timestamp t = source.getTimestamp(columnIndex); - final int offsetMinute = t.getTimezoneOffset(); - return t == null ? null : t.toInstant() - .atOffset(ZoneOffset.ofHoursMinutes(offsetMinute / 60, offsetMinute % 60)); - } - - private static OffsetTime toOffsetTime(ResultSet source, int columnIndex) throws SQLException { - final Time t = source.getTime(columnIndex); - final int offsetMinute = t.getTimezoneOffset(); - return t == null ? null : t.toLocalTime() - .atOffset(ZoneOffset.ofHoursMinutes(offsetMinute / 60, offsetMinute % 60)); + return specificMapping.flatMap(dialect -> dialect.getMapping(sqlType, sqlTypeName)) + .orElseGet(() -> defaultMapping.getMappingImpl(sqlType, sqlTypeName)); } /** @@ -174,34 +121,10 @@ class SpatialFunctions { return null; } - private static <T> ColumnAdapter<T> forceCast(final Class<T> targetType) { - return new ColumnAdapter<>(targetType, (r, i) -> forceCast(targetType, r, i)); - } - - private static <T> T forceCast(final Class<T> targetType, ResultSet source, final Integer columnIndex) throws SQLException { - final Object value = source.getObject(columnIndex); - return value == null ? null : targetType.cast(value); - } - - protected static class ColumnAdapter<T> implements SQLBiFunction<ResultSet, Integer, T> { - final Class<T> javaType; - private final SQLBiFunction<ResultSet, Integer, T> fetchValue; - - protected ColumnAdapter(Class<T> javaType, SQLBiFunction<ResultSet, Integer, T> fetchValue) { - ensureNonNull("Result java type", javaType); - ensureNonNull("Function for value retrieval", fetchValue); - this.javaType = javaType; - this.fetchValue = fetchValue; - } - - @Override - public T apply(ResultSet resultSet, Integer integer) throws SQLException { - return fetchValue.apply(resultSet, integer); - } - - @Override - public <V> SQLBiFunction<ResultSet, Integer, V> andThen(Function<? super T, ? extends V> after) { - return fetchValue.andThen(after); + static Optional<DialectMapping> forDialect(final Dialect dialect) { + switch (dialect) { + case POSTGRESQL: return Optional.of(new PostGISMapping()); + default: return Optional.empty(); } } }
