use of org.geotoolkit.filter.visitor.FilterAttributeExtractor in project geotoolkit by Geomatys.
the class DefaultJDBCFeatureStore method getQOMFeatureReader.
/**
* Get reader with geotk query model.
*/
private FeatureReader getQOMFeatureReader(final org.geotoolkit.storage.feature.query.Query query, Connection cnx) throws DataStoreException {
final String dbSchemaName = getDatabaseSchema();
final FeatureType type = dbmodel.getFeatureType(query.getTypeName());
final String tableName = type.getName().tip().toString();
TableMetaModel tableMeta = null;
if (dbSchemaName == null) {
// Try to handle empty schema name given at configuration
for (final SchemaMetaModel scheme : dbmodel.getSchemaMetaModels()) {
final TableMetaModel tableMetaTemp = scheme.getTable(tableName);
if (tableMetaTemp != null) {
tableMeta = tableMetaTemp;
break;
}
}
} else {
tableMeta = dbmodel.getSchemaMetaModel(getDatabaseSchema()).getTable(tableName);
}
if (tableMeta == null) {
throw new DataStoreException("Unable to get table " + tableName + " in the database.");
}
final FeatureType tableType = tableMeta.getType(TableMetaModel.View.ALLCOMPLEX).build();
final PrimaryKey pkey = dbmodel.getPrimaryKey(query.getTypeName());
// replace any PropertyEqualsTo in true ID filters
Filter baseFilter = query.getSelection();
baseFilter = (Filter) FIDFixVisitor.INSTANCE.visit(baseFilter);
// split the filter between what can be send and must be handle by code
final Filter[] divided = getDialect().splitFilter(baseFilter, tableType);
Filter preFilter = divided[0];
Filter postFilter = divided[1];
// ensure spatial filters are in featuretype geometry crs
preFilter = (Filter) new CRSAdaptorVisitor(tableType).visit(preFilter);
// rebuild a new query with the same params, but just the pre-filter
final org.geotoolkit.storage.feature.query.Query builder = new org.geotoolkit.storage.feature.query.Query();
builder.copy(query);
builder.setSelection(preFilter);
if (query.getResolution() != null) {
// attach resampling in hints; used later by postgis dialect
builder.getHints().add(new Hints(RESAMPLING, query.getResolution()));
}
final org.geotoolkit.storage.feature.query.Query preQuery = builder;
final FeatureType baseType = getFeatureType(query.getTypeName());
// Build the feature type returned by this query. Also build an eventual extra feature type
// containing the attributes we might need in order to evaluate the post filter
final FeatureType queryFeatureType;
final FeatureType returnedFeatureType;
if (query.retrieveAllProperties()) {
returnedFeatureType = queryFeatureType = (FeatureType) baseType;
} else {
// TODO BUG here, query with filter on a not returned geometry field crash
returnedFeatureType = (FeatureType) FeatureTypeExt.createSubType(tableType, query.getPropertyNames());
final FilterAttributeExtractor extractor = new FilterAttributeExtractor(tableType);
extractor.visit(postFilter, null);
final GenericName[] extraAttributes = extractor.getAttributeNames();
final List<GenericName> allAttributes = new ArrayList<>();
for (String str : query.getPropertyNames()) {
allAttributes.add(type.getProperty(str).getName());
}
for (GenericName extraAttribute : extraAttributes) {
if (!allAttributes.contains(extraAttribute)) {
allAttributes.add(extraAttribute);
}
}
// ensure we have the primarykeys
pkLoop: for (ColumnMetaModel pkc : pkey.getColumns()) {
final String pkcName = pkc.getName();
for (GenericName n : allAttributes) {
if (n.tip().toString().equals(pkcName)) {
continue pkLoop;
}
}
// add the pk attribut
allAttributes.add(baseType.getProperty(pkcName).getName());
}
final GenericName[] allAttributeArray = allAttributes.toArray(new GenericName[allAttributes.size()]);
queryFeatureType = (FeatureType) FeatureTypeExt.createSubType(tableType, allAttributeArray);
}
final String sql;
// we gave him the connection, he must not release it
final boolean release = (cnx == null);
if (cnx == null) {
try {
cnx = getDataSource().getConnection();
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
FeatureReader reader;
// so for now if we got one, we let the filter be evaluated in java and not with a sql query
if (containsOperation(preQuery, baseType)) {
try {
sql = getQueryBuilder().selectSQL(baseType, new org.geotoolkit.storage.feature.query.Query(baseType.getName()));
reader = new JDBCFeatureReader(this, sql, baseType, cnx, release, null);
FeatureStreams.subset(reader, query);
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
} else {
try {
sql = getQueryBuilder().selectSQL(queryFeatureType, preQuery);
reader = new JDBCFeatureReader(this, sql, queryFeatureType, cnx, release, null);
} catch (SQLException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
// if post filter, wrap it
if (postFilter != null && postFilter != Filter.include()) {
reader = FeatureStreams.filter(reader, postFilter);
}
// if we need to constraint type
if (!returnedFeatureType.equals(queryFeatureType)) {
reader = FeatureStreams.decorate(reader, new ViewMapper(type, query.getPropertyNames()), query.getHints());
}
return reader;
}
use of org.geotoolkit.filter.visitor.FilterAttributeExtractor in project geotoolkit by Geomatys.
the class IndexedShapefileFeatureStore method getFeatureReader.
/**
* Use the spatial index if available and adds a small optimization: if no
* attributes are going to be read, don't uselessly open and read the dbf
* file.
*/
@Override
public FeatureReader getFeatureReader(final Query query) throws DataStoreException {
if (!(query instanceof org.geotoolkit.storage.feature.query.Query))
throw new UnsupportedQueryException();
final org.geotoolkit.storage.feature.query.Query gquery = (org.geotoolkit.storage.feature.query.Query) query;
final FeatureType baseType = getFeatureType();
final String queryTypeName = gquery.getTypeName();
final String[] queryPropertyNames = gquery.getPropertyNames();
final Hints queryHints = gquery.getHints();
final double[] queryRes = gquery.getResolution();
Filter queryFilter = gquery.getSelection();
// check if we must read the 3d values
final boolean read3D = true;
// find the properties we will read and return --------------------------
final AttributeType idAttribute = (AttributeType) baseType.getProperty(AttributeConvention.IDENTIFIER);
Set<AttributeType> readProperties;
Set<PropertyType> returnedProperties;
if (queryPropertyNames == null) {
// return all properties. Note : preserve order by using a linked set implementation
readProperties = new LinkedHashSet<>(getAttributes(baseType, true));
returnedProperties = new LinkedHashSet<>((Collection) baseType.getProperties(true));
} else {
// return only a subset of properties. Note : preserve order by using a linked set implementation
readProperties = new LinkedHashSet<>(queryPropertyNames.length);
returnedProperties = new LinkedHashSet<>(queryPropertyNames.length);
for (String n : queryPropertyNames) {
final PropertyType cdt = baseType.getProperty(n);
if (cdt instanceof AttributeType) {
readProperties.add((AttributeType) cdt);
} else if (cdt instanceof AbstractOperation) {
final Set<String> deps = ((AbstractOperation) cdt).getDependencies();
for (String dep : deps) readProperties.add((AttributeType) baseType.getProperty(dep));
}
returnedProperties.add(cdt);
}
// add filter properties
final FilterAttributeExtractor fae = new FilterAttributeExtractor();
fae.visit(queryFilter, null);
final Set<GenericName> filterPropertyNames = fae.getAttributeNameSet();
for (GenericName n : filterPropertyNames) {
final PropertyType cdt = baseType.getProperty(n.toString());
if (cdt instanceof AttributeType) {
readProperties.add((AttributeType) cdt);
} else if (cdt instanceof AbstractOperation) {
final Set<String> deps = ((AbstractOperation) cdt).getDependencies();
for (String dep : deps) readProperties.add((AttributeType) baseType.getProperty(dep));
}
}
}
final Set<PropertyType> allProperties = new LinkedHashSet<>(returnedProperties);
allProperties.addAll(readProperties);
// create a reader ------------------------------------------------------
final FeatureType readType;
final FeatureReader reader;
try {
final GenericName[] readPropertyNames = new GenericName[allProperties.size()];
int i = 0;
for (PropertyType prop : allProperties) {
readPropertyNames[i++] = prop.getName();
}
readType = FeatureTypeExt.createSubType(baseType, readPropertyNames);
if (queryFilter.getOperatorType() == SpatialOperatorName.BBOX) {
// in case we have a BBOX filter only, which is very commun, we can speed
// the process by relying on the quadtree estimations
final Envelope bbox = ExtractBoundsFilterVisitor.bbox(queryFilter, null);
final boolean loose = (queryFilter instanceof LooseBBox);
queryFilter = Filter.include();
final List<AttributeType> attsProperties = new ArrayList<>(readProperties);
attsProperties.remove(idAttribute);
reader = createFeatureReader(getBBoxAttributesReader(attsProperties, bbox, loose, queryHints, read3D, queryRes), readType, queryHints);
} else if (queryFilter instanceof ResourceId && ((ResourceId) queryFilter).getIdentifier() == null) {
// in case we have an empty id set (TODO: should never happen, maybe we should remove this case).
return FeatureStreams.emptyReader(getFeatureType());
} else {
final List<AttributeType> attsProperties = new ArrayList<>(readProperties);
attsProperties.remove(idAttribute);
reader = createFeatureReader(getAttributesReader(attsProperties, queryFilter, read3D, queryRes), readType, queryHints);
}
} catch (IOException ex) {
throw new DataStoreException(ex);
}
// handle remaining query parameters ------------------------------------
final org.geotoolkit.storage.feature.query.Query qb = new org.geotoolkit.storage.feature.query.Query(queryTypeName);
if (readProperties.equals(returnedProperties)) {
qb.setProperties(queryPropertyNames);
}
qb.setSelection(queryFilter);
qb.setHints(queryHints);
qb.setSortBy(gquery.getSortBy());
qb.setOffset(gquery.getOffset());
gquery.getLimit().ifPresent(qb::setLimit);
return FeatureStreams.subset(reader, qb);
}
Aggregations