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; } 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] = { type: 'range', column: dataview.options.column, params: 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); }); };