Compare commits

...

44 Commits

Author SHA1 Message Date
Francisco Dans
0542b65cbb shrinkwrap changes for 2.38.0 2016-05-05 12:26:12 +02:00
Francisco Dans
60fa94781e adds upgrade to NEWS 2016-05-05 12:25:12 +02:00
Francisco Dans
ffd58cc7ca bumps minor 2016-05-05 12:07:26 +02:00
Francisco Dans
e103c52d27 upgrades turbo carto 2016-05-05 12:04:14 +02:00
Daniel García Aubert
00a71af95d Stubs next version 2016-05-03 17:58:47 +02:00
Daniel García Aubert
2fb8036740 Release 2.37.0 2016-05-03 17:53:08 +02:00
Daniel García Aubert
6902a8c9b3 Upgraded camashaft version to 0.6.0 2016-05-03 17:46:38 +02:00
Raul Ochoa
c19a345f6c Stubs next version 2016-04-29 12:54:47 +02:00
Raul Ochoa
bdc3ecff5a Release 2.36.1 2016-04-29 12:53:58 +02:00
Raul Ochoa
6c4ec29e18 Add test to validate new behaviour in camshaft 0.5.1 2016-04-29 12:51:48 +02:00
Raul Ochoa
412712e62e Upgrades camshaft to 0.5.1 2016-04-29 12:51:39 +02:00
Raul Ochoa
0edcb30f75 Stubs next version 2016-04-28 18:46:49 +02:00
Raul Ochoa
c0f49b3acb Release 2.36.0 2016-04-28 18:45:51 +02:00
Raul Ochoa
b926244085 Upgrades windshaft to 1.19.0 2016-04-28 17:30:57 +02:00
Raul Ochoa
d21136b475 Stubs next version 2016-04-27 18:44:47 +02:00
Raul Ochoa
8788aaaf25 Release 2.35.0 2016-04-27 18:43:50 +02:00
Raul Ochoa
120e800089 Bump version and update news 2016-04-27 18:42:56 +02:00
Raul Ochoa
92dc4b148c Merge pull request #432 from CartoDB/dataviews-columns
Append dataviews related columns to layers
2016-04-27 18:40:33 +02:00
Raul Ochoa
755dfe6822 Append dataviews related columns to layers 2016-04-27 18:30:05 +02:00
Daniel García Aubert
b787ee1033 Stubs next version 2016-04-27 15:12:13 +02:00
Daniel García Aubert
9ee3612da0 Release 2.34.1 2016-04-27 15:09:13 +02:00
Daniel García Aubert
fe0b0a9c50 Upgraded windshaft to 1.17.3 2016-04-27 15:05:45 +02:00
Raul Ochoa
dea19f20dd Stubs next version 2016-04-27 10:24:16 +02:00
Raul Ochoa
f9f70cc6e7 Release 2.34.0 2016-04-27 10:23:24 +02:00
Raul Ochoa
23ef1157cb Merge pull request #431 from CartoDB/dataviews-filters
Dataviews filters
2016-04-26 19:21:43 +02:00
Raul Ochoa
8ca4d537ce Update news 2016-04-26 19:18:04 +02:00
Raul Ochoa
98d5731555 Add test to validate latest windshaft uses dataviews filters
Windshaft is transforming dataview filters into widget filters
2016-04-26 19:13:30 +02:00
Raul Ochoa
5da8929a5d Upgrade windshaft 2016-04-26 19:13:10 +02:00
Raul Ochoa
e198bafac1 Merge pull request #429 from CartoDB/upgrade-turbo-carto
Starts using turbo-carto dependency
2016-04-26 16:56:11 +02:00
Raul Ochoa
dd731399dc Starts using turbo-carto dependency 2016-04-26 16:28:05 +02:00
csobier
66fd899ffb Merge pull request #426 from CartoDB/docs-801-misplaced-text
removed dup text from static api section
2016-04-24 14:16:40 -04:00
csobier
bca8a33417 removed dup text from static api section 2016-04-24 13:59:38 -04:00
Raul Ochoa
a11c8d882e Each error-case will have different expectations 2016-04-21 17:27:20 +02:00
Raul Ochoa
c5bed48d61 Handle missing analyses nodes for layers pointing to them
Fixes #422
2016-04-21 17:24:52 +02:00
Raul Ochoa
98b7d12796 Merge pull request #424 from CartoDB/analysis-named-metadata
Analysis named maps metadata
2016-04-21 17:10:36 +02:00
Raul Ochoa
93dd8a2213 Add analyses metadata for named maps excluding queries 2016-04-21 17:03:41 +02:00
Raul Ochoa
4e4a223f24 Better naming for analysis mapconfig adapter 2016-04-21 16:25:59 +02:00
Raul Ochoa
4a73f3874d Better naming 2016-04-21 16:18:17 +02:00
Raul Ochoa
bc845b2e8d Validate dataviews format before instantiating 2016-04-21 16:16:00 +02:00
Raul Ochoa
83eceb349c Merge pull request #423 from CartoDB/multierror-support
Adds support to return multiple errors in BaseController.sendError
2016-04-21 16:15:28 +02:00
Raul Ochoa
bb518f0744 Update news 2016-04-21 16:09:57 +02:00
Raul Ochoa
08ad961123 Adds support to return multiple errors in BaseController.sendError 2016-04-21 16:05:48 +02:00
Raul Ochoa
146d494cae Adds dataview example in named map 2016-04-21 15:35:45 +02:00
Javier Goizueta
bb40ecf7c2 Stub next version 2016-04-20 18:30:42 +02:00
28 changed files with 898 additions and 900 deletions

60
NEWS.md
View File

@@ -1,5 +1,65 @@
# Changelog
## 2.38.0
Released 2016-05-05
Announcements:
- Upgrades turbo-carto to [0.7.0](https://github.com/CartoDB/turbo-carto/releases/tag/0.7.0)
## 2.37.0
Released 2016-05-03
Announcements:
- Upgrades camshaft to [0.6.0](https://github.com/CartoDB/camshaft/releases/tag/0.6.0)
## 2.36.1
Released 2016-04-29
Announcements:
- Upgrades camshaft to [0.5.1](https://github.com/CartoDB/camshaft/releases/tag/0.5.1)
## 2.36.0
Released 2016-04-28
Announcements:
- Upgrades windshaft to [1.19.0](https://github.com/CartoDB/Windshaft/releases/tag/1.19.0)
## 2.35.0
Released 2016-04-27
Announcements:
- Upgrades windshaft to [1.18.0](https://github.com/CartoDB/Windshaft/releases/tag/1.18.0)
- Appends columns to layers from associated dataviews
## 2.34.1
Released 2016-04-27
Announcements:
- Upgrades windshaft to [1.17.3](https://github.com/CartoDB/Windshaft/releases/tag/1.17.3)
## 2.34.0
Released 2016-04-27
Enhancements:
- Adds support to return multiple errors in BaseController.sendError #423
- Starts using turbo-carto dependency
Announcements:
- Upgrades windshaft to [1.17.2](https://github.com/CartoDB/Windshaft/releases/tag/1.17.2)
## 2.33.1
Released 2016-04-20

View File

@@ -49,8 +49,6 @@ bbox | the bounding box in WGS 84 (EPSG:4326), comma separated values for:
width | the width in pixels for the output image
height | the height in pixels for the output image
format | the format for the image, supported types: `png`, `jpg`
format | the bounding box in WGS 84 (EPSG:4326), comma separated values for:
--- | ---
|_ jpg | will have a default quality of 85.

View File

@@ -9,7 +9,7 @@ var queue = require('queue-async');
var LruCache = require("lru-cache");
function NamedMapProviderCache(templateMaps, pgConnection, metadataBackend, userLimitsApi, overviewsAdapter,
turboCartocssAdapter) {
turboCartoAdapter) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend;
@@ -18,7 +18,7 @@ function NamedMapProviderCache(templateMaps, pgConnection, metadataBackend, user
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
this.analysisMapConfigAdapter = new AnalysisMapConfigAdapter();
this.overviewsAdapter = overviewsAdapter;
this.turboCartocssAdapter = turboCartocssAdapter;
this.turboCartoAdapter = turboCartoAdapter;
this.providerCache = new LruCache({ max: 2000 });
}
@@ -38,7 +38,7 @@ NamedMapProviderCache.prototype.get = function(user, templateId, config, authTok
this.userLimitsApi,
this.namedLayersAdapter,
this.overviewsAdapter,
this.turboCartocssAdapter,
this.turboCartoAdapter,
this.analysisMapConfigAdapter,
user,
templateId,

View File

@@ -197,7 +197,10 @@ BaseController.prototype.send = function(req, res, body, status, headers) {
// jshint maxcomplexity:6
BaseController.prototype.sendError = function(req, res, err, label) {
var allErrors = Array.isArray(err) ? err : [err];
label = label || 'UNKNOWN';
err = allErrors[0] || new Error(label);
allErrors[0] = err;
var statusCode = findStatusCode(err);
@@ -208,7 +211,7 @@ BaseController.prototype.sendError = function(req, res, err, label) {
statusCode = 200;
}
var errorResponseBody = { errors: [errorMessage(err)] };
var errorResponseBody = { errors: allErrors.map(errorMessage) };
this.send(req, res, errorResponseBody, statusCode);
};

View File

@@ -30,13 +30,13 @@ var CreateLayergroupMapConfigProvider = require('../models/mapconfig/create_laye
* @param {UserLimitsApi} userLimitsApi
* @param {LayergroupAffectedTables} layergroupAffectedTables
* @param {MapConfigOverviewsAdapter} overviewsAdapter
* @param {TurboCartocssAdapter} turboCartoCssAdapter
* @param {TurboCartoAdapter} turboCartoAdapter
* @param {AnalysisBackend} analysisBackend
* @constructor
*/
function MapController(authApi, pgConnection, templateMaps, mapBackend, metadataBackend,
surrogateKeysCache, userLimitsApi, layergroupAffectedTables,
overviewsAdapter, turboCartoCssAdapter, analysisBackend) {
overviewsAdapter, turboCartoAdapter, analysisBackend) {
BaseController.call(this, authApi, pgConnection);
@@ -47,7 +47,7 @@ function MapController(authApi, pgConnection, templateMaps, mapBackend, metadata
this.surrogateKeysCache = surrogateKeysCache;
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
this.turboCartoCssAdapter = turboCartoCssAdapter;
this.turboCartoAdapter = turboCartoAdapter;
this.analysisMapConfigAdapter = new AnalysisMapConfigAdapter(analysisBackend);
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
@@ -163,7 +163,7 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
// ignore
}
}
self.analysisMapConfigAdapter.getLayers(analysisConfiguration, requestMapConfig, filters, this);
self.analysisMapConfigAdapter.getMapConfig(analysisConfiguration, requestMapConfig, filters, this);
},
function beforeLayergroupCreate(err, requestMapConfig, _analysesResults) {
assert.ifError(err);
@@ -197,11 +197,11 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
return next(null, requestMapConfig, datasource);
});
},
function parseTurboCartoCss(err, requestMapConfig, datasource) {
function parseTurboCarto(err, requestMapConfig, datasource) {
assert.ifError(err);
var next = this;
self.turboCartoCssAdapter.getLayers(req.context.user, requestMapConfig.layers, function (err, layers) {
self.turboCartoAdapter.getLayers(req.context.user, requestMapConfig.layers, function (err, layers) {
if (err) {
return next(err);
}
@@ -263,7 +263,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
self.userLimitsApi,
self.namedLayersAdapter,
self.overviewsAdapter,
self.turboCartoCssAdapter,
self.turboCartoAdapter,
self.analysisMapConfigAdapter,
cdbuser,
req.params.template_id,
@@ -293,7 +293,9 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
var templateHash = self.templateMaps.fingerPrint(mapConfigProvider.template).substring(0, 8);
layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid;
addWidgetsUrl(req.context.user, layergroup);
addWidgetsUrl(cdbuser, layergroup);
addDataviewsUrls(cdbuser, layergroup, mapConfig.obj());
addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults);
res.set('X-Layergroup-Id', layergroup.layergroupid);
self.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(cdbuser, mapConfigProvider.getTemplateName()));
@@ -371,7 +373,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, an
// TODO this should take into account several URL patterns
addWidgetsUrl(username, layergroup);
addDataviewsUrls(username, layergroup, mapconfig.obj());
addAnalysesMetadata(username, layergroup, analysesResults);
addAnalysesMetadata(username, layergroup, analysesResults, true);
if (req.method === 'GET') {
var ttl = global.environment.varnish.layergroupTtl || 86400;
res.set('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
@@ -390,9 +392,10 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, an
);
};
function addAnalysesMetadata(username, layergroup, analysesResults) {
function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery) {
includeQuery = includeQuery || false;
analysesResults = analysesResults || [];
layergroup.metadata.analyses = layergroup.metadata.analyses || [];
layergroup.metadata.analyses = [];
analysesResults.forEach(function(analysis) {
var nodes = analysis.getSortedNodes();
@@ -402,9 +405,11 @@ function addAnalysesMetadata(username, layergroup, analysesResults) {
var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id();
nodesIdMap[node.params.id] = {
status: node.getStatus(),
query: node.getQuery(),
url: getUrls(username, nodeResource)
};
if (includeQuery) {
nodesIdMap[node.params.id].query = node.getQuery();
}
}
return nodesIdMap;

View File

@@ -66,7 +66,7 @@ function getFilter(dataview, params) {
};
}
AnalysisMapConfigAdapter.prototype.getLayers = function(analysisConfiguration, requestMapConfig, filters, callback) {
AnalysisMapConfigAdapter.prototype.getMapConfig = function(analysisConfiguration, requestMapConfig, filters, callback) {
// jshint maxcomplexity:7
var self = this;
filters = filters || {};
@@ -79,6 +79,11 @@ AnalysisMapConfigAdapter.prototype.getLayers = function(analysisConfiguration, r
debug(dataviewsFilters);
var dataviews = requestMapConfig.dataviews || {};
var errors = getDataviewsErrors(dataviews);
if (errors.length > 0) {
return callback(errors);
}
var dataviewsFiltersBySourceId = Object.keys(dataviewsFilters).reduce(function(bySourceId, dataviewName) {
var dataview = dataviews[dataviewName];
if (dataview) {
@@ -127,16 +132,89 @@ AnalysisMapConfigAdapter.prototype.getLayers = function(analysisConfiguration, r
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());
var missingNodesErrors = [];
requestMapConfig.layers = requestMapConfig.layers.map(function(layer, layerIndex) {
if (getLayerSourceId(layer)) {
var layerSourceId = getLayerSourceId(layer);
var layerNode = sourceId2Node[layerSourceId];
if (layerNode) {
layer.options.sql = layerQuery(layerNode.getQuery(), layerNode.getColumns());
var layerDataviews = getLayerDataviews(layer, dataviews);
layer.options.columns = layerDataviews.reduce(function(columns, dataview) {
return columns.concat(getDataviewColumns(dataview));
}, []);
} else {
missingNodesErrors.push(
new Error('Missing analysis node.id="' + layerSourceId +'" for layer='+layerIndex)
);
}
}
return layer;
});
debug('mapconfig output', JSON.stringify(requestMapConfig, null, 4));
if (missingNodesErrors.length > 0) {
return callback(missingNodesErrors);
}
return callback(null, requestMapConfig, analysesResults);
});
};
function getLayerSourceId(layer) {
return layer.options.source && layer.options.source.id;
}
function getDataviewSourceId(dataview) {
return dataview.source && dataview.source.id;
}
function getLayerDataviews(layer, dataviews) {
var layerDataviews = [];
var layerSourceId = getLayerSourceId(layer);
if (layerSourceId) {
var dataviewsList = getDataviewsList(dataviews);
dataviewsList.forEach(function(dataview) {
if (getDataviewSourceId(dataview) === layerSourceId) {
layerDataviews.push(dataview);
}
});
}
return layerDataviews;
}
function getDataviewColumns(dataview) {
var columns = [];
var options = dataview.options;
['column', 'aggregationColumn'].forEach(function(opt) {
if (options.hasOwnProperty(opt)) {
columns.push(options[opt]);
}
});
return columns;
}
function getDataviewsList(dataviews) {
return Object.keys(dataviews).map(function(dataviewKey) { return dataviews[dataviewKey]; });
}
function getDataviewsErrors(dataviews) {
var errors = [];
Object.keys(dataviews).forEach(function(dataviewName) {
var dataview = dataviews[dataviewName];
if (!dataview.hasOwnProperty('source') || !dataview.source.id) {
errors.push(new Error('Dataview "' + dataviewName + '" is missing `source.id` attribute'));
}
if (!dataview.type) {
errors.push(new Error('Dataview "' + dataviewName + '" is missing `type` attribute'));
}
});
return errors;
}

View File

@@ -12,14 +12,14 @@ var QueryTables = require('cartodb-query-tables');
* @type {NamedMapMapConfigProvider}
*/
function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend, userLimitsApi,
namedLayersAdapter, overviewsAdapter, turboCartoCssAdapter, analysisMapConfigAdapter,
namedLayersAdapter, overviewsAdapter, turboCartoAdapter, analysisMapConfigAdapter,
owner, templateId, config, authToken, params) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend;
this.userLimitsApi = userLimitsApi;
this.namedLayersAdapter = namedLayersAdapter;
this.turboCartoCssAdapter = turboCartoCssAdapter;
this.turboCartoAdapter = turboCartoAdapter;
this.analysisMapConfigAdapter = analysisMapConfigAdapter;
this.overviewsAdapter = overviewsAdapter;
@@ -41,6 +41,7 @@ function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend,
this.mapConfig = null;
this.rendererParams = null;
this.context = {};
this.analysesResults = [];
}
module.exports = NamedMapMapConfigProvider;
@@ -118,11 +119,12 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
// ignore
}
}
self.analysisMapConfigAdapter.getLayers(analysisConfiguration, requestMapConfig, filters, this);
self.analysisMapConfigAdapter.getMapConfig(analysisConfiguration, requestMapConfig, filters, this);
},
function prepareLayergroup(err, _mapConfig) {
function prepareLayergroup(err, _mapConfig, analysesResults) {
assert.ifError(err);
var next = this;
self.analysesResults = analysesResults || [];
self.namedLayersAdapter.getLayers(self.owner, _mapConfig.layers, self.pgConnection,
function(err, layers, datasource) {
if (err) {
@@ -152,11 +154,11 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
return next(null, _mapConfig, datasource);
});
},
function parseTurboCartoCss(err, _mapConfig, datasource) {
function parseTurboCarto(err, _mapConfig, datasource) {
assert.ifError(err);
var next = this;
self.turboCartoCssAdapter.getLayers(self.owner, _mapConfig.layers, function (err, layers) {
self.turboCartoAdapter.getLayers(self.owner, _mapConfig.layers, function (err, layers) {
if (err) {
return next(err);
}

View File

@@ -34,8 +34,8 @@ var timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encodin
var MapConfigOverviewsAdapter = require('./models/mapconfig_overviews_adapter');
var TurboCartocssParser = require('./utils/style/turbo-cartocss-parser');
var TurboCartocssAdapter = require('./utils/style/turbo-cartocss-adapter');
var TurboCartoParser = require('./utils/style/turbo-carto-parser');
var TurboCartoAdapter = require('./utils/style/turbo-carto-adapter');
module.exports = function(serverOptions) {
// Make stats client globally accessible
@@ -149,8 +149,8 @@ module.exports = function(serverOptions) {
var overviewsAdapter = new MapConfigOverviewsAdapter(overviewsMetadataApi);
var turboCartoCssParser = new TurboCartocssParser(pgQueryRunner);
var turboCartocssAdapter = new TurboCartocssAdapter(turboCartoCssParser);
var turboCartoParser = new TurboCartoParser(pgQueryRunner);
var turboCartoAdapter = new TurboCartoAdapter(turboCartoParser);
var namedMapProviderCache = new NamedMapProviderCache(
templateMaps,
@@ -158,7 +158,7 @@ module.exports = function(serverOptions) {
metadataBackend,
userLimitsApi,
overviewsAdapter,
turboCartocssAdapter
turboCartoAdapter
);
['update', 'delete'].forEach(function(eventType) {
@@ -198,7 +198,7 @@ module.exports = function(serverOptions) {
userLimitsApi,
layergroupAffectedTablesCache,
overviewsAdapter,
turboCartocssAdapter,
turboCartoAdapter,
analysisBackend
).register(app);

View File

@@ -2,26 +2,26 @@
var queue = require('queue-async');
function TurboCartocssAdapter(turboCartocssParser) {
this.turboCartocssParser = turboCartocssParser;
function TurboCartoAdapter(turboCartoParser) {
this.turboCartoParser = turboCartoParser;
}
module.exports = TurboCartocssAdapter;
module.exports = TurboCartoAdapter;
TurboCartocssAdapter.prototype.getLayers = function (username, layers, callback) {
TurboCartoAdapter.prototype.getLayers = function (username, layers, callback) {
var self = this;
if (!layers || layers.length === 0) {
return callback(null, layers);
}
var parseCartoCssQueue = queue(layers.length);
var parseCartoQueue = queue(layers.length);
layers.forEach(function(layer) {
parseCartoCssQueue.defer(self._parseCartoCss.bind(self), username, layer);
parseCartoQueue.defer(self._parseCartoCss.bind(self), username, layer);
});
parseCartoCssQueue.awaitAll(function (err, layers) {
parseCartoQueue.awaitAll(function (err, layers) {
if (err) {
return callback(err);
}
@@ -30,15 +30,15 @@ TurboCartocssAdapter.prototype.getLayers = function (username, layers, callback)
});
};
TurboCartocssAdapter.prototype._parseCartoCss = function (username, layer, callback) {
TurboCartoAdapter.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
this.turboCartoParser.process(username, layer.options.cartocss, layer.options.sql, function (err, cartocss) {
// Ignore turbo-carto errors and continue
if (!err && cartocss) {
layer.options.cartocss = cartocss;
}

View File

@@ -0,0 +1,15 @@
'use strict';
var turboCarto = require('turbo-carto');
var PostgresDatasource = require('./postgres-datasource');
function TurboCartoParser (pgQueryRunner) {
this.pgQueryRunner = pgQueryRunner;
}
module.exports = TurboCartoParser;
TurboCartoParser.prototype.process = function (username, cartocss, sql, callback) {
var datasource = new PostgresDatasource(this.pgQueryRunner, username, sql);
turboCarto(cartocss, datasource, callback);
};

View File

@@ -1,15 +0,0 @@
'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);
};

1115
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "windshaft-cartodb",
"version": "2.33.1",
"version": "2.38.0",
"description": "A map tile server for CartoDB",
"keywords": [
"cartodb"
@@ -26,20 +26,20 @@
"node-statsd": "~0.0.7",
"underscore" : "~1.6.0",
"dot": "~1.0.2",
"windshaft": "1.17.1",
"windshaft": "1.19.0",
"step": "~0.0.6",
"queue-async": "~1.0.7",
"request": "~2.62.0",
"cartodb-redis": "~0.13.0",
"cartodb-psql": "~0.6.1",
"camshaft": "0.5.0",
"camshaft": "0.6.0",
"fastly-purge": "~1.0.1",
"redis-mpool": "~0.4.0",
"lru-cache": "2.6.5",
"lzma": "~1.3.7",
"log4js": "https://github.com/CartoDB/log4js-node/tarball/cdb",
"cartodb-query-tables": "~0.1.0",
"turbo-cartocss": "0.4.0"
"turbo-carto": "0.7.0"
},
"devDependencies": {
"istanbul": "~0.3.6",

View File

@@ -0,0 +1,81 @@
require('../../support/test_helper');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
describe('analysis-layers-dataviews-geojson', function() {
function createMapConfig(layers, dataviews, analysis) {
return {
version: '1.5.0',
layers: layers,
dataviews: dataviews || {},
analyses: analysis || []
};
}
var CARTOCSS = [
"#points {",
" marker-fill-opacity: 1.0;",
" marker-line-color: #FFF;",
" marker-line-width: 0.5;",
" marker-line-opacity: 1.0;",
" marker-placement: point;",
" marker-type: ellipse;",
" marker-width: 8;",
" marker-fill: red;",
" marker-allow-overlap: true;",
"}"
].join('\n');
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
},
"cartocss": CARTOCSS,
"cartocss_version": "2.3.0"
}
}
],
{
pop_max_histogram: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
type: 'histogram',
options: {
column: 'pop_max'
}
}
},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
]
);
it('should get pop_max column from dataview', function(done) {
var testClient = new TestClient(mapConfig, 1234);
testClient.getTile(0, 0, 0, {format: 'geojson', layers: 0}, function(err, res, geojson) {
assert.ok(!err, err);
assert.ok(Array.isArray(geojson.features));
assert.ok(geojson.features.length > 0);
var feature = geojson.features[0];
assert.ok(feature.properties.hasOwnProperty('pop_max'), 'Missing pop_max property');
testClient.drain(done);
});
});
});

View File

@@ -184,4 +184,124 @@ describe('analysis-layers', function() {
testClient.drain(done);
});
});
it('should retrieve enough metadata about analyses', function(done) {
var useCase = useCases[1];
// No API key here
var testClient = new TestClient(useCase.mapConfig, 1234);
testClient.getLayergroup(function(err, layergroupResult) {
assert.ok(!err, err);
assert.ok(
Array.isArray(layergroupResult.metadata.analyses),
'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult)
);
var analyses = layergroupResult.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745', 'HEAD']);
nodesIds.forEach(function(nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node');
});
testClient.drain(done);
});
});
it('should have analysis metadata when dataviews point to source node', function(done) {
var useCase = {
desc: 'basic source-id mapnik layer',
fixture: 'basic-source-id-mapnik-layer.png',
mapConfig: mapConfig(
[
{
"type": "cartodb",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
}
},
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
},
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
}
}
],
{
pop_max_histogram: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
type: 'histogram',
options: {
column: 'pop_max'
}
},
scalerank_histogram: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
type: 'histogram',
options: {
column: 'scalerank'
}
}
},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
]
)
};
var testClient = new TestClient(useCase.mapConfig, 1234);
testClient.getLayergroup(function(err, layergroupResult) {
assert.ok(!err, err);
assert.ok(
Array.isArray(layergroupResult.metadata.analyses),
'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult)
);
var analyses = layergroupResult.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745']);
nodesIds.forEach(function(nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node');
});
testClient.drain(done);
});
});
});

View File

@@ -0,0 +1,67 @@
require('../../support/test_helper');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
describe('analysis-layers error cases', function() {
function createMapConfig(layers, dataviews, analysis) {
return {
version: '1.5.0',
layers: layers,
dataviews: dataviews || {},
analyses: analysis || []
};
}
var ERROR_RESPONSE = {
status: 400,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
it('should handle missing analysis nodes for layers', function(done) {
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "INVALID-SOURCE-ID"
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
}
}
],
{},
[
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
},
"radius": 50000
}
}
]
);
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="INVALID-SOURCE-ID" for layer=0');
testClient.drain(done);
});
});
});

View File

@@ -40,6 +40,17 @@ describe('named-maps analysis', function() {
}
}
],
dataviews: {
pop_max_histogram: {
source: {
id: 'HEAD'
},
type: 'histogram',
options: {
column: 'pop_max'
}
}
},
analyses: [
{
"id": "HEAD",
@@ -115,6 +126,22 @@ describe('named-maps analysis', function() {
assert.ok(layergroup.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from: " + res.body);
layergroupid = layergroup.layergroupid;
assert.ok(
Array.isArray(layergroup.metadata.analyses),
'Missing "analyses" array metadata from: ' + res.body
);
var analyses = layergroup.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745', 'HEAD']);
nodesIds.forEach(function(nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(!node.hasOwnProperty('query'), 'Unexpected "query" attribute in node');
});
keysToDelete['map_cfg|' + LayergroupToken.parse(layergroup.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
@@ -185,4 +212,34 @@ describe('named-maps analysis', function() {
);
});
it('should be able to retrieve dataviews from analysis', function(done) {
assert.response(
server,
{
url: '/api/v1/map/' + layergroupid + '/dataview/pop_max_histogram',
method: 'GET',
headers: {
host: username
}
},
{
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
},
function(res, err) {
if (err) {
return done(err);
}
var dataview = JSON.parse(res.body);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 0);
done();
}
);
});
});

View File

@@ -1,5 +1,5 @@
var assert = require('../support/assert');
var TestClient = require('../support/test-client');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
var IMAGE_TOLERANCE_PER_MIL = 20;
@@ -38,7 +38,7 @@ function makeMapconfig(cartocss) {
};
}
describe('turbo-cartocss for anonymous maps', function() {
describe('turbo-carto for anonymous maps', function() {
describe('parsing ramp function with colorbrewer for greens and mapnik renderer', function () {
beforeEach(function () {
var turboCartocss = '#layer { marker-fill: ramp([price], colorbrewer(Greens)); }';
@@ -49,8 +49,8 @@ describe('turbo-cartocss for anonymous maps', function() {
this.testClient.drain(done);
});
it('should get a tile with turbo-cartocss parsed properly', function (done) {
var fixturePath = 'test_turbo_cartocss_greens_13_4011_3088.png';
it('should get a tile with turbo-carto parsed properly', function (done) {
var fixturePath = 'test_turbo_carto_greens_13_4011_3088.png';
this.testClient.getTile(13, 4011, 3088, imageCompareFn(fixturePath, done));
});
});
@@ -65,8 +65,8 @@ describe('turbo-cartocss for anonymous maps', function() {
this.testClient.drain(done);
});
it('should get a tile with turbo-cartocss parsed properly', function (done) {
var fixtureFileName = 'test_turbo_cartocss_reds_13_4011_3088.png';
it('should get a tile with turbo-carto parsed properly', function (done) {
var fixtureFileName = 'test_turbo_carto_reds_13_4011_3088.png';
this.testClient.getTile(13, 4011, 3088, imageCompareFn(fixtureFileName, done));
});
});
@@ -115,12 +115,12 @@ describe('turbo-cartocss for anonymous maps', function() {
this.testClient.drain(done);
});
it('should get a tile with turbo-cartocss parsed properly', function (done) {
it('should get a tile with turbo-carto parsed properly', function (done) {
var z = 2;
var x = 2;
var y = 1;
var pngFixture = 'torque/populated_places_simple_reduced-turbo-cartocss-' + [z, x, y].join('.') + '.png';
var pngFixture = 'torque/populated_places_simple_reduced-turbo-carto-' + [z, x, y].join('.') + '.png';
this.testClient.getTile(z, x, y, { layers: 0, format: 'torque.png' }, imageCompareFn(pngFixture, done));
});

View File

@@ -1,14 +1,14 @@
var assert = require('../support/assert');
var assert = require('../../support/assert');
var step = require('step');
var LayergroupToken = require('../../lib/cartodb/models/layergroup_token');
var testHelper = require(__dirname + '/../support/test_helper');
var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server');
var serverOptions = require(__dirname + '/../../lib/cartodb/server_options');
var LayergroupToken = require('../../../lib/cartodb/models/layergroup_token');
var testHelper = require('../../support/test_helper');
var CartodbWindshaft = require('../../../lib/cartodb/server');
var serverOptions = require('../../../lib/cartodb/server_options');
var server = new CartodbWindshaft(serverOptions);
var mapnik = require('windshaft').mapnik;
var IMAGE_TOLERANCE_PER_MIL = 10;
describe('turbo-cartocss for named maps', function() {
describe('turbo-carto for named maps', function() {
var keysToDelete;
@@ -20,7 +20,7 @@ describe('turbo-cartocss for named maps', function() {
testHelper.deleteRedisKeys(keysToDelete, done);
});
var templateId = 'turbo-cartocss-template-1';
var templateId = 'turbo-carto-template-1';
var template = {
version: '0.0.1',
@@ -65,7 +65,7 @@ describe('turbo-cartocss for named maps', function() {
var templateParamsReds = { color: 'Reds' };
var templateParamsBlues = { color: 'Blues' };
it('should create a template with turbo-cartocss parsed properly', function (done) {
it('should create a template with turbo-carto parsed properly', function (done) {
step(
function postTemplate() {
var next = this;
@@ -144,7 +144,7 @@ describe('turbo-cartocss for named maps', function() {
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'image/png');
var fixturePath = './test/fixtures/turbo-cartocss-named-maps-reds.png';
var fixturePath = './test/fixtures/turbo-carto-named-maps-reds.png';
var image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, next);
@@ -203,7 +203,7 @@ describe('turbo-cartocss for named maps', function() {
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'image/png');
var fixturePath = './test/fixtures/turbo-cartocss-named-maps-blues.png';
var fixturePath = './test/fixtures/turbo-carto-named-maps-blues.png';
var image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
assert.imageIsSimilarToFile(image, fixturePath, IMAGE_TOLERANCE_PER_MIL, next);

View File

@@ -1,7 +1,7 @@
require('../support/test_helper');
require('../../support/test_helper');
var assert = require('../support/assert');
var TestClient = require('../support/test-client');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
function makeMapconfig(cartocss) {
return {
@@ -31,7 +31,7 @@ function makeMapconfig(cartocss) {
};
}
describe('turbo-cartocss regressions', function() {
describe('turbo-carto regressions', function() {
var cartocss = [
"/** simple visualization */",

View File

@@ -114,6 +114,34 @@ describe('histogram widgets', function() {
testClient.drain(done);
});
});
it("should expose a filtered histogram using dataviews for filtering", function(done) {
var params = {
filters: {
dataviews: {
country_places_histogram: { min: 4000000 }
}
}
};
var testClient = new TestClient(histogramMapConfig);
testClient.getWidget('country_places_histogram', params, function(err, res) {
if (err) {
return done(err);
}
var histogram = JSON.parse(res.body);
// notice min value
assert.deepEqual(histogram.bins[0], {
bin: 0,
freq: 62,
min: 4000000,
max: 9276403,
avg: 5815009.596774193
});
testClient.drain(done);
});
});
});
});

View File

@@ -113,7 +113,7 @@ describe('named-maps widgets', function() {
}
);
},
function fetchTile(err, res) {
function finish(err, res) {
assert.ifError(err);
layergroup = JSON.parse(res.body);

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 356 B

After

Width:  |  Height:  |  Size: 356 B

View File

Before

Width:  |  Height:  |  Size: 349 B

After

Width:  |  Height:  |  Size: 349 B

View File

@@ -313,13 +313,15 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) {
assert.response(server, request, expectedResponse, function(res, err) {
assert.ifError(err);
var image;
var obj;
if (isPng) {
image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
obj = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
} else {
obj = JSON.parse(res.body);
}
next(null, res, image);
next(null, res, obj);
});
},
function finish(err, res, image) {