Windshaft-cartodb/lib/cartodb/models/analysis_mapconfig_adapter.js
2016-03-22 12:22:04 +01:00

166 lines
5.5 KiB
JavaScript

var queue = require('queue-async');
var debug = require('debug')('windshaft:analysis');
var camshaft = require('camshaft');
var dot = require('dot');
dot.templateSettings.strip = false;
function AnalysisMapConfigAdapter(templateMaps) {
this.templateMaps = templateMaps;
}
module.exports = AnalysisMapConfigAdapter;
var SKIP_COLUMNS = {
'the_geom': true,
'the_geom_webmercator': true
};
function skipColumns(columnNames) {
return columnNames
.filter(function(columnName) { return !SKIP_COLUMNS[columnName]; });
}
var layerQueryTemplate = dot.template([
'SELECT ST_Transform(the_geom, 3857) the_geom_webmercator, {{=it._columns}}',
'FROM ({{=it._query}}) _cdb_analysis_query'
].join('\n'));
function layerQuery(query, columnNames) {
return layerQueryTemplate({ _query: query, _columns: skipColumns(columnNames).join(', ') });
}
function replaceSourceRootQueries(requestMapConfig, analysisToRemove) {
var analysisSourceRootsIds = requestMapConfig.analyses.reduce(function(sourceRootsIds, analysis, analysisIndex) {
if (analysis.type === 'source' && !!analysis.id) {
sourceRootsIds[analysis.id] = analysis;
analysisToRemove[analysisIndex] = true;
}
return sourceRootsIds;
}, {});
requestMapConfig.layers = requestMapConfig.layers.map(function(layer) {
var sourceId = layer.options && layer.options.source && layer.options.source.id;
if (sourceId && analysisSourceRootsIds.hasOwnProperty(sourceId)) {
delete layer.options.source;
layer.options.sql = analysisSourceRootsIds[sourceId].params.query;
}
return layer;
});
return requestMapConfig;
}
function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) {
var analyses = requestMapConfig.analyses || [];
debug(JSON.stringify(requestMapConfig, null, 4));
requestMapConfig.analyses = analyses.map(function(analysisDefinition) {
var analysisGraph = new camshaft.reference.AnalysisGraph(analysisDefinition);
var definition = analysisDefinition;
Object.keys(dataviewsFiltersBySourceId).forEach(function(sourceId) {
definition = analysisGraph.getDefinitionWith(sourceId, {filters: dataviewsFiltersBySourceId[sourceId] });
});
return definition;
});
debug(JSON.stringify(requestMapConfig, null, 4));
return requestMapConfig;
}
function shouldAdaptLayers(requestMapConfig) {
return Array.isArray(requestMapConfig.layers) &&
Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0;
}
var DATAVIEW_TYPE_2_FILTER_TYPE = {
aggregation: 'category',
histogram: 'range'
};
function getFilter(dataview, params) {
var type = dataview.type;
return {
type: DATAVIEW_TYPE_2_FILTER_TYPE[type],
column: dataview.options.column,
params: params
};
}
AnalysisMapConfigAdapter.prototype.getLayers = function(analysisConfiguration, requestMapConfig, filters, callback) {
// jshint maxcomplexity:7
filters = filters || {};
var dataviewsFilters = filters.dataviews || {};
debug(dataviewsFilters);
var dataviews = requestMapConfig.dataviews || {};
var dataviewsFiltersBySourceId = Object.keys(dataviewsFilters).reduce(function(bySourceId, dataviewName) {
var dataview = dataviews[dataviewName];
if (dataview) {
var sourceId = dataview.source.id;
if (!bySourceId.hasOwnProperty(sourceId)) {
bySourceId[sourceId] = {};
}
bySourceId[sourceId][dataviewName] = getFilter(dataview, dataviewsFilters[dataviewName]);
}
return bySourceId;
}, {});
debug(dataviewsFiltersBySourceId);
debug('mapconfig input', JSON.stringify(requestMapConfig, null, 4));
requestMapConfig = appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId);
if (!shouldAdaptLayers(requestMapConfig)) {
debug('mapconfig output', JSON.stringify(requestMapConfig, null, 4));
return callback(null, requestMapConfig);
}
function createAnalysis(analysisDefinition, done) {
camshaft.create(analysisConfiguration, analysisDefinition, done);
}
var analysesQueue = queue(requestMapConfig.analyses.length);
requestMapConfig.analyses.forEach(function(analysis) {
analysesQueue.defer(createAnalysis, analysis);
});
analysesQueue.awaitAll(function(err, analysesResults) {
if (err) {
return callback(err);
}
var sourceId2Node = analysesResults.reduce(function(sourceId2Query, analysis) {
var rootNode = analysis.getRoot();
if (rootNode.params && rootNode.params.id) {
sourceId2Query[rootNode.params.id] = rootNode;
}
analysis.getSortedNodes().forEach(function(node) {
if (node.params && node.params.id) {
sourceId2Query[node.params.id] = node;
}
});
return sourceId2Query;
}, {});
requestMapConfig.layers = requestMapConfig.layers.map(function(layer) {
if (layer.options.source && layer.options.source.id) {
var layerNode = sourceId2Node[layer.options.source.id];
layer.options.sql = layerQuery(layerNode.getQuery(), layerNode.getColumns());
}
return layer;
});
debug('mapconfig output', JSON.stringify(requestMapConfig, null, 4));
return callback(null, requestMapConfig);
});
};