diff --git a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js index 46f5185a..b6fca095 100644 --- a/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/analysis-mapconfig-adapter.js @@ -125,10 +125,12 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi return layer; }); + debug('mapconfig output', JSON.stringify(requestMapConfig, null, 4)); - if (missingNodesErrors.length > 0) { - return callback(missingNodesErrors); + var missingDataviewsNodesErrors = getMissingDataviewsSourceIds(dataviews, sourceId2Node); + if (missingNodesErrors.length > 0 || missingDataviewsNodesErrors.length > 0) { + return callback(missingNodesErrors.concat(missingDataviewsNodesErrors)); } context.analysesResults = analysesResults; @@ -177,8 +179,9 @@ function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) { } function shouldAdaptLayers(requestMapConfig) { - return Array.isArray(requestMapConfig.layers) && - Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0; + return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId) || + (Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0) || + requestMapConfig.dataviews; } var DATAVIEW_TYPE_2_FILTER_TYPE = { @@ -270,3 +273,26 @@ function getDataviewsErrors(dataviews) { return errors; } + +function getMissingDataviewsSourceIds(dataviews, sourceId2Node) { + var missingDataviewsSourceIds = []; + Object.keys(dataviews).forEach(function(dataviewName) { + var dataview = dataviews[dataviewName]; + var dataviewSourceId = getDataviewSourceId(dataview); + if (!sourceId2Node.hasOwnProperty(dataviewSourceId)) { + missingDataviewsSourceIds.push(new AnalysisError('Node with `source.id="' + dataviewSourceId +'"`' + + ' not found in analyses for dataview "' + dataviewName + '"')); + } + }); + + return missingDataviewsSourceIds; +} + +function AnalysisError(message) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.type = 'analysis'; + this.message = message; +} + +require('util').inherits(AnalysisError, Error); \ No newline at end of file diff --git a/test/acceptance/analysis/error-cases.js b/test/acceptance/analysis/error-cases.js index c876f147..5a2628eb 100644 --- a/test/acceptance/analysis/error-cases.js +++ b/test/acceptance/analysis/error-cases.js @@ -72,6 +72,89 @@ describe('analysis-layers error cases', function() { }); }); + it('should handle missing analyses when layers point to nonexistent one', function(done) { + var mapConfig = createMapConfig( + [ + { + "type": "http", + "options": { + "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png", + "subdomains": "abcd" + } + }, + { + "type": "cartodb", + "options": { + "source": { + "id": "ID-FOR-NONEXISTENT-ANALYSIS" + }, + "cartocss": '#polygons { polygon-fill: red; }', + "cartocss_version": "2.3.0" + } + } + ] + ); + + var testClient = new TestClient(mapConfig, 1234); + + testClient.getLayergroup(ERROR_RESPONSE, function(err, layergroupResult) { + assert.ok(!err, err); + + assert.equal(layergroupResult.errors.length, 1); + assert.equal( + layergroupResult.errors[0], + 'Missing analysis node.id="ID-FOR-NONEXISTENT-ANALYSIS" for layer=1' + ); + + testClient.drain(done); + }); + }); + + it('should handle missing analyses when dataviews point to nonexistent one', function(done) { + var mapConfig = createMapConfig( + [ + { + "type": "http", + "options": { + "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png", + "subdomains": "abcd" + } + }, + { + "type": "cartodb", + "options": { + "sql": "select * from populated_places_simple_reduced", + "cartocss": '#polygons { polygon-fill: red; }', + "cartocss_version": "2.3.0" + } + } + ], + { + pop_max_histogram: { + source: { + id: 'ID-FOR-NONEXISTENT-ANALYSIS' + }, + type: 'histogram', + options: { + column: 'pop_max' + } + } + } + ); + + var testClient = new TestClient(mapConfig, 1234); + + testClient.getLayergroup(ERROR_RESPONSE, function(err, layergroupResult) { + assert.ok(!err, err); + + assert.equal(layergroupResult.errors.length, 1); + assert.equal(layergroupResult.errors[0], 'Node with `source.id="ID-FOR-NONEXISTENT-ANALYSIS"`' + + ' not found in analyses for dataview "pop_max_histogram"'); + + testClient.drain(done); + }); + }); + it('camshaft: should return error missing analysis nodes for layers with some context', function(done) { var mapConfig = createMapConfig( [