Merge branch 'master' into analysis-layers

Conflicts:
	npm-shrinkwrap.json
	test/support/test-client.js
This commit is contained in:
Raul Ochoa
2016-03-14 15:13:19 +01:00
21 changed files with 1175 additions and 550 deletions
+3 -1
View File
@@ -7,12 +7,13 @@ var queue = require('queue-async');
var LruCache = require("lru-cache");
function NamedMapProviderCache(templateMaps, pgConnection, userLimitsApi) {
function NamedMapProviderCache(templateMaps, pgConnection, userLimitsApi, turboCartocssAdapter) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.userLimitsApi = userLimitsApi;
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
this.turboCartocssAdapter = turboCartocssAdapter;
this.providerCache = new LruCache({ max: 2000 });
}
@@ -30,6 +31,7 @@ NamedMapProviderCache.prototype.get = function(user, templateId, config, authTok
this.pgConnection,
this.userLimitsApi,
this.namedLayersAdapter,
this.turboCartocssAdapter,
user,
templateId,
config,
+20 -1
View File
@@ -35,7 +35,7 @@ var MapConfigOverviewsAdapter = require('../models/mapconfig_overviews_adapter')
*/
function MapController(authApi, pgConnection, templateMaps, mapBackend, metadataBackend,
overviewsMetadataApi,
surrogateKeysCache, userLimitsApi, layergroupAffectedTables) {
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, turboCartoCssAdapter) {
BaseController.call(this, authApi, pgConnection);
@@ -47,6 +47,7 @@ function MapController(authApi, pgConnection, templateMaps, mapBackend, metadata
this.surrogateKeysCache = surrogateKeysCache;
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
this.turboCartoCssAdapter = turboCartoCssAdapter;
this.analysisMapConfigAdapter = new AnalysisMapConfigAdapter();
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
@@ -183,6 +184,23 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
if (layers) {
requestMapConfig.layers = layers;
}
return next(null, requestMapConfig, datasource);
});
},
function parseTurboCartoCss(err, requestMapConfig, datasource) {
assert.ifError(err);
var next = this;
self.turboCartoCssAdapter.getLayers(req.context.user, requestMapConfig.layers, function (err, layers) {
if (err) {
return next(err);
}
if (layers) {
requestMapConfig.layers = layers;
}
return next(null, requestMapConfig, datasource);
});
},
@@ -234,6 +252,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
self.pgConnection,
self.userLimitsApi,
self.namedLayersAdapter,
self.turboCartoCssAdapter,
cdbuser,
req.params.template_id,
templateParams,
@@ -65,6 +65,7 @@ NamedMapsAdminController.prototype.update = function(req, res) {
var cdbuser = req.context.user;
var template;
var tpl_id;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
@@ -12,11 +12,12 @@ var QueryTables = require('cartodb-query-tables');
* @type {NamedMapMapConfigProvider}
*/
function NamedMapMapConfigProvider(templateMaps, pgConnection, userLimitsApi, namedLayersAdapter,
owner, templateId, config, authToken, params) {
turboCartoCssAdapter, owner, templateId, config, authToken, params) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.userLimitsApi = userLimitsApi;
this.namedLayersAdapter = namedLayersAdapter;
this.turboCartoCssAdapter = turboCartoCssAdapter;
this.owner = owner;
this.templateName = templateName(templateId);
@@ -91,6 +92,18 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
}
);
},
function parseTurboCartoCss(err, _mapConfig, datasource) {
assert.ifError(err);
var next = this;
self.turboCartoCssAdapter.getLayers(self.owner, _mapConfig.layers, function (err, layers) {
if (!err && layers) {
_mapConfig.layers = layers;
}
return next(null, _mapConfig, datasource);
});
},
function beforeLayergroupCreate(err, _mapConfig, _datasource) {
assert.ifError(err);
mapConfig = _mapConfig;
+14 -2
View File
@@ -30,6 +30,8 @@ var PgConnection = require('./backends/pg_connection');
var timeoutErrorTilePath = __dirname + '/../../assets/render-timeout-fallback.png';
var timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encoding: null});
var TurboCartocssParser = require('./utils/style/turbo-cartocss-parser');
var TurboCartocssAdapter = require('./utils/style/turbo-cartocss-adapter');
module.exports = function(serverOptions) {
// Make stats client globally accessible
@@ -140,7 +142,16 @@ module.exports = function(serverOptions) {
var layergroupAffectedTablesCache = new LayergroupAffectedTablesCache();
app.layergroupAffectedTablesCache = layergroupAffectedTablesCache;
var namedMapProviderCache = new NamedMapProviderCache(templateMaps, pgConnection, userLimitsApi);
var turboCartoCssParser = new TurboCartocssParser(pgQueryRunner);
var turboCartocssAdapter = new TurboCartocssAdapter(turboCartoCssParser);
var namedMapProviderCache = new NamedMapProviderCache(
templateMaps,
pgConnection,
userLimitsApi,
turboCartocssAdapter
);
['update', 'delete'].forEach(function(eventType) {
templateMaps.on(eventType, namedMapProviderCache.invalidate.bind(namedMapProviderCache));
});
@@ -176,7 +187,8 @@ module.exports = function(serverOptions) {
overviewsMetadataApi,
surrogateKeysCache,
userLimitsApi,
layergroupAffectedTablesCache
layergroupAffectedTablesCache,
turboCartocssAdapter
).register(app);
new controller.NamedMaps(
@@ -0,0 +1,55 @@
'use strict';
var dot = require('dot');
dot.templateSettings.strip = false;
function createTemplate(method) {
return dot.template([
'SELECT',
method,
'FROM ({{=it._sql}}) _table_sql WHERE {{=it._column}} IS NOT NULL'
].join('\n'));
}
var methods = {
quantiles: 'CDB_QuantileBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as quantiles',
equal: 'CDB_EqualIntervalBins(array_agg({{=it._column}}::numeric), {{=it._buckets}}) as equal',
jenks: 'CDB_JenksBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as jenks',
headtails: 'CDB_HeadsTailsBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as headtails'
};
var methodTemplates = Object.keys(methods).reduce(function(methodTemplates, methodName) {
methodTemplates[methodName] = createTemplate(methods[methodName]);
return methodTemplates;
}, {});
function PostgresDatasource (pgQueryRunner, username, query) {
this.pgQueryRunner = pgQueryRunner;
this.username = username;
this.query = query;
}
PostgresDatasource.prototype.getName = function () {
return 'PostgresDatasource';
};
PostgresDatasource.prototype.getRamp = function (column, buckets, method, callback) {
var methodName = methods.hasOwnProperty(method) ? method : 'quantiles';
var template = methodTemplates[methodName];
var query = template({ _column: column, _sql: this.query, _buckets: buckets });
this.pgQueryRunner.run(this.username, query, function (err, result) {
if (err) {
return callback(err);
}
var ramp = result[0][methodName].sort(function(a, b) {
return a - b;
});
return callback(null, ramp);
});
};
module.exports = PostgresDatasource;
@@ -0,0 +1,56 @@
'use strict';
var queue = require('queue-async');
function TurboCartocssAdapter(turboCartocssParser) {
this.turboCartocssParser = turboCartocssParser;
}
module.exports = TurboCartocssAdapter;
TurboCartocssAdapter.prototype.getLayers = function (username, layers, callback) {
var self = this;
if (!layers || layers.length === 0) {
return callback(null, layers);
}
var parseCartoCssQueue = queue(layers.length);
layers.forEach(function(layer) {
parseCartoCssQueue.defer(self._parseCartoCss.bind(self), username, layer);
});
parseCartoCssQueue.awaitAll(function (err, layers) {
if (err) {
return callback(err);
}
return callback(null, layers);
});
};
TurboCartocssAdapter.prototype._parseCartoCss = function (username, layer, callback) {
if (isNotLayerToParseCartocss(layer)) {
return process.nextTick(function () {
callback(null, layer);
});
}
this.turboCartocssParser.process(username, layer.options.cartocss, layer.options.sql, function (err, cartocss) {
// Ignore turbo-cartocss errors and continue
if (!err && cartocss) {
layer.options.cartocss = cartocss;
}
callback(null, layer);
});
};
function isNotLayerToParseCartocss(layer) {
if (!layer || !layer.options || !layer.options.cartocss || !layer.options.sql) {
return true;
}
return false;
}
@@ -0,0 +1,15 @@
'use strict';
var turboCartoCss = require('turbo-cartocss');
var PostgresDatasource = require('./postgres-datasource');
function TurboCartocssParser (pgQueryRunner) {
this.pgQueryRunner = pgQueryRunner;
}
module.exports = TurboCartocssParser;
TurboCartocssParser.prototype.process = function (username, cartocss, sql, callback) {
var datasource = new PostgresDatasource(this.pgQueryRunner, username, sql);
turboCartoCss(cartocss, datasource, callback);
};