Implement circle filter for dataviews

This commit is contained in:
Daniel García Aubert 2019-12-02 18:36:41 +01:00
parent 0940158d01
commit 17f151cd5a
5 changed files with 75 additions and 13 deletions

View File

@ -18,6 +18,7 @@ const ALLOWED_DATAVIEW_QUERY_PARAMS = [
'own_filter', // 0, 1 'own_filter', // 0, 1
'no_filters', // 0, 1 'no_filters', // 0, 1
'bbox', // w,s,e,n 'bbox', // w,s,e,n
'circle', // json
'start', // number 'start', // number
'end', // number 'end', // number
'column_type', // string 'column_type', // string

View File

@ -3,6 +3,7 @@
var _ = require('underscore'); var _ = require('underscore');
var PSQL = require('cartodb-psql'); var PSQL = require('cartodb-psql');
var BBoxFilter = require('../models/filter/bbox'); var BBoxFilter = require('../models/filter/bbox');
const CircleFilter = require('../models/filter/circle');
var DataviewFactory = require('../models/dataview/factory'); var DataviewFactory = require('../models/dataview/factory');
var DataviewFactoryWithOverviews = require('../models/dataview/overviews/factory'); var DataviewFactoryWithOverviews = require('../models/dataview/overviews/factory');
const dbParamsFromReqParams = require('../utils/database-params'); const dbParamsFromReqParams = require('../utils/database-params');
@ -86,6 +87,9 @@ function getQueryWithFilters (dataviewDefinition, params) {
if (params.bbox) { if (params.bbox) {
var bboxFilter = new BBoxFilter({ column: 'the_geom_webmercator', srid: 3857 }, { bbox: params.bbox }); var bboxFilter = new BBoxFilter({ column: 'the_geom_webmercator', srid: 3857 }, { bbox: params.bbox });
query = bboxFilter.sql(query); query = bboxFilter.sql(query);
} else if (params.circle) {
const circleFilter = new CircleFilter({ column: 'the_geom_webmercator', srid: 3857 }, { circle: params.circle });
query = circleFilter.sql(query);
} }
return query; return query;
@ -197,6 +201,9 @@ function getQueryWithOwnFilters (dataviewDefinition, params) {
if (params.bbox) { if (params.bbox) {
var bboxFilter = new BBoxFilter({ column: 'the_geom', srid: 4326 }, { bbox: params.bbox }); var bboxFilter = new BBoxFilter({ column: 'the_geom', srid: 4326 }, { bbox: params.bbox });
query = bboxFilter.sql(query); query = bboxFilter.sql(query);
} else if (params.circle) {
const circleFilter = new CircleFilter({ column: 'the_geom', srid: 4326 }, { circle: params.circle });
query = circleFilter.sql(query);
} }
return query; return query;

View File

@ -0,0 +1,58 @@
'use strict';
const debug = require('debug')('windshaft:filter:circle');
function filterQueryTpl ({ sql, column, srid, lng, lat, radius } = {}) {
return `
SELECT
*
FROM (${sql}) _cdb_circle_filter
WHERE
ST_Intersects(
${column},
ST_Buffer(
ST_Transform(
ST_SetSRID(ST_Point(${lng},${lat}), 4326),
${srid}
),
${radius}
)
)
`;
}
module.exports = class CircleFilter {
constructor (filterDefinition, filterParams) {
const { circle } = filterParams;
if (!circle) {
throw new Error('Circle filter expects to have a "circle" param');
}
const { lng, lat, radius } = JSON.parse(circle);
if (!Number.isFinite(lng) || !Number.isFinite(lat) || !Number.isFinite(radius)) {
throw new Error('Missing parameter for Circle Filter, expected: "lng", "lat", and "radius"');
}
this.column = filterDefinition.column || 'the_geom_webmercator';
this.srid = filterDefinition.srid || 3857;
this.lng = lng;
this.lat = lat;
this.radius = radius;
}
sql (rawSql) {
const circleSql = filterQueryTpl({
sql: rawSql,
column: this.column,
srid: this.srid,
lng: this.lng,
lat: this.lat,
radius: this.radius
});
debug(circleSql);
return circleSql;
}
};

View File

@ -77,8 +77,7 @@ describe('circle filter', function () {
const scenarios = [ const scenarios = [
{ {
params: { params: JSON.stringify({}),
},
expected: { expected: {
type: 'aggregation', type: 'aggregation',
aggregation: 'sum', aggregation: 'sum',
@ -99,27 +98,24 @@ describe('circle filter', function () {
}, },
{ {
params: { params: {
circle: { circle: JSON.stringify({
lat: 0, lat: 0,
lng: 0, lng: 0,
radius: 5000 radius: 5000
} })
}, },
expected: { expected: {
type: 'aggregation', type: 'aggregation',
aggregation: 'sum', aggregation: 'sum',
count: 21, count: 1,
nulls: 0, nulls: 0,
nans: 0, nans: 0,
infinities: 0, infinities: 0,
min: 5, min: 1,
max: 40, max: 1,
categoriesCount: 4, categoriesCount: 1,
categories: [ categories: [
{ category: 'category_4', value: 40, agg: false }, { category: 'category_1', value: 1, agg: false }
{ category: 'category_3', value: 9, agg: false },
{ category: 'category_2', value: 6, agg: false },
{ category: 'category_1', value: 5, agg: false }
] ]
} }
} }

View File

@ -485,7 +485,7 @@ TestClient.prototype.getDataview = function (dataviewName, params, callback) {
urlParams.own_filter = params.own_filter; urlParams.own_filter = params.own_filter;
} }
['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function (extraParam) { ['bbox', 'circle', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function (extraParam) {
if (Object.prototype.hasOwnProperty.call(params, extraParam)) { if (Object.prototype.hasOwnProperty.call(params, extraParam)) {
urlParams[extraParam] = params[extraParam]; urlParams[extraParam] = params[extraParam];
} }