Implement circle filter for dataviews
This commit is contained in:
parent
0940158d01
commit
17f151cd5a
@ -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
|
||||||
|
@ -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;
|
||||||
|
58
lib/models/filter/circle.js
Normal file
58
lib/models/filter/circle.js
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
@ -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 }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user