Skip to content

Commit

Permalink
Add support to Cross-Layer Filtering (#1262)
Browse files Browse the repository at this point in the history
* Add support to Cross-Layer Filtering

Added to Filter Utils the possibility to parse cross layer filtering

* add doc and test
  • Loading branch information
offtherailz authored and mbarto committed Nov 11, 2016
1 parent 9ec1c06 commit dacfe9f
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 2 deletions.
65 changes: 63 additions & 2 deletions web/client/utils/FilterUtils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const FilterUtils = {
"ogc": {startTag: "<ogc:PropertyName>", endTag: "</ogc:PropertyName>"},
"fes": {startTag: "<fes:ValueReference>", endTag: "</fes:ValueReference>"}
},
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) {
Expand Down Expand Up @@ -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>";

Expand All @@ -104,7 +112,12 @@ const FilterUtils = {

ogcFilter += '<wfs:Query ' + (versionOGC === "2.0" ? "typeNames" : "typeName") + '="' + ftName + '" srsName="EPSG:4326">';
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>" +
Expand Down Expand Up @@ -475,6 +488,54 @@ 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;
// only collectGeometries is supported now
if (crossLayerFilter.collectGeometries) {
ogc += `<ogc:Function name="collectGeometries">` +
`<ogc:Function name="queryCollection">` +
`<ogc:Literal>${crossLayerFilter.collectGeometries.queryCollection.typeName}</ogc:Literal>` +
`<ogc:Literal>${crossLayerFilter.collectGeometries.queryCollection.geometryName}</ogc:Literal>` +
`<ogc:Literal>${crossLayerFilter.collectGeometries.queryCollection.cqlFilter}</ogc:Literal>` +
`</ogc:Function>` +
`</ogc:Function>`;
}
if (crossLayerFilter.operation === "DWITHIN") {
ogc += '<' + this.nsplaceholder + ':Distance units="m">' + (crossLayerFilter.distance || 0) + '</' + this.nsplaceholder + ':Distance>';
}

ogc += this.ogcSpatialOperator[crossLayerFilter.operation].endTag;
return ogc;
},
getGmlPointElement: function(coordinates, srsName, version) {
let gmlPoint = '<gml:Point srsDimension="2"';

Expand Down
28 changes: 28 additions & 0 deletions web/client/utils/__tests__/FilterUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<ogc:Intersects>"
+ '<ogc:PropertyName>roads_geom</ogc:PropertyName>'
+ '<ogc:Function name="collectGeometries">'
+ '<ogc:Function name="queryCollection">'
+ '<ogc:Literal>regions</ogc:Literal>'
+ '<ogc:Literal>regions_geom</ogc:Literal>'
+ '<ogc:Literal>area > 10</ogc:Literal>'
+ '</ogc:Function></ogc:Function>'
+ "</ogc:Intersects>";

// 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);
});
});

0 comments on commit dacfe9f

Please sign in to comment.