@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
226 lines (225 loc) • 10.3 kB
JavaScript
import { equalTo, greaterThan, greaterThanOrEqualTo, isNull, lessThan, lessThanOrEqualTo, like, not, notEqualTo, between, during } from 'ol/format/filter';
import { isStringNumeric, isString, isDate } from '../../models/xmlTypes';
export const wfsOperatorsStrList = [
'eq',
'neq',
'gt',
'gte',
'lt',
'lte',
'like',
'nlike',
'before',
'after',
'between',
'nul',
'nnul'
];
export const mapAttributeTypeToFilterOperators = {
string: ['eq', 'neq', 'like', 'nlike', 'nul', 'nnul'],
number: ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'nul', 'nnul'],
date: ['eq', 'neq', 'before', 'after', 'between', 'nnul']
};
export class WfsFilter {
constructor(property, operator, value, value2 = '', propertyType) {
Object.defineProperty(this, "property", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "propertyType", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "operator", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "value", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "value2", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "beginOfTime", {
enumerable: true,
configurable: true,
writable: true,
value: '0001-01-01'
});
Object.defineProperty(this, "endOfTime", {
enumerable: true,
configurable: true,
writable: true,
value: '9999-12-31'
});
this.property = property;
this.operator = operator;
this.value = value;
this.value2 = value2;
this.propertyType = propertyType;
if (this.operator === 'between' && !this.value2) {
throw new Error('Between operator needs two filter values !');
}
}
toOpenLayersFilter() {
if (!this.propertyType) {
throw new Error('The type of the property should never be null !');
}
//(this.property, this.value, propertyType)
switch (this.operator) {
case 'eq':
if (isString(this.propertyType) && isStringNumeric(this.value)) {
// See https://mapserver-users.osgeo.narkive.com/P0EVA6Qr/wfs-filter-creates-a-query-using-a-number-instead-of-text
return like(this.property, '*' + this.value + '*');
}
else {
return equalTo(this.property, this.value);
}
case 'neq':
if (isString(this.propertyType) && isStringNumeric(this.value)) {
// See https://mapserver-users.osgeo.narkive.com/P0EVA6Qr/wfs-filter-creates-a-query-using-a-number-instead-of-text
return not(like(this.property, '*' + this.value + '*'));
}
else if (isDate(this.propertyType)) {
// mapserver does not support notEqualTo for date values, see notes in https://www.mapserver.org/ogc/filter_encoding.html#tests
return not(equalTo(this.property, this.value));
}
else {
return notEqualTo(this.property, this.value);
}
case 'gt':
return greaterThan(this.property, Number(this.value));
case 'gte':
return greaterThanOrEqualTo(this.property, Number(this.value));
case 'lt':
return lessThan(this.property, Number(this.value));
case 'lte':
return lessThanOrEqualTo(this.property, Number(this.value));
case 'like':
return like(this.property, '*' + this.value + '*');
case 'nlike':
return not(like(this.property, '*' + this.value + '*'));
case 'before':
return during(this.property, this.beginOfTime, this.value);
case 'after':
return during(this.property, this.value, this.endOfTime);
case 'between':
if (isDate(this.propertyType)) {
return during(this.property, this.value, this.value2);
}
return between(this.property, Number(this.value), Number(this.value2));
case 'nul':
return isNull(this.property);
case 'nnul':
if (isDate(this.propertyType)) {
return notEqualTo(this.property, '');
}
return not(isNull(this.property));
default:
throw new Error('Unknown filter operator');
}
}
/**
*
* @returns a simple filter string that can be used in a WMS GetMap request, does not provide any XML namespace (xmlns attributes)
*/
toWmsGetMapFilter() {
if (!this.propertyType) {
throw new Error('The type of the property should never be null !');
}
const wildCard = WfsFilter.simpleLikeFilterGenerateWildCard(this.value);
switch (this.operator) {
case 'eq':
if (this.propertyType === 'string' && isStringNumeric(this.value)) {
// See https://mapserver-users.osgeo.narkive.com/P0EVA6Qr/wfs-filter-creates-a-query-using-a-number-instead-of-text
return WfsFilter.simpleLikeFilter(this.property, this.value);
}
else {
return WfsFilter.simpleEqFilter(this.property, this.value);
}
case 'neq':
if (this.propertyType === 'string' && isStringNumeric(this.value)) {
// See https://mapserver-users.osgeo.narkive.com/P0EVA6Qr/wfs-filter-creates-a-query-using-a-number-instead-of-text
return WfsFilter.simpleNlikeFilter(this.property, this.value);
}
else {
return WfsFilter.simpleNeqFilter(this.property, this.value);
}
case 'gt':
return WfsFilter.simpleGtFilter(this.property, this.value);
case 'gte':
return WfsFilter.simpleGteFilter(this.property, this.value);
case 'lt':
return WfsFilter.simpleLtFilter(this.property, this.value);
case 'lte':
return WfsFilter.simpleLteFilter(this.property, this.value);
case 'like':
return WfsFilter.simpleLikeFilter(this.property, wildCard + this.value + wildCard, wildCard);
case 'nlike':
return WfsFilter.simpleNlikeFilter(this.property, wildCard + this.value + wildCard, wildCard);
case 'before':
return WfsFilter.simpleLteFilter(this.property, this.value);
case 'after':
return WfsFilter.simpleGteFilter(this.property, this.value);
case 'between':
return WfsFilter.simpleBetweenFilter(this.property, this.value, this.value2);
case 'nul':
return WfsFilter.simpleEqFilter(this.property, '');
case 'nnul':
return WfsFilter.simpleNeqFilter(this.property, '');
default:
throw new Error('Unknown filter operator');
}
}
static simpleEqFilter(name, value) {
return `<Filter><PropertyIsEqualTo><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsEqualTo></Filter>`;
}
static simpleNeqFilter(name, value) {
return `<Filter><Not><PropertyIsEqualTo><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsEqualTo></Not></Filter>`;
}
static simpleLtFilter(name, value) {
return `<Filter><PropertyIsLessThan><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsLessThan></Filter>`;
}
static simpleLteFilter(name, value) {
return `<Filter><PropertyIsLessThanOrEqualTo><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsLessThanOrEqualTo></Filter>`;
}
static simpleGtFilter(name, value) {
return `<Filter><PropertyIsGreaterThan><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsGreaterThan></Filter>`;
}
static simpleGteFilter(name, value) {
return `<Filter><PropertyIsGreaterThanOrEqualTo><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsGreaterThanOrEqualTo></Filter>`;
}
static simpleBetweenFilter(name, value, value2) {
return `<Filter><And><PropertyIsGreaterThanOrEqualTo><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsGreaterThanOrEqualTo><PropertyIsLessThanOrEqualTo><PropertyName>${name}</PropertyName><Literal>${value2}</Literal></PropertyIsLessThanOrEqualTo></And></Filter>`;
}
static simpleInnerLikeFilter(name, value, wildCard) {
if (!wildCard) {
wildCard = WfsFilter.simpleLikeFilterGenerateWildCard(value);
}
return `<PropertyIsLike wildCard="${wildCard}" singleChar="." escapeChar="!"><PropertyName>${name}</PropertyName><Literal>${value}</Literal></PropertyIsLike>`;
}
static simpleLikeFilter(name, value, wildCard) {
return '<Filter>' + this.simpleInnerLikeFilter(name, value, wildCard) + '</Filter>';
}
static simpleNlikeFilter(name, value, wildCard) {
return '<Filter><Not>' + this.simpleInnerLikeFilter(name, value, wildCard) + '</Not></Filter>';
}
// TODO: make wildcard/escape/single char configurable in config.json/themes.json?
// Here is a quickfix for map.bs.ch not accepting * in url params
static simpleLikeFilterGenerateWildCard(value) {
return 'WABCDEFGIJKLMNOPQRSTUVXYZ'.split('').find((c) => !value.includes(c)) ?? '*';
}
}
export default WfsFilter;