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 1eb8926acb3e729133273dc3bd08b66bd257359d Author: Alexis Manin <[email protected]> AuthorDate: Tue Nov 12 17:32:54 2019 +0100 doc(SQLStore): add api doc about new components for SQL feature sets. --- .../sis/internal/sql/feature/ANSIMapping.java | 9 +++-- .../apache/sis/internal/sql/feature/Analyzer.java | 38 ++++++++++++++++++---- .../apache/sis/internal/sql/feature/Connector.java | 3 +- .../sis/internal/sql/feature/DialectMapping.java | 30 ++++++++++++++++- .../apache/sis/internal/sql/feature/Features.java | 1 - .../sql/feature/GeometryIdentification.java | 2 ++ .../sis/internal/sql/feature/PostGISMapping.java | 8 +++++ 7 files changed, 79 insertions(+), 12 deletions(-) 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 index ed1c429..b98f53f 100644 --- 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 @@ -14,7 +14,10 @@ import java.time.OffsetTime; import java.time.ZoneOffset; import java.util.Optional; -public class ANSIMapping implements DialectMapping { +/** + * Default JDBC mapping type, used as a fallback when no other database-specific mapping can handle value binding. + */ +class ANSIMapping implements DialectMapping { /** * Whether {@link Types#TINYINT} is an unsigned integer. Both conventions (-128 … 127 range and @@ -23,7 +26,7 @@ public class ANSIMapping implements DialectMapping { */ private final boolean isByteUnsigned; - public ANSIMapping(boolean isByteUnsigned) { + ANSIMapping(boolean isByteUnsigned) { this.isByteUnsigned = isByteUnsigned; } @@ -40,7 +43,7 @@ public class ANSIMapping implements DialectMapping { return Optional.ofNullable(getMappingImpl(columnDefinition)); } - public ColumnAdapter<?> getMappingImpl(SQLColumn columnDefinition) { + ColumnAdapter<?> getMappingImpl(SQLColumn columnDefinition) { switch (columnDefinition.type) { case Types.BIT: case Types.BOOLEAN: return forceCast(Boolean.class); 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 e58d0c0..063a17f 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 @@ -333,14 +333,40 @@ final class Analyzer { return tables.values(); } + /** + * Performs a simple analysis of given table to find its attributes and constraints. + * + * @param table The table to analyze. + * @param importedBy If this analysis is caused by another table analysis (foreign key between tables), it can be + * specified here. It will serve to deactivate constraints from the table to analyze and this one, + * to avoid cyclic associations. + * @return Table metadata, never null. + * @throws SQLException If something goes wrong while contacting database (fetching table metadata). + */ public SQLTypeSpecification create(final TableReference table, final TableReference importedBy) throws SQLException { return new TableMetadata(table, importedBy); } - public SQLTypeSpecification create(final PreparedStatement target, final String sourceQuery, final GenericName optName) throws SQLException { - return new QuerySpecification(target, sourceQuery, optName); + /** + * Analyze given SQL query to find what columns are returned. + * @param target The statement defining the query to analyze. + * @param definition An optional definition (free-text) to describe this statement. This typically can be text + * representation of user query. + * @param optName A name to identify the query. Can be null. + * @return Metadata of input statement, never null. + * @throws SQLException If something goes wrong while contacting database to fetch statement metadata. + */ + public SQLTypeSpecification create(final PreparedStatement target, final String definition, final GenericName optName) throws SQLException { + return new QuerySpecification(target, definition, optName); } + /** + * Creates a component in charge of mapping information between JDBC data and Feature model. + * @param spec The SQL metadata which will serve to infer Feature model mappings. Mandatory. + * @return A mapping layer above SQL information. Never null. + * @throws SQLException If we fail querying some additional metadata from database. Especially, we need to ask + * database for some relation information. + */ public FeatureAdapter buildAdapter(final SQLTypeSpecification spec) throws SQLException { final FeatureTypeBuilder builder = new FeatureTypeBuilder(nameFactory, functions.library, locale); builder.setName(spec.getName().orElseGet(RANDOME_NAME)); @@ -563,16 +589,16 @@ final class Analyzer { final int total; final PreparedStatement source; private final ResultSetMetaData meta; - private final String query; + private final String definition; private final GenericName name; private final List<SQLColumn> columns; - public QuerySpecification(PreparedStatement source, String sourceQuery, GenericName optName) throws SQLException { + public QuerySpecification(PreparedStatement source, String definition, GenericName optName) throws SQLException { this.source = source; meta = source.getMetaData(); total = meta.getColumnCount(); - query = sourceQuery; + this.definition = definition; name = optName; final ArrayList<SQLColumn> tmpCols = new ArrayList<>(total); @@ -602,7 +628,7 @@ final class Analyzer { @Override public Optional<String> getDefinition() throws SQLException { - return Optional.of(query); + return Optional.ofNullable(definition); } @Override diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Connector.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Connector.java index 9ce296c..b81af08 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Connector.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Connector.java @@ -9,7 +9,8 @@ import org.opengis.feature.Feature; import org.apache.sis.storage.DataStoreException; /** - * Simple abstraction to describe a component capable of loading data from an SQL connection. Used + * Simple abstraction to describe a component capable of loading data from an SQL connection. Used for subsetting SQL + * related feature sets. */ interface Connector { /** 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 index 33d0266..5f42858 100644 --- 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 @@ -6,15 +6,38 @@ import java.util.Optional; import org.apache.sis.internal.metadata.sql.Dialect; +/** + * Specifies mapping between values stored in database and Java. It is particularly useful for geo-related information, + * as geometries. + * + * @implNote For now, only two example implementations can be found in SIS: + * <ul> + * <li>{@link PostGISMapping PostGIS (geographic) specific mapping}</li> + * <li>{@link ANSIMapping Default mapping for simple types (text, numbers, temporal, etc.)}</li> + * </ul> + */ public interface DialectMapping extends SQLCloseable { + /** + * + * @return Provider that served to create this mapping. Should never be null. + */ Spi getSpi(); + /** + * Analyze given column definition to determine a mapping to java values. + * @param columnDefinition Information about the column to extract values from and expose through Java API. + * @return an empty shell if this dialect is not capable of founding a proper mapping, + */ Optional<ColumnAdapter<?>> getMapping(final SQLColumn columnDefinition); + /** + * TODO: expose that through Service loader. + * @implNote See {@link PostGISMapping} for an example. + */ interface Spi { /** - * + * Checks if database is compliant with this service specification, and create a mapper in such case. * @param c The connection to use to connect to the database. It will be read-only. * @return A component compatible with database of given connection, or nothing if the database is not supported * by this component. @@ -22,6 +45,11 @@ public interface DialectMapping extends SQLCloseable { */ Optional<DialectMapping> create(final Connection c) throws SQLException; + /** + * + * @return The target dialect accepted by this service. This is a vital information, because the system will + * only ask for a mapping if its service provider match current database dialect. + */ Dialect getDialect(); } } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java index 1bbc3f0..7e700a7 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java @@ -417,7 +417,6 @@ final class Features implements Spliterator<Feature> { */ private boolean fetch(final Consumer<? super Feature> action, final boolean all) throws SQLException { while (result.next()) { - // TODO: give connection to adapter. final Feature feature = adapter.read(result); for (int i=0; i < dependencies.length; i++) { final Features dependency = dependencies[i]; diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java index bb5c67e..5e97236 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java @@ -19,6 +19,8 @@ import static org.apache.sis.util.ArgumentChecks.ensureNonEmpty; /** * Not THREAD-SAFE ! + * Search for geometric information in specialized SQL for Simple feature tables (refer to + * <a href="https://www.opengeospatial.org/standards/sfs">OGC 06-104r4 (Simple feature access - Part 2: SQL option)</a>). * * @implNote <a href="https://www.jooq.org/doc/3.12/manual/sql-execution/fetching/pojos/#N5EFC1">I miss JOOQ...</a> */ 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 index eb3915a..ac9fc0f 100644 --- 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 @@ -18,6 +18,14 @@ import org.apache.sis.util.collection.BackingStoreException; import org.apache.sis.util.collection.Cache; import org.apache.sis.util.logging.Logging; +/** + * Maps geometric values between PostGIS natural representation (Hexadecimal EWKT) and SIS. + * For more information about EWKB format, see: + * <ul> + * <li><a href="http://postgis.refractions.net/documentation/manual-1.3/ch04.html#id2571020">PostGIS manual, section 4.1.2</a></li> + * <li><a href="https://www.ibm.com/support/knowledgecenter/SSGU8G_14.1.0/com.ibm.spatial.doc/ids_spat_285.htm">IBM WKB description</a></li> + * </ul> + */ public final class PostGISMapping implements DialectMapping { final PostGISMapping.Spi spi;
