Skip to content

Commit

Permalink
Fix #1692 WFS spatial query works only if geometry field name is the_…
Browse files Browse the repository at this point in the history
…geom (#1773)

* Added geometry attribute on feautere type selected

* Removed comment

* Modified wfsquery epic structure
  • Loading branch information
allyoucanmap authored and offtherailz committed May 3, 2017
1 parent 618c611 commit 3212993
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 77 deletions.
2 changes: 1 addition & 1 deletion web/client/actions/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function textSearch(format, url, startPosition, maxRecords, text, options) {
function addLayerAndDescribe(layer) {
return (dispatch, getState) => {
const state = getState();
const layers = state && state.layers;
const layers = state && state.layers && state.layers.flat;
const id = LayersUtils.getLayerId(layer, layers || []);
dispatch(addLayer({...layer, id}));
if (layer.type === 'wms') {
Expand Down
11 changes: 10 additions & 1 deletion web/client/actions/queryform.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const EXPAND_ATTRIBUTE_PANEL = 'EXPAND_ATTRIBUTE_PANEL';
const EXPAND_SPATIAL_PANEL = 'EXPAND_SPATIAL_PANEL';
const SELECT_SPATIAL_METHOD = 'SELECT_SPATIAL_METHOD';
const SELECT_SPATIAL_OPERATION = 'SELECT_SPATIAL_OPERATION';
const CHANGE_SPATIAL_ATTRIBUTE = 'CHANGE_SPATIAL_ATTRIBUTE';
const REMOVE_SPATIAL_SELECT = 'REMOVE_SPATIAL_SELECT';
const SHOW_SPATIAL_DETAILS = 'SHOW_SPATIAL_DETAILS';
// const QUERY_FORM_SEARCH = 'QUERY_FORM_SEARCH';
Expand Down Expand Up @@ -133,6 +134,13 @@ function selectSpatialOperation(operation, fieldName) {
};
}

function changeSpatialAttribute(attribute) {
return {
type: CHANGE_SPATIAL_ATTRIBUTE,
attribute
};
}

function removeSpatialSelection() {
return {
type: REMOVE_SPATIAL_SELECT
Expand All @@ -159,7 +167,6 @@ function changeDwithinValue(distance) {
response: response
};
}
function wfsLoadError(e) {
return {
type: WFS_LOAD_ERROR,
Expand Down Expand Up @@ -297,6 +304,7 @@ module.exports = {
EXPAND_SPATIAL_PANEL,
SELECT_SPATIAL_METHOD,
SELECT_SPATIAL_OPERATION,
CHANGE_SPATIAL_ATTRIBUTE,
REMOVE_SPATIAL_SELECT,
SHOW_SPATIAL_DETAILS,
// QUERY_FORM_SEARCH,
Expand Down Expand Up @@ -333,6 +341,7 @@ module.exports = {
expandSpatialFilterPanel,
selectSpatialMethod,
selectSpatialOperation,
changeSpatialAttribute,
removeSpatialSelection,
showSpatialSelectionDetails,
query,
Expand Down
23 changes: 2 additions & 21 deletions web/client/actions/wfsquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,6 @@ function queryError(error) {
};
}

function describeFeatureType(baseUrl, typeName) {
return (dispatch) => {
return axios.get(baseUrl + '?service=WFS&version=1.1.0&request=DescribeFeatureType&typeName=' + typeName + '&outputFormat=application/json').then((response) => {
if (typeof response.data === 'object') {
dispatch(featureTypeLoaded(typeName, response.data));
} else {
try {
JSON.parse(response.data);
} catch(e) {
dispatch(featureTypeError(typeName, 'Error from WFS: ' + e.message));
}

}

}).catch((e) => {
dispatch(featureTypeError(typeName, e));
});
};
}

function loadFeature(baseUrl, typeName) {
return (dispatch) => {
return axios.get(baseUrl + '?service=WFS&version=1.1.0&request=GetFeature&typeName=' + typeName + '&outputFormat=application/json').then((response) => {
Expand Down Expand Up @@ -196,7 +176,8 @@ module.exports = {
QUERY_ERROR,
RESET_QUERY,
featureTypeSelected,
describeFeatureType,
featureTypeLoaded,
featureTypeError,
loadFeature,
createQuery,
query,
Expand Down
16 changes: 1 addition & 15 deletions web/client/components/data/query/QueryBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ const QueryBuilder = React.createClass({
onUpdateLogicCombo: () => {},
onRemoveGroupField: () => {},
onChangeCascadingValue: () => {},
onExpandAttributeFilterPanel: () => {},
onLoadFeatureTypeConfig: () => {}
onExpandAttributeFilterPanel: () => {}
},
spatialFilterActions: {
onExpandSpatialFilterPanel: () => {},
Expand All @@ -107,19 +106,6 @@ const QueryBuilder = React.createClass({
}
};
},
componentDidMount() {
if (this.props.featureTypeConfigUrl && this.props.attributes.length < 1) {
this.props.attributeFilterActions.onLoadFeatureTypeConfig(
this.props.featureTypeConfigUrl, this.props.params);
}
},
componentWillReceiveProps(props) {
let url = props.featureTypeConfigUrl;
let params = props.params !== this.props.params ? props.params : this.props.params;
if (url !== this.props.featureTypeConfigUrl) {
this.props.attributeFilterActions.onLoadFeatureTypeConfig(url, params);
}
},
render() {
if (this.props.featureTypeError !== "") {
return (<div style={{margin: "0 auto", "text-align": "center"}}>{this.props.featureTypeErrorText}</div>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,13 @@ describe('QueryBuilder', () => {

it('creates the QueryBuilder component in error state', () => {

let attributeFilterActions = {
onLoadFeatureTypeConfig: () => {}
};
let spy = expect.spyOn(attributeFilterActions, 'onLoadFeatureTypeConfig');

const querybuilder = ReactDOM.render(<QueryBuilder
featureTypeError={"true"}
featureTypeErrorText={"bla bla"}
attributeFilterActions={attributeFilterActions}
featureTypeConfigUrl={"randomurl"} />,
document.getElementById("container"));

expect(querybuilder).toExist();
expect(spy.calls.length).toEqual(1);
});

it('creates the QueryBuilder component with empty filter support', () => {
Expand Down
77 changes: 77 additions & 0 deletions web/client/epics/wfsquery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2017, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

const Rx = require('rxjs');
const axios = require('../libs/ajax');
const {changeSpatialAttribute} = require('../actions/queryform');
const {FEATURE_TYPE_SELECTED, featureTypeLoaded, featureTypeError} = require('../actions/wfsquery');

const types = {
'xsd:string': 'string',
'xsd:dateTime': 'date',
'xsd:number': 'number',
'xsd:int': 'number'
};
const fieldConfig = {};
const extractInfo = (data) => {
return {
geometry: data.featureTypes[0].properties
.filter((attribute) => attribute.type.indexOf('gml:') === 0)
.map((attribute) => {
let conf = {
label: attribute.name,
attribute: attribute.name,
type: 'geometry',
valueId: "id",
valueLabel: "name",
values: []
};
conf = fieldConfig[attribute.name] ? {...conf, ...fieldConfig[attribute.name]} : conf;
return conf;
}),
attributes: data.featureTypes[0].properties
.filter((attribute) => attribute.type.indexOf('gml:') !== 0)
.map((attribute) => {
let conf = {
label: attribute.name,
attribute: attribute.name,
type: types[attribute.type],
valueId: "id",
valueLabel: "name",
values: []
};
conf = fieldConfig[attribute.name] ? {...conf, ...fieldConfig[attribute.name]} : conf;
return conf;
})
};
};

const featureTypeSelectedEpic = action$ =>
action$.ofType(FEATURE_TYPE_SELECTED).switchMap(action => {
return Rx.Observable.defer( () =>
axios.get(action.url + '?service=WFS&version=1.1.0&request=DescribeFeatureType&typeName=' + action.typeName + '&outputFormat=application/json'))
.map((response) => {
if (typeof response.data === 'object' && response.data.featureTypes && response.data.featureTypes[0]) {
const info = extractInfo(response.data);
const geometry = info.geometry[0] && info.geometry[0].attribute ? info.geometry[0].attribute : 'the_geom';
return Rx.Observable.from([featureTypeLoaded(action.typeName, info), changeSpatialAttribute(geometry)]);
}
try {
JSON.parse(response.data);
} catch(e) {
return Rx.Observable.from([featureTypeError(action.typeName, 'Error from WFS: ' + e.message)]);
}
return Rx.Observable.from([featureTypeError(action.typeName, 'Error: feature types are empty')]);
})
.mergeAll()
.catch(e => Rx.Observable.of(featureTypeError(action.typeName, e.message)));
});

module.exports = {
featureTypeSelectedEpic
};
5 changes: 4 additions & 1 deletion web/client/plugins/QueryPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const LayersUtils = require('../utils/LayersUtils');
// include application component
const QueryBuilder = require('../components/data/query/QueryBuilder');

const {featureTypeSelectedEpic} = require('../epics/wfsquery');

const {bindActionCreators} = require('redux');
const {
// QueryBuilder action functions
Expand Down Expand Up @@ -234,5 +236,6 @@ module.exports = {
reducers: {
queryform: require('../reducers/queryform'),
query: require('../reducers/query')
}
},
epics: {featureTypeSelectedEpic}
};
5 changes: 1 addition & 4 deletions web/client/plugins/TOC.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const {
zoneChange
} = require('../actions/queryform');

const {createQuery, toggleQueryPanel, describeFeatureType} = require('../actions/wfsquery');
const {createQuery, toggleQueryPanel} = require('../actions/wfsquery');

const {
changeDrawingStatus,
Expand Down Expand Up @@ -92,9 +92,6 @@ const SmartQueryForm = connect((state) => {
return {

attributeFilterActions: bindActionCreators({
onLoadFeatureTypeConfig: (url, params) => {
return describeFeatureType(url, params.typeName);
},
onAddGroupField: addGroupField,
onAddFilterField: addFilterField,
onRemoveFilterField: removeFilterField,
Expand Down
28 changes: 1 addition & 27 deletions web/client/reducers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,6 @@ const {RESET_CONTROLS} = require('../actions/controls');

const assign = require('object-assign');

const types = {
'xsd:string': 'string',
'xsd:dateTime': 'date',
'xsd:number': 'number',
'xsd:int': 'number'
};
const fieldConfig = {};
const extractInfo = (featureType) => {
return {
attributes: featureType.featureTypes[0].properties
.filter((attribute) => attribute.type.indexOf('gml:') !== 0)
.map((attribute) => {
let conf = {
label: attribute.name,
attribute: attribute.name,
type: types[attribute.type],
valueId: "id",
valueLabel: "name",
values: []
};
conf = fieldConfig[attribute.name] ? {...conf, ...fieldConfig[attribute.name]} : conf;
return conf;
})
};
};

const extractData = (feature) => {
return ['STATE_NAME', 'STATE_ABBR', 'SUB_REGION', 'STATE_FIPS' ].map((attribute) => ({
attribute,
Expand Down Expand Up @@ -86,7 +60,7 @@ function query(state = initialState, action) {
}
case FEATURE_TYPE_LOADED: {
return assign({}, state, {
featureTypes: assign({}, state.featureTypes, {[action.typeName]: extractInfo(action.featureType)})
featureTypes: assign({}, state.featureTypes, {[action.typeName]: action.featureType})
});
}
case FEATURE_TYPE_ERROR: {
Expand Down
4 changes: 4 additions & 0 deletions web/client/reducers/queryform.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
EXPAND_SPATIAL_PANEL,
SELECT_SPATIAL_METHOD,
SELECT_SPATIAL_OPERATION,
CHANGE_SPATIAL_ATTRIBUTE,
REMOVE_SPATIAL_SELECT,
SHOW_SPATIAL_DETAILS,
QUERY_FORM_RESET,
Expand Down Expand Up @@ -167,6 +168,9 @@ function queryform(state = initialState, action) {
case SELECT_SPATIAL_OPERATION: {
return assign({}, state, {spatialField: assign({}, state.spatialField, {[action.fieldName]: action.operation})});
}
case CHANGE_SPATIAL_ATTRIBUTE: {
return assign({}, state, { spatialField: assign({}, state.spatialField, {attribute: action.attribute}) });
}
case CHANGE_DRAWING_STATUS: {
if (action.owner === "queryform" && action.status === "start") {
return assign({}, state, {toolbarEnabled: false});
Expand Down

0 comments on commit 3212993

Please sign in to comment.