Implement circle filter for dataviews

remotes/origin/1117-camshaft-update
Daniel García Aubert 5 years ago
parent 0940158d01
commit 17f151cd5a

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

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

@ -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;
}
};

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

@ -485,7 +485,7 @@ TestClient.prototype.getDataview = function (dataviewName, params, callback) {
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)) {
urlParams[extraParam] = params[extraParam];
}

Loading…
Cancel
Save