diff --git a/lib/models/dataview/overviews/aggregation.js b/lib/models/dataview/overviews/aggregation.js index 1d0f7de6..bc0b9116 100644 --- a/lib/models/dataview/overviews/aggregation.js +++ b/lib/models/dataview/overviews/aggregation.js @@ -94,6 +94,8 @@ var CATEGORIES_LIMIT = 6; function Aggregation(query, options, queryRewriter, queryRewriteData, params, queries) { BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params, queries); + this._checkOptions(options); + this.query = query; this.queries = queries; this.column = options.column; @@ -219,6 +221,26 @@ var aggregationFnQueryTpl = { sum: dot.template('sum({{=it._aggregationColumn}}*_feature_count)') }; +const VALID_OPERATIONS = { + count: [], + sum: ['aggregationColumn'] +}; + +Aggregation.prototype._checkOptions = function (options) { + if (!VALID_OPERATIONS[options.aggregation]) { + throw new Error(`Aggregation does not support '${options.aggregation}' operation in dataview overview options`); + } + + const requiredOptions = VALID_OPERATIONS[options.aggregation]; + const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption)); + + if (missingOptions.length > 0) { + throw new Error( + `Aggregation '${options.aggregation}' is missing some options for overview: ${missingOptions.join(',')}` + ); + } +}; + Aggregation.prototype.getAggregationSql = function() { return aggregationFnQueryTpl[this.aggregation]({ _aggregationFn: this.aggregation, diff --git a/test/acceptance/dataviews/overviews-test.js b/test/acceptance/dataviews/overviews-test.js index 8df298b3..ea688882 100644 --- a/test/acceptance/dataviews/overviews-test.js +++ b/test/acceptance/dataviews/overviews-test.js @@ -665,6 +665,194 @@ describe('dataviews using tables with overviews', function() { }); }); }); + + describe.only('agreggation validation', function (){ + const params = { + response: { + status: 400, + headers: { + 'Content-Type': 'application/json; charset=utf-8' + } + } + }; + + function createMapConfig(options) { + return { + version: '1.5.0', + analyses: [ + { id: 'data-source', + type: 'source', + params: { + query: 'select * from test_table_overviews' + } + }, + { + id: 'data-source-special-float-values', + type: 'source', + params: { + query: 'select * from test_special_float_values_table_overviews' + } + } + ], + dataviews: { + test_invalid_aggregation: { + type: 'aggregation', + source: {id: 'data-source'}, + options: options + } + }, + layers: [ + { + type: 'mapnik', + options: { + sql: 'select * from test_table_overviews', + cartocss: '#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }', + cartocss_version: '2.3.0', + source: { id: 'data-source' } + } + }, + { + type: 'mapnik', + options: { + sql: 'select * from test_special_float_values_table_overviews', + cartocss: '#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }', + cartocss_version: '2.3.0', + source: { + id: 'data-source-special-float-values' + } + } + } + ] + }; + } + + it('should fail if missing column', function (done) { + var options = { + aggregation: "sum", + aggregationColumn: "value" + }; + var missingCOlumnMapConfig = createMapConfig(options); + + var testClient = new TestClient(missingCOlumnMapConfig); + testClient.getDataview('test_invalid_aggregation', params, function (err, dataview) { + if (err) { + return done(err); + } + + assert.deepStrictEqual(dataview, { + errors: ["Aggregation expects 'column' in dataview options"], + errors_with_context: [{ + type: 'unknown', + message: "Aggregation expects 'column' in dataview options" + }] + }); + + testClient.drain(done); + }); + }); + + it('should fail if no aggregation operation', function (done) { + var options = { + column: "value", + aggregationColumn: "value" + }; + var missingOperationMapConfig = createMapConfig(options); + + var testClient = new TestClient(missingOperationMapConfig); + testClient.getDataview('test_invalid_aggregation', params, function (err, dataview) { + if (err) { + return done(err); + } + + assert.deepStrictEqual(dataview, { + errors: ["Aggregation expects 'aggregation' operation in dataview options"], + errors_with_context: [{ + type: 'unknown', + message: "Aggregation expects 'aggregation' operation in dataview options" + }] + }); + + testClient.drain(done); + }); + }); + + it('should fail if fake operation', function (done) { + var options = { + column: "value", + aggregation: "wadus", + aggregationColumn: "value" + }; + var wrongOperationMapConfig = createMapConfig(options); + + var testClient = new TestClient(wrongOperationMapConfig); + testClient.getDataview('test_invalid_aggregation', params, function (err, dataview) { + if (err) { + return done(err); + } + + assert.deepStrictEqual(dataview, { + errors: ["Aggregation does not support 'wadus' operation"], + errors_with_context: [{ + type: 'unknown', + message: "Aggregation does not support 'wadus' operation" + }] + }); + + testClient.drain(done); + }); + }); + + it('should fail if invalid operation for overview', function (done) { + var options = { + column: "value", + aggregation: "avg", + aggregationColumn: "value" + }; + var wrongOperationMapConfig = createMapConfig(options); + + var testClient = new TestClient(wrongOperationMapConfig); + testClient.getDataview('test_invalid_aggregation', params, function (err, dataview) { + if (err) { + return done(err); + } + + assert.deepStrictEqual(dataview, { + errors: ["Aggregation does not support 'avg' operation in dataview overview options"], + errors_with_context: [{ + type: 'unknown', + message: "Aggregation does not support 'avg' operation in dataview overview options" + }] + }); + + testClient.drain(done); + }); + }); + + it('should fail if no aggregation column when needed', function (done) { + var options = { + column: "value", + aggregation: "sum" + }; + var missingOptionMapConfig = createMapConfig(options); + + var testClient = new TestClient(missingOptionMapConfig); + testClient.getDataview('test_invalid_aggregation', params, function (err, dataview) { + if (err) { + return done(err); + } + + assert.deepStrictEqual(dataview, { + errors: ["Aggregation 'sum' is missing some options: aggregationColumn"], + errors_with_context: [{ + type: 'unknown', + message: "Aggregation 'sum' is missing some options: aggregationColumn" + }] + }); + + testClient.drain(done); + }); + }); + }); }); });