From c3ebdf776f54ccd40f5f38709983a8c4d4f90c41 Mon Sep 17 00:00:00 2001 From: Lorenzo Natali Date: Fri, 11 Nov 2016 09:57:47 +0100 Subject: [PATCH 1/2] Add support to Cross-Layer Filtering Added to Filter Utils the possibility to parse cross layer filtering --- web/client/utils/FilterUtils.jsx | 52 ++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/web/client/utils/FilterUtils.jsx b/web/client/utils/FilterUtils.jsx index 54d0c05b13..af78549596 100644 --- a/web/client/utils/FilterUtils.jsx +++ b/web/client/utils/FilterUtils.jsx @@ -49,7 +49,7 @@ const FilterUtils = { "ogc": {startTag: "", endTag: ""}, "fes": {startTag: "", endTag: ""} }, - toOGCFilter: function(ftName, json, version, sortOptions = null, hits = false, format = null) { + toOGCFilter: function(ftName, json, version, sortOptions = null, hits = false, format = null, propertyNames = null) { try { this.objFilter = (json instanceof Object) ? json : JSON.parse(json); } catch(e) { @@ -87,6 +87,14 @@ const FilterUtils = { spatialFilter = this.processOGCSpatialFilter(versionOGC); filters.push(spatialFilter); } + if (this.objFilter.crossLayerFilter) { + let crossLayerFilter = this.objFilter.crossLayerFilter; + if (Array.isArray()) { + crossLayerFilter.forEach( f => filters.push(this.processOGCCrossLayerFilter(f))); + } else { + filters.push(this.processOGCCrossLayerFilter(crossLayerFilter)); + } + } let filter = "<" + this.nsplaceholder + ":Filter>"; @@ -104,7 +112,12 @@ const FilterUtils = { ogcFilter += ''; ogcFilter += filter; - + if (propertyNames) { + ogcFilter += propertyNames.map( name => ( + this.propertyTagReference[this.nsplaceholder].startTag + + name + + this.propertyTagReference[this.nsplaceholder].endTag )).join(""); + } if (sortOptions && sortOptions.sortBy && sortOptions.sortOrder) { ogcFilter += "<" + this.nsplaceholder + ":SortBy>" + @@ -475,6 +488,41 @@ const FilterUtils = { ogc += this.ogcSpatialOperator[this.objFilter.spatialField.operation].endTag; return ogc; }, + processOGCCrossLayerFilter: function(crossLayerFilter) { + let ogc = this.ogcSpatialOperator[crossLayerFilter.operation].startTag; + ogc += + this.propertyTagReference[this.nsplaceholder].startTag + + crossLayerFilter.attribute + + this.propertyTagReference[this.nsplaceholder].endTag; + + switch (crossLayerFilter.operation) { + case "INTERSECTS": + case "DWITHIN": + case "WITHIN": + case "CONTAINS": { + if (crossLayerFilter.collectGeometries) { + ogc += ` + + ${crossLayerFilter.collectGeometries.queryCollection.typeName} + ${crossLayerFilter.collectGeometries.queryCollection.geometryName} + ${crossLayerFilter.collectGeometries.queryCollection.cqlFilter} + + `; + } + + if (crossLayerFilter.operation === "DWITHIN") { + ogc += '<' + this.nsplaceholder + ':Distance units="m">' + (crossLayerFilter.distance || 0) + ''; + } + + break; + } + default: + break; + } + + ogc += this.ogcSpatialOperator[this.objFilter.spatialField.operation].endTag; + return ogc; + }, getGmlPointElement: function(coordinates, srsName, version) { let gmlPoint = ' Date: Fri, 11 Nov 2016 10:59:58 +0100 Subject: [PATCH 2/2] add doc and test --- web/client/utils/FilterUtils.jsx | 63 +++++++++++-------- .../utils/__tests__/FilterUtils-test.js | 28 +++++++++ 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/web/client/utils/FilterUtils.jsx b/web/client/utils/FilterUtils.jsx index af78549596..88a33c30a2 100644 --- a/web/client/utils/FilterUtils.jsx +++ b/web/client/utils/FilterUtils.jsx @@ -488,39 +488,52 @@ const FilterUtils = { ogc += this.ogcSpatialOperator[this.objFilter.spatialField.operation].endTag; return ogc; }, + /** + * processOGCCrossLayerFilter(object) + * object should be in this form : + * { + * operation: "FILTER_OPERATION_TO_DO_WITH_GEOMETRY", + * attribute: "GEOMETRY_NAME_OF_THE_FEATURE_TYPE_TO_FILTER", + * collectGeometries: {queryCollection: { + * typeName: "TYPE_NAME_TO_QUERY", + * geometryName: "GEOMETRY_NAME_OF_THE_FEATURE_TYPE_TO_QUERY", + * cqlFilter: "CQL_FITER_TO_APPLY_TO_THE_FEATURE_TYPE" + * } + * }} + * Example: if I want to filter the featureType "roads", with the geometryName = "roads_geom" + * that intersect the polygons from the featureType "regions, with geometryName "regions_geom" + * where the attribute "area" of the region is >= 10 You will have the following + * { + * operation: "INTERSECTS" + * attribute: "roads_geom", + * collectGeometries: {queryCollection: { + * typeName: "regions", + * geometryName: "regions_geom", + * cqlFilter: "area > 10" + * }} + * } + */ processOGCCrossLayerFilter: function(crossLayerFilter) { let ogc = this.ogcSpatialOperator[crossLayerFilter.operation].startTag; ogc += this.propertyTagReference[this.nsplaceholder].startTag + crossLayerFilter.attribute + this.propertyTagReference[this.nsplaceholder].endTag; - - switch (crossLayerFilter.operation) { - case "INTERSECTS": - case "DWITHIN": - case "WITHIN": - case "CONTAINS": { - if (crossLayerFilter.collectGeometries) { - ogc += ` - - ${crossLayerFilter.collectGeometries.queryCollection.typeName} - ${crossLayerFilter.collectGeometries.queryCollection.geometryName} - ${crossLayerFilter.collectGeometries.queryCollection.cqlFilter} - - `; - } - - if (crossLayerFilter.operation === "DWITHIN") { - ogc += '<' + this.nsplaceholder + ':Distance units="m">' + (crossLayerFilter.distance || 0) + ''; - } - - break; - } - default: - break; + // only collectGeometries is supported now + if (crossLayerFilter.collectGeometries) { + ogc += `` + + `` + + `${crossLayerFilter.collectGeometries.queryCollection.typeName}` + + `${crossLayerFilter.collectGeometries.queryCollection.geometryName}` + + `${crossLayerFilter.collectGeometries.queryCollection.cqlFilter}` + + `` + + ``; + } + if (crossLayerFilter.operation === "DWITHIN") { + ogc += '<' + this.nsplaceholder + ':Distance units="m">' + (crossLayerFilter.distance || 0) + ''; } - ogc += this.ogcSpatialOperator[this.objFilter.spatialField.operation].endTag; + ogc += this.ogcSpatialOperator[crossLayerFilter.operation].endTag; return ogc; }, getGmlPointElement: function(coordinates, srsName, version) { diff --git a/web/client/utils/__tests__/FilterUtils-test.js b/web/client/utils/__tests__/FilterUtils-test.js index 11d6a677b1..60fef16739 100644 --- a/web/client/utils/__tests__/FilterUtils-test.js +++ b/web/client/utils/__tests__/FilterUtils-test.js @@ -461,4 +461,32 @@ describe('FilterUtils', () => { let filter = FilterUtils.toCQLFilter(filterObj); expect(filter).toEqual(expected); }); + it('Check CrossLayerFilter segment generation', () => { + let crossLayerFilterObj = { + operation: "INTERSECTS", + attribute: "roads_geom", + collectGeometries: {queryCollection: { + typeName: "regions", + geometryName: "regions_geom", + cqlFilter: "area > 10" + }} + }; + let expected = "" + + 'roads_geom' + + '' + + '' + + 'regions' + + 'regions_geom' + + 'area > 10' + + '' + + ""; + + // this is a workarround for this issue : https://github.com/geosolutions-it/MapStore2/issues/1263 + // please remove when fixed + FilterUtils.nsplaceholder = "ogc"; + FilterUtils.setOperatorsPlaceholders("{namespace}", "ogc"); + + let filter = FilterUtils.processOGCCrossLayerFilter(crossLayerFilterObj); + expect(filter).toEqual(expected); + }); });