use of org.apache.sis.filter.Filter in project sis by apache.
the class FeatureStream method filter.
/**
* Returns a stream with features of this stream that match the given predicate.
* If the given predicate is an instance of {@link Filter}, then this method tries
* to express the filter using SQL statements.
*/
@Override
public Stream<AbstractFeature> filter(final Predicate<? super AbstractFeature> predicate) {
ArgumentChecks.ensureNonNull("predicate", predicate);
if (predicate == Filter.include())
return this;
if (predicate == Filter.exclude())
return empty();
if (isPagined()) {
/*
* Offset/limit executed before the filter. Can not continue to build an SQL statement
* because the SQL `OFFSET ... FETCH NEXT` clause would be executed after the filter.
*/
return delegate().filter(predicate);
}
if (!(predicate instanceof Filter<?>)) {
hasPredicates = true;
return super.filter(predicate);
}
if (selection == null) {
selection = new SelectionClause(table);
filterToSQL = table.database.getFilterToSupportedSQL();
}
/*
* Simplify/optimize the filter (it may cause `include` or `exclude` filters to emerge) and try
* to convert the filter to SQL statements. This is not necessarily an all or nothing operation:
* if we have a "F₀ AND F₁ AND F₂" chain, it is possible to have some Fₙ as SQL statements and
* other Fₙ executed in Java code.
*/
final Optimization optimization = new Optimization();
optimization.setFeatureType(table.featureType);
Stream<AbstractFeature> stream = this;
for (final Filter<? super AbstractFeature> filter : optimization.applyAndDecompose((Filter<? super AbstractFeature>) predicate)) {
if (filter == Filter.include())
continue;
if (filter == Filter.exclude())
return empty();
if (!selection.tryAppend(filterToSQL, filter)) {
// Delegate to Java code all filters that we can not translate to SQL statement.
stream = super.filter(filter);
hasPredicates = true;
}
}
return stream;
}
use of org.apache.sis.filter.Filter in project sis by apache.
the class SelectionClauseWriter method removeUnsupportedFunctions.
/**
* Returns a writer without the functions that are unsupported by the database software.
* If the database supports all functions, then this method returns {@code this}.
* Otherwise it returns a copy of {@code this} with unsupported functions removed.
* This method should be invoked at most once for a {@link Database} instance.
*
* @param database information about the database software.
* @return a writer with unsupported functions removed.
*/
final SelectionClauseWriter removeUnsupportedFunctions(final Database<?> database) {
final Map<String, SpatialOperatorName> unsupported = new HashMap<>();
try (Connection c = database.source.getConnection()) {
final DatabaseMetaData metadata = c.getMetaData();
/*
* Get the names of all spatial functions for which a handler is registered.
* All those handlers should be instances of `Function`, otherwise we do not
* know how to determine whether the function is supported or not.
*/
final boolean lowerCase = metadata.storesLowerCaseIdentifiers();
final boolean upperCase = metadata.storesUpperCaseIdentifiers();
for (final SpatialOperatorName type : SpatialOperatorName.values()) {
final BiConsumer<Filter<AbstractFeature>, SelectionClause> function = getFilterHandler(type);
if (function instanceof Function) {
String name = ((Function) function).name;
if (lowerCase)
name = name.toLowerCase(Locale.US);
if (upperCase)
name = name.toUpperCase(Locale.US);
unsupported.put(name, type);
}
}
/*
* Remove from above map all functions that are supported by the database.
* This list is potentially large so we do not put those items in a map.
*/
final String pattern = (lowerCase ? "st_%" : "ST\\_%").replace("\\", metadata.getSearchStringEscape());
try (ResultSet r = metadata.getFunctions(database.catalogOfSpatialTables, database.schemaOfSpatialTables, pattern)) {
while (r.next()) {
unsupported.remove(r.getString("FUNCTION_NAME"));
}
}
} catch (SQLException e) {
/*
* If this exception happens before `unsupported` entries were removed,
* this is equivalent to assuming that all functions are unsupported.
*/
database.listeners.warning(e);
}
/*
* Remaining functions are unsupported functions.
*/
if (unsupported.isEmpty()) {
return this;
}
final SelectionClauseWriter copy = duplicate();
copy.removeFilterHandlers(unsupported.values());
return copy;
}
use of org.apache.sis.filter.Filter in project sis by apache.
the class FeatureSubset method features.
/**
* Returns a stream of all features contained in this dataset.
*/
@Override
public Stream<AbstractFeature> features(final boolean parallel) throws DataStoreException {
Stream<AbstractFeature> stream = source.features(parallel);
/*
* Apply filter.
*/
final Filter<? super AbstractFeature> selection = query.getSelection();
if (selection != null && !selection.equals(Filter.include())) {
stream = stream.filter(selection);
}
/*
* Apply sorting.
*/
final SortBy<AbstractFeature> sortBy = query.getSortBy();
if (sortBy != null) {
stream = stream.sorted(sortBy);
}
/*
* Apply offset.
*/
final long offset = query.getOffset();
if (offset > 0) {
stream = stream.skip(offset);
}
/*
* Apply limit.
*/
final OptionalLong limit = query.getLimit();
if (limit.isPresent()) {
stream = stream.limit(limit.getAsLong());
}
/*
* Transform feature instances.
* Note: "projection" here is in relational database sense, not map projection.
*/
final FeatureQuery.NamedExpression[] projection = query.getProjection();
if (projection != null) {
@SuppressWarnings({ "unchecked", "rawtypes" }) final Expression<? super AbstractFeature, ?>[] expressions = new Expression[projection.length];
for (int i = 0; i < expressions.length; i++) {
expressions[i] = projection[i].expression;
}
final DefaultFeatureType type = getType();
final String[] names = FeatureUtilities.getNames(type.getProperties(false));
stream = stream.map(t -> {
final AbstractFeature f = type.newInstance();
for (int i = 0; i < expressions.length; i++) {
f.setPropertyValue(names[i], expressions[i].apply(t));
}
return f;
});
}
return stream;
}
Aggregations