diff --git a/NEWS.md b/NEWS.md index 6312c5bb..409b5ebc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,10 +1,11 @@ # Changelog -## 4.0.2 +## 4.1.0 Released 2017-mm-dd Announcements: - Upgrades windshaft to [4.0.1](https://github.com/CartoDB/windshaft/releases/tag/4.0.1). + - Add `categories` query param to define the number of categories to be ranked for aggregation dataviews. ## 4.0.1 diff --git a/lib/cartodb/backends/dataview.js b/lib/cartodb/backends/dataview.js index b6037ae6..9df22868 100644 --- a/lib/cartodb/backends/dataview.js +++ b/lib/cartodb/backends/dataview.js @@ -24,7 +24,7 @@ module.exports = DataviewBackend; DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, params, callback) { - var dataviewName = params.dataviewName; + var dataviewName = params.dataviewName; step( function getMapConfig() { mapConfigProvider.getMapConfig(this); @@ -94,7 +94,7 @@ function getQueryRewriteData(mapConfig, dataviewDefinition, params) { } function getOverrideParams(params, ownFilter) { - var overrideParams = _.reduce(_.pick(params, 'start', 'end', 'bins', 'offset'), + var overrideParams = _.reduce(_.pick(params, 'start', 'end', 'bins', 'offset', 'categories'), function castNumbers(overrides, val, k) { if (!Number.isFinite(+val)) { throw new Error('Invalid number format for parameter \'' + k + '\''); diff --git a/lib/cartodb/controllers/layergroup.js b/lib/cartodb/controllers/layergroup.js index d9551c9c..98616484 100644 --- a/lib/cartodb/controllers/layergroup.js +++ b/lib/cartodb/controllers/layergroup.js @@ -109,7 +109,8 @@ LayergroupController.prototype.register = function(app) { 'bins', // number 'aggregation', //string 'offset', // number - 'q' // widgets search + 'q', // widgets search + 'categories', // number ]; app.get( diff --git a/lib/cartodb/models/dataview/aggregation.js b/lib/cartodb/models/dataview/aggregation.js index b4c59af2..40774353 100644 --- a/lib/cartodb/models/dataview/aggregation.js +++ b/lib/cartodb/models/dataview/aggregation.js @@ -245,6 +245,10 @@ module.exports = class Aggregation extends BaseDataview { return null; } + const limit = Number.isFinite(override.categories) && override.categories > 0 ? + override.categories : + CATEGORIES_LIMIT; + const aggregationSql = aggregationDataviewQueryTpl({ override: override, query: this.query, @@ -256,7 +260,7 @@ module.exports = class Aggregation extends BaseDataview { aggregationColumn: this.aggregationColumn || 1 }), isFloatColumn: this._isFloatColumn, - limit: CATEGORIES_LIMIT + limit }); debug(aggregationSql); diff --git a/test/acceptance/dataviews/aggregation.js b/test/acceptance/dataviews/aggregation.js index d8d03177..e29d9ff4 100644 --- a/test/acceptance/dataviews/aggregation.js +++ b/test/acceptance/dataviews/aggregation.js @@ -324,3 +324,104 @@ describe('aggregation-dataview: special float values', function() { }); }); }); + +describe('aggregation dataview tuned by categories query param', function () { + const mapConfig = { + version: '1.5.0', + layers: [ + { + type: "cartodb", + options: { + source: { + "id": "a0" + }, + cartocss: "#points { marker-width: 10; marker-fill: red; }", + cartocss_version: "2.3.0" + } + } + ], + dataviews: { + categories: { + source: { + id: 'a0' + }, + type: 'aggregation', + options: { + column: 'cat', + aggregation: 'sum', + aggregationColumn: 'val' + } + } + }, + analyses: [ + { + id: "a0", + type: "source", + params: { + query: ` + SELECT + null::geometry the_geom_webmercator, + CASE + WHEN x % 4 = 0 THEN 1 + WHEN x % 4 = 1 THEN 2 + WHEN x % 4 = 2 THEN 3 + ELSE 4 + END AS val, + CASE + WHEN x % 4 = 0 THEN 'category_1' + WHEN x % 4 = 1 THEN 'category_2' + WHEN x % 4 = 2 THEN 'category_3' + ELSE 'category_4' + END AS cat + FROM generate_series(1, 1000) x + ` + } + } + ] + }; + + beforeEach(function () { + this.testClient = new TestClient(mapConfig, 1234); + }); + + afterEach(function (done) { + this.testClient.drain(done); + }); + + var scenarios = [ + { + params: { own_filter: 0, categories: -1 }, + categoriesExpected: 4 + }, + { + params: { own_filter: 0, categories: 0 }, + categoriesExpected: 4 + }, + { + params: { own_filter: 0, categories: 1 }, + categoriesExpected: 1 + }, + { + params: { own_filter: 0, categories: 2 }, + categoriesExpected: 2 + }, + { + params: { own_filter: 0, categories: 4 }, + categoriesExpected: 4 + }, + { + params: { own_filter: 0, categories: 5 }, + categoriesExpected: 4 + } + ]; + + scenarios.forEach(function (scenario) { + it(`should handle cartegories to customize aggregations: ${JSON.stringify(scenario.params)}`, function (done) { + this.testClient.getDataview('categories', scenario.params, (err, dataview) => { + assert.ifError(err); + assert.equal(dataview.categories.length, scenario.categoriesExpected); + done(); + }); + }); + }); +}); diff --git a/test/support/test-client.js b/test/support/test-client.js index cd7b4f60..f31f9db4 100644 --- a/test/support/test-client.js +++ b/test/support/test-client.js @@ -415,7 +415,7 @@ TestClient.prototype.getDataview = function(dataviewName, params, callback) { own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1 }; - ['bbox', 'bins', 'start', 'end', 'aggregation', 'offset'].forEach(function(extraParam) { + ['bbox', 'bins', 'start', 'end', 'aggregation', 'offset', 'categories'].forEach(function(extraParam) { if (params.hasOwnProperty(extraParam)) { urlParams[extraParam] = params[extraParam]; }