use of org.apache.sis.storage.sql.ResourceDefinition in project sis by apache.
the class PostgresTest method testSpatialFeatures.
/**
* Tests reading and writing features and rasters.
*
* @throws Exception if an error occurred while testing the database.
*/
@Test
public void testSpatialFeatures() throws Exception {
try (TestDatabase database = TestDatabase.createOnPostgreSQL(SQLStoreTest.SCHEMA, true)) {
database.executeSQL(PostgresTest.class, "file:SpatialFeatures.sql");
final StorageConnector connector = new StorageConnector(database.source);
connector.setOption(OptionKey.GEOMETRY_LIBRARY, GeometryLibrary.JTS);
final ResourceDefinition table = ResourceDefinition.table(null, SQLStoreTest.SCHEMA, "SpatialData");
try (SQLStore store = new SQLStore(new SQLStoreProvider(), connector, table)) {
/*
* Invoke the private `model()` method. We have to use reflection because the class
* is not in the same package and we do not want to expose the method in public API.
*/
final Method modelAccessor = SQLStore.class.getDeclaredMethod("model");
modelAccessor.setAccessible(true);
final Postgres<?> pg = (Postgres<?>) modelAccessor.invoke(store);
try (Connection connection = database.source.getConnection();
ExtendedInfo info = new ExtendedInfo(pg, connection)) {
testInfoStatements(info);
testGeometryGetter(info, connection);
testRasterReader(TestRaster.USHORT, info, connection);
}
/*
* Tests through public API.
*/
final FeatureSet resource = store.findResource("SpatialData");
try (Stream<AbstractFeature> features = resource.features(false)) {
features.forEach(PostgresTest::validate);
}
final Envelope envelope = resource.getEnvelope().get();
assertEquals(envelope.getMinimum(0), -72, 1);
assertEquals(envelope.getMaximum(1), 43, 1);
}
}
}
use of org.apache.sis.storage.sql.ResourceDefinition in project sis by apache.
the class Database method analyze.
/**
* Creates a model about the specified tables in the database.
* This method shall be invoked exactly once after {@code Database} construction.
* It requires a list of tables to include in the model, but this list should not
* include the dependencies; this method will follow foreigner keys automatically.
*
* <p>The table names shall be qualified names of 1, 2 or 3 components.
* The components are {@code <catalog>.<schema pattern>.<table pattern>} where:</p>
*
* <ul>
* <li>{@code <catalog>}, if present, shall be the name of a catalog as it is stored in the database.</li>
* <li>{@code <schema pattern>}, if present, shall be the pattern of a schema.
* The pattern can use {@code '_'} and {@code '%'} wildcards characters.</li>
* <li>{@code <table pattern>} (mandatory) shall be the pattern of a table.
* The pattern can use {@code '_'} and {@code '%'} wildcards characters.</li>
* </ul>
*
* @param store the data store for which we are creating a model. Used only in case of error.
* @param connection connection to the database. Sometime the caller already has a connection at hand.
* @param tableNames qualified name of the tables. Specified by users at construction time.
* @param queries additional resources associated to SQL queries. Specified by users at construction time.
* @param customizer user-specified modification to the features, or {@code null} if none.
* @throws SQLException if a database error occurred while reading metadata.
* @throws DataStoreException if a logical error occurred while analyzing the database structure.
*/
private void analyze(final SQLStore store, final Connection connection, final GenericName[] tableNames, final ResourceDefinition[] queries, final SchemaModifier customizer) throws Exception {
final DatabaseMetaData metadata = connection.getMetaData();
final String[] tableTypes = getTableTypes(metadata);
/*
* The following tables are defined by ISO 19125 / OGC Simple feature access part 2.
* Note that the standard specified those names in upper-case letters, which is also
* the default case specified by the SQL standard. However some databases use lower
* cases instead.
*/
String tableCRS = InfoStatements.SPATIAL_REF_SYS;
String tableGeom = InfoStatements.GEOMETRY_COLUMNS;
if (metadata.storesLowerCaseIdentifiers()) {
tableCRS = tableCRS.toLowerCase(Locale.US).intern();
tableGeom = tableGeom.toLowerCase(Locale.US).intern();
}
final Map<String, Boolean> ignoredTables = new HashMap<>(8);
ignoredTables.put(tableCRS, Boolean.TRUE);
ignoredTables.put(tableGeom, Boolean.TRUE);
addIgnoredTables(ignoredTables);
isSpatial = hasTable(metadata, tableTypes, ignoredTables);
/*
* Collect the names of all tables specified by user, ignoring the tables
* used for database internal working (for example by PostGIS).
*/
final Analyzer analyzer = new Analyzer(this, connection, metadata, customizer);
final Set<TableReference> declared = new LinkedHashSet<>();
for (final GenericName tableName : tableNames) {
final String[] names = TableReference.splitName(tableName);
try (ResultSet reflect = metadata.getTables(names[2], names[1], names[0], tableTypes)) {
while (reflect.next()) {
final String table = analyzer.getUniqueString(reflect, Reflection.TABLE_NAME);
if (ignoredTables.containsKey(table)) {
continue;
}
declared.add(new TableReference(analyzer.getUniqueString(reflect, Reflection.TABLE_CAT), analyzer.getUniqueString(reflect, Reflection.TABLE_SCHEM), table, analyzer.getUniqueString(reflect, Reflection.REMARKS)));
}
}
}
/*
* At this point we got the list of tables requested by the user. Now create the Table objects for each
* specified name. During this iteration, we may discover new tables to analyze because of dependencies
* (foreigner keys).
*/
final List<Table> tableList;
tableList = new ArrayList<>(tableNames.length);
for (final TableReference reference : declared) {
// Adds only the table explicitly required by the user.
tableList.add(analyzer.table(reference, reference.getName(analyzer), null));
}
/*
* Add queries if any.
*/
for (final ResourceDefinition resource : queries) {
// Optional value should always be present in this context.
tableList.add(analyzer.query(resource.getName(), resource.getQuery().get()));
}
/*
* At this point we finished to create the tables explicitly requested by the user.
* Register all tables only at this point, because other tables (dependencies) may
* have been analyzed as a side-effect of above loop.
*/
for (final Table table : analyzer.finish()) {
tablesByNames.add(store, table.featureType.getName(), table);
hasGeometry |= table.hasGeometry;
hasRaster |= table.hasRaster;
}
tables = tableList.toArray(new Table[tableList.size()]);
}
Aggregations