Search in sources :

Example 1 with FilterAttributeExtractor

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;
}
Also used : FeatureType(org.opengis.feature.FeatureType) Query(org.apache.sis.storage.Query) SQLQuery(org.geotoolkit.storage.feature.query.SQLQuery) Hints(org.geotoolkit.factory.Hints) SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) GenericName(org.opengis.util.GenericName) FeatureReader(org.geotoolkit.storage.feature.FeatureReader) DataStoreException(org.apache.sis.storage.DataStoreException) ViewMapper(org.geotoolkit.feature.ViewMapper) FilterAttributeExtractor(org.geotoolkit.filter.visitor.FilterAttributeExtractor) Filter(org.opengis.filter.Filter) CRSAdaptorVisitor(org.geotoolkit.filter.visitor.CRSAdaptorVisitor)

Example 2 with FilterAttributeExtractor

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);
}
Also used : FeatureType(org.opengis.feature.FeatureType) Query(org.apache.sis.storage.Query) Hints(org.geotoolkit.factory.Hints) UnsupportedQueryException(org.apache.sis.storage.UnsupportedQueryException) PropertyType(org.opengis.feature.PropertyType) Envelope(org.locationtech.jts.geom.Envelope) GenericName(org.opengis.util.GenericName) LooseBBox(org.geotoolkit.filter.binaryspatial.LooseBBox) AttributeType(org.opengis.feature.AttributeType) ShapefileFeatureReader(org.geotoolkit.data.shapefile.ShapefileFeatureReader) FeatureReader(org.geotoolkit.storage.feature.FeatureReader) DataStoreException(org.apache.sis.storage.DataStoreException) IOException(java.io.IOException) AbstractOperation(org.apache.sis.feature.AbstractOperation) FilterAttributeExtractor(org.geotoolkit.filter.visitor.FilterAttributeExtractor) Filter(org.opengis.filter.Filter) ResourceId(org.opengis.filter.ResourceId) CloseableCollection(org.geotoolkit.index.CloseableCollection)

Aggregations

DataStoreException (org.apache.sis.storage.DataStoreException)2 Query (org.apache.sis.storage.Query)2 Hints (org.geotoolkit.factory.Hints)2 FilterAttributeExtractor (org.geotoolkit.filter.visitor.FilterAttributeExtractor)2 FeatureReader (org.geotoolkit.storage.feature.FeatureReader)2 FeatureType (org.opengis.feature.FeatureType)2 Filter (org.opengis.filter.Filter)2 GenericName (org.opengis.util.GenericName)2 IOException (java.io.IOException)1 SQLException (java.sql.SQLException)1 ArrayList (java.util.ArrayList)1 AbstractOperation (org.apache.sis.feature.AbstractOperation)1 UnsupportedQueryException (org.apache.sis.storage.UnsupportedQueryException)1 ShapefileFeatureReader (org.geotoolkit.data.shapefile.ShapefileFeatureReader)1 ViewMapper (org.geotoolkit.feature.ViewMapper)1 LooseBBox (org.geotoolkit.filter.binaryspatial.LooseBBox)1 CRSAdaptorVisitor (org.geotoolkit.filter.visitor.CRSAdaptorVisitor)1 CloseableCollection (org.geotoolkit.index.CloseableCollection)1 SQLQuery (org.geotoolkit.storage.feature.query.SQLQuery)1 Envelope (org.locationtech.jts.geom.Envelope)1