Merge pull request #809 from CartoDB/analyses-filters-params

Add `no_filters` param to dataviews
This commit is contained in:
Ivan Malagon 2017-12-15 11:13:56 +01:00 committed by GitHub
commit 8e9f61f9f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 285 additions and 14 deletions

View File

@ -4,7 +4,8 @@
Released 2017-mm-dd Released 2017-mm-dd
Announcements: Announcements:
- Logging all errors - Logging all errors.
- Histograms: Now they accept a `no_filters` parameter.
## 4.4.0 ## 4.4.0
Released 2017-12-12 Released 2017-12-12

View File

@ -37,12 +37,19 @@ DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, param
throw new Error("Dataview '" + dataviewName + "' does not exists"); throw new Error("Dataview '" + dataviewName + "' does not exists");
} }
var pg = new PSQL(dbParamsFromReqParams(params));
var ownFilter = +params.own_filter; var ownFilter = +params.own_filter;
ownFilter = !!ownFilter; var noFilters = +params.no_filters;
if (Number.isFinite(ownFilter) && Number.isFinite(noFilters)) {
err = new Error();
err.message = 'Both own_filter and no_filters cannot be sent in the same request';
err.type = 'dataview';
err.http_status = 400;
return callback(err);
}
var query = (ownFilter) ? dataviewDefinition.sql.own_filter_on : dataviewDefinition.sql.own_filter_off; var pg = new PSQL(dbParamsFromReqParams(params));
var query = getDataviewQuery(dataviewDefinition, ownFilter, noFilters);
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);
@ -55,7 +62,7 @@ DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, param
); );
var dataview = dataviewFactory.getDataview(query, dataviewDefinition); var dataview = dataviewFactory.getDataview(query, dataviewDefinition);
dataview.getResult(pg, getOverrideParams(params, ownFilter), this); dataview.getResult(pg, getOverrideParams(params, !!ownFilter), this);
}, },
function returnCallback(err, result) { function returnCallback(err, result) {
return callback(err, result); return callback(err, result);
@ -63,6 +70,16 @@ DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, param
); );
}; };
function getDataviewQuery(dataviewDefinition, ownFilter, noFilters) {
if (noFilters) {
return dataviewDefinition.sql.no_filters;
} else if (ownFilter === 1) {
return dataviewDefinition.sql.own_filter_on;
} else {
return dataviewDefinition.sql.own_filter_off;
}
}
function getQueryRewriteData(mapConfig, dataviewDefinition, params) { function getQueryRewriteData(mapConfig, dataviewDefinition, params) {
var sourceId = dataviewDefinition.source.id; // node.id var sourceId = dataviewDefinition.source.id; // node.id
var layer = _.find(mapConfig.obj().layers, function(l) { var layer = _.find(mapConfig.obj().layers, function(l) {

View File

@ -106,6 +106,7 @@ LayergroupController.prototype.register = function(app) {
var allowedDataviewQueryParams = [ var allowedDataviewQueryParams = [
'filters', // json 'filters', // json
'own_filter', // 0, 1 'own_filter', // 0, 1
'no_filters', // 0, 1
'bbox', // w,s,e,n 'bbox', // w,s,e,n
'start', // number 'start', // number
'end', // number 'end', // number

View File

@ -58,6 +58,13 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi
requestMapConfig = appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId); requestMapConfig = appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId);
// Expected format for analyses filters
// filters = {analyses: {
// a1: [{min, max}, {accept, reject}],
// b1: [{range, column, min, max}, {category, column, accept, reject}]
// }}
requestMapConfig = appendFiltersToNodes(requestMapConfig, filters.analyses);
function createAnalysis(analysisDefinition, done) { function createAnalysis(analysisDefinition, done) {
self.analysisBackend.create(analysisConfiguration, analysisDefinition, function (err, analysis) { self.analysisBackend.create(analysisConfiguration, analysisDefinition, function (err, analysis) {
if (err) { if (err) {
@ -200,6 +207,7 @@ function dataviewQuery(node, dataviewName, ownFilter) {
function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) { function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) {
var analyses = requestMapConfig.analyses || []; var analyses = requestMapConfig.analyses || [];
dataviewsFiltersBySourceId = dataviewsFiltersBySourceId || {};
requestMapConfig.analyses = analyses.map(function(analysisDefinition) { requestMapConfig.analyses = analyses.map(function(analysisDefinition) {
var analysisGraph = new camshaft.reference.AnalysisGraph(analysisDefinition); var analysisGraph = new camshaft.reference.AnalysisGraph(analysisDefinition);

View File

@ -19,7 +19,9 @@
"Sandro Santilli <strk@vizzuality.com>", "Sandro Santilli <strk@vizzuality.com>",
"Carlos Matallín <matallo@carto.com>", "Carlos Matallín <matallo@carto.com>",
"Daniel Garcia Aubert <dgaubert@carto.com>", "Daniel Garcia Aubert <dgaubert@carto.com>",
"Mario de Frutos <mario.defrutos@carto.com>" "Mario de Frutos <mario.defrutos@carto.com>",
"Ivan Malagon <ivan@carto.com>",
"Simon Martin <simon@carto.com>"
], ],
"dependencies": { "dependencies": {
"body-parser": "^1.18.2", "body-parser": "^1.18.2",

View File

@ -0,0 +1,150 @@
require('../../support/test_helper');
const assert = require('../../support/assert');
const TestClient = require('../../support/test-client');
describe('analysis-filters-params', () => {
const CARTOCSS = `#layer {
marker-fill-opacity: 1;
marker-line-color: white;
marker-line-width: 0.5;
marker-line-opacity: 1;
marker-placement: point;
marker-type: ellipse;
marker-width: 8;
marker-fill: red;
marker-allow-overlap: true;
}`;
const mapConfig = {
version: '1.6.0',
layers: [
{
"type": "cartodb",
"options": {
"source": {
"id": "a1"
},
"cartocss": CARTOCSS,
"cartocss_version": "2.3.0"
}
}
],
dataviews: {
pop_max_histogram: {
source: {
id: 'a1'
},
type: 'histogram',
options: {
column: 'pop_max'
}
},
pop_min_histogram: {
source: {
id: 'a1'
},
type: 'histogram',
options: {
column: 'pop_min'
}
}
},
analyses: [
{
"id": "a1",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
]
};
var params = {
filters: {
dataviews: {
pop_max_histogram: {
min: 2e6
},
pop_min_histogram: {
max: 2e6
}
}
}
};
it('should get a filtered histogram dataview with all filters', function(done) {
const testClient = new TestClient(mapConfig, 1234);
const testParams = Object.assign({}, params, {
own_filter: 1
});
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 6);
testClient.drain(done);
});
});
it('should get a filtered histogram dataview with all filters except my own filter', function(done) {
const testClient = new TestClient(mapConfig, 1234);
const testParams = Object.assign({}, params, {
own_filter: 0
});
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 24);
testClient.drain(done);
});
});
it('should get a filtered histogram dataview without filters', function(done) {
const testClient = new TestClient(mapConfig, 1234);
const testParams = Object.assign({}, params, {
no_filters: 1
});
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 48);
testClient.drain(done);
});
});
it('should return an error if both no_filters and own_filter params are present', function (done) {
const testClient = new TestClient(mapConfig, 1234);
const expectedError = {
errors: ['Both own_filter and no_filters cannot be sent in the same request'],
errors_with_context: [{
type: 'dataview',
message: 'Both own_filter and no_filters cannot be sent in the same request'
}]
};
const testParams = Object.assign({}, params, {
no_filters: 1,
own_filter: 0,
response: {
status: 400
}
});
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.deepEqual(dataview, expectedError);
testClient.drain(done);
});
});
});

View File

@ -0,0 +1,84 @@
require('../../support/test_helper');
const assert = require('../../support/assert');
const TestClient = require('../../support/test-client');
describe('analysis-layers-dataviews', () => {
const CARTOCSS = `#layer {
marker-fill-opacity: 1;
marker-line-color: white;
marker-line-width: 0.5;
marker-line-opacity: 1;
marker-placement: point;
marker-type: ellipse;
marker-width: 8;
marker-fill: red;
marker-allow-overlap: true;
}`;
const mapConfig = {
version: '1.6.0',
layers: [
{
"type": "cartodb",
"options": {
"source": {
"id": "a1"
},
"cartocss": CARTOCSS,
"cartocss_version": "2.3.0"
}
}
],
dataviews: {
pop_max_histogram: {
source: {
id: 'a1'
},
type: 'histogram',
options: {
column: 'pop_max'
}
}
},
analyses: [
{
"id": "a1",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
]
};
it('should get a filtered histogram dataview', function(done) {
const testClient = new TestClient(mapConfig, 1234);
const params = {
filters: {
analyses: {
'a1': [
{
type: 'range',
column: 'pop_max',
params: {
min: 2e6
}
}
]
}
}
};
testClient.getDataview('pop_max_histogram', params, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 2008000);
testClient.drain(done);
});
});
});

View File

@ -109,7 +109,8 @@ describe('analysis-layers-dataviews', function() {
min: 2e6 min: 2e6
} }
} }
} },
own_filter: 1
}; };
testClient.getDataview('pop_max_histogram', params, function(err, dataview) { testClient.getDataview('pop_max_histogram', params, function(err, dataview) {

View File

@ -393,7 +393,8 @@ describe('dataviews using tables with overviews', function() {
var params = { var params = {
filters: { filters: {
dataviews: { test_histogram: { min: 2 } } dataviews: { test_histogram: { min: 2 } }
} },
own_filter: 1
}; };
var testClient = new TestClient(overviewsMapConfig); var testClient = new TestClient(overviewsMapConfig);
testClient.getDataview('test_histogram', params, function (err, histogram) { testClient.getDataview('test_histogram', params, function (err, histogram) {
@ -412,7 +413,8 @@ describe('dataviews using tables with overviews', function() {
var params = { var params = {
filters: { filters: {
dataviews: { test_histogram: { max: -1 } } dataviews: { test_histogram: { max: -1 } }
} },
own_filter: 1
}; };
var testClient = new TestClient(overviewsMapConfig); var testClient = new TestClient(overviewsMapConfig);
testClient.getDataview('test_histogram', params, function (err, histogram) { testClient.getDataview('test_histogram', params, function (err, histogram) {
@ -433,7 +435,8 @@ describe('dataviews using tables with overviews', function() {
var params = { var params = {
filters: { filters: {
dataviews: { test_histogram_date: { max: -1 } } dataviews: { test_histogram_date: { max: -1 } }
} },
own_filter: 1
}; };
var testClient = new TestClient(overviewsMapConfig); var testClient = new TestClient(overviewsMapConfig);
testClient.getDataview('test_histogram_date', params, function (err, histogram) { testClient.getDataview('test_histogram_date', params, function (err, histogram) {

View File

@ -411,9 +411,13 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) {
self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0; self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
self.keysToDelete['user:localhost:mapviews:global'] = 5; self.keysToDelete['user:localhost:mapviews:global'] = 5;
var urlParams = { var urlParams = {};
own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1 if (params.hasOwnProperty('no_filters')) {
}; urlParams.no_filters = params.no_filters;
}
if (params.hasOwnProperty('own_filter')) {
urlParams.own_filter = params.own_filter;
}
['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function(extraParam) { ['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function(extraParam) {
if (params.hasOwnProperty(extraParam)) { if (params.hasOwnProperty(extraParam)) {