Compare commits

..

31 Commits

Author SHA1 Message Date
Raul Ochoa
6a15cd0566 Release 2.45.0 2016-06-02 16:19:39 +02:00
Raul Ochoa
614fe3f703 Update news and bump version 2016-06-02 14:45:00 +02:00
Raul Ochoa
82d4bb3046 Merge pull request #485 from CartoDB/mapconfig-dataviews-adapter
Mapconfig dataviews adapter
2016-06-02 14:42:22 +02:00
Raul Ochoa
f49c13b1b3 Do not apply twice metadata in anonymous maps 2016-06-02 14:28:32 +02:00
Raul Ochoa
828b817aca Append widgets metadata from mapconfig 2016-06-02 14:14:11 +02:00
Raul Ochoa
7f26f01743 Upgrade windshaft to 2.0.1 2016-06-02 13:38:05 +02:00
Raul Ochoa
50da63fc63 Upgrades windshaft to 2.0.0 2016-06-02 13:02:50 +02:00
Raul Ochoa
f8f6508449 Merge branch 'master' into mapconfig-dataviews-adapter
Conflicts:
	NEWS.md
	npm-shrinkwrap.json
2016-06-02 10:57:43 +02:00
Raul Ochoa
7256eb0935 Upgrade camshaft to 0.12.1 2016-06-02 10:54:23 +02:00
Raul Ochoa
cb08b42e54 Merge pull request #486 from CartoDB/upgrade-turbo-carto
Upgrades turbo-carto to 0.10.1
2016-06-01 19:43:58 +02:00
Raul Ochoa
9e7caeff94 Upgrades turbo-carto to 0.10.1 2016-06-01 19:32:17 +02:00
Raul Ochoa
e72a1d73be Geojson + column selection tests 2016-06-01 19:06:01 +02:00
Raul Ochoa
aaacad81e7 Add bbox unit tests 2016-06-01 19:05:46 +02:00
Raul Ochoa
55ee5b3b01 Ported histogram tests from windshaft 2016-06-01 15:03:18 +02:00
Raul Ochoa
94bf2748be Ignore errors coming from overviews adapter 2016-06-01 15:03:02 +02:00
Raul Ochoa
9a4aa7c1fa Add params to url if present in override option 2016-06-01 15:00:30 +02:00
Raul Ochoa
3e71365a95 Update camshaft to 0.12.0 2016-06-01 15:00:00 +02:00
Raul Ochoa
018ffcea7c List widget tests ported from windshaft 2016-06-01 11:51:31 +02:00
Raul Ochoa
e24ba9f495 Ported formula widget tests from windshaft 2016-06-01 11:48:37 +02:00
Raul Ochoa
0e2e069503 Remove empty line 2016-06-01 11:48:28 +02:00
Raul Ochoa
c4bbff3802 Tests for aggregation dataview ported from windshaft 2016-06-01 11:44:24 +02:00
Raul Ochoa
290054ef5d Add widget search support in test client 2016-06-01 11:43:19 +02:00
Raul Ochoa
4c25828540 Fix sql signature in agg, formula, and list dataviews 2016-06-01 11:42:24 +02:00
Javier Goizueta
5eda4888ed Stub next version 2016-06-01 10:51:36 +02:00
Raul Ochoa
6eb711e70b Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-31 18:51:13 +02:00
Raul Ochoa
cd7adbd792 Return a dataview/widget from response body 2016-05-31 18:20:16 +02:00
Raul Ochoa
5b76ec9f68 Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-31 17:14:28 +02:00
Raul Ochoa
b2d8f53a5c Merge branch 'master' into mapconfig-dataviews-adapter 2016-05-31 09:41:22 +02:00
Raul Ochoa
e12133e24b Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-27 15:35:29 +02:00
Raul Ochoa
f602ea88e2 Convert widgets from layers into dataviews
It also converts filters so full dataviews backend is reusable, that removes
widgets backend dependency.
2016-05-26 19:32:58 +02:00
Raul Ochoa
da6870cf1e Adds new adapter to transform widgets into dataviews 2016-05-26 11:57:55 +02:00
19 changed files with 1944 additions and 200 deletions

15
NEWS.md
View File

@@ -1,5 +1,20 @@
# Changelog
## 2.45.0
Released 2016-06-02
Improvements:
- Removes Windshaft's widgets dependency.
- Makes widgets/dataviews endpoint compatible, but all using dataviews backend instead of widgets from Windshaft.
- Keeps adding widgets metadata in map instantiations for old clients.
Announcements:
- Upgrades windshaft to [2.0.1](https://github.com/CartoDB/camshaft/releases/tag/2.0.1 )
- Upgrades camshaft to [0.12.1](https://github.com/CartoDB/camshaft/releases/tag/0.12.1)
- Upgrades turbo-carto to [0.10.1](https://github.com/CartoDB/turbo-carto/releases/tag/0.10.1)
## 2.44.1
Released 2016-06-01

View File

@@ -21,7 +21,6 @@ var QueryTables = require('cartodb-query-tables');
* @param {TileBackend} tileBackend
* @param {PreviewBackend} previewBackend
* @param {AttributesBackend} attributesBackend
* @param {WidgetBackend} widgetBackend
* @param {SurrogateKeysCache} surrogateKeysCache
* @param {UserLimitsApi} userLimitsApi
* @param {LayergroupAffectedTables} layergroupAffectedTables
@@ -29,7 +28,7 @@ var QueryTables = require('cartodb-query-tables');
* @constructor
*/
function LayergroupController(authApi, pgConnection, mapStore, tileBackend, previewBackend, attributesBackend,
widgetBackend, surrogateKeysCache, userLimitsApi, layergroupAffectedTables, analysisBackend) {
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, analysisBackend) {
BaseController.call(this, authApi, pgConnection);
this.pgConnection = pgConnection;
@@ -37,7 +36,6 @@ function LayergroupController(authApi, pgConnection, mapStore, tileBackend, prev
this.tileBackend = tileBackend;
this.previewBackend = previewBackend;
this.attributesBackend = attributesBackend;
this.widgetBackend = widgetBackend;
this.surrogateKeysCache = surrogateKeysCache;
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
@@ -78,21 +76,19 @@ LayergroupController.prototype.register = function(app) {
// Undocumented/non-supported API endpoint methods.
// Use at your own peril.
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:widgetName', cors(), userMiddleware,
this.widget.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:widgetName/search', cors(), userMiddleware,
this.widgetSearch.bind(this));
app.get(app.base_url_mapconfig +
'/:token/dataview/:dataviewName', cors(), userMiddleware,
this.dataview.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:dataviewName', cors(), userMiddleware,
this.dataview.bind(this));
app.get(app.base_url_mapconfig +
'/:token/dataview/:dataviewName/search', cors(), userMiddleware,
this.dataviewSearch.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:dataviewName/search', cors(), userMiddleware,
this.dataviewSearch.bind(this));
app.get(app.base_url_mapconfig +
'/:token/analysis/node/:nodeId', cors(), userMiddleware,
@@ -181,62 +177,6 @@ LayergroupController.prototype.dataviewSearch = function(req, res) {
};
LayergroupController.prototype.widget = function(req, res) {
var self = this;
step(
function setupParams() {
self.req2params(req, this);
},
function retrieveList(err) {
assert.ifError(err);
var mapConfigProvider = new MapStoreMapConfigProvider(
self.mapStore, req.context.user, self.userLimitsApi, req.params
);
self.widgetBackend.getWidget(mapConfigProvider, req.params, this);
},
function finish(err, widget, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET WIDGET');
} else {
self.sendResponse(req, res, widget, 200);
}
}
);
};
LayergroupController.prototype.widgetSearch = function(req, res) {
var self = this;
step(
function setupParams() {
self.req2params(req, this);
},
function retrieveList(err) {
assert.ifError(err);
var mapConfigProvider = new MapStoreMapConfigProvider(
self.mapStore, req.context.user, self.userLimitsApi, req.params
);
self.widgetBackend.search(mapConfigProvider, req.params, this);
},
function finish(err, searchResult, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET WIDGET');
} else {
self.sendResponse(req, res, searchResult, 200);
}
}
);
};
LayergroupController.prototype.attributes = function(req, res) {
var self = this;

View File

@@ -161,15 +161,15 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
},
function afterLayergroupCreate(err, layergroup) {
assert.ifError(err);
var analysesResults = context.analysesResults || [];
self.afterLayergroupCreate(req, res, mapConfig, analysesResults, layergroup, this);
self.afterLayergroupCreate(req, res, mapConfig, layergroup, this);
},
function finish(err, layergroup) {
if (err) {
self.sendError(req, res, err, 'ANONYMOUS LAYERGROUP');
} else {
addWidgetsUrl(req.context.user, layergroup);
var analysesResults = context.analysesResults || [];
addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj());
addAnalysesMetadata(req.context.user, layergroup, analysesResults, true);
res.set('X-Layergroup-Id', layergroup.layergroupid);
self.send(req, res, layergroup, 200);
}
@@ -219,7 +219,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
},
function afterLayergroupCreate(err, layergroup) {
assert.ifError(err);
self.afterLayergroupCreate(req, res, mapConfig, [], layergroup, this);
self.afterLayergroupCreate(req, res, mapConfig, layergroup, this);
},
function finishTemplateInstantiation(err, layergroup) {
if (err) {
@@ -228,8 +228,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
var templateHash = self.templateMaps.fingerPrint(mapConfigProvider.template).substring(0, 8);
layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid;
addWidgetsUrl(cdbuser, layergroup);
addDataviewsUrls(cdbuser, layergroup, mapConfig.obj());
addDataviewsAndWidgetsUrls(cdbuser, layergroup, mapConfig.obj());
addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults);
res.set('X-Layergroup-Id', layergroup.layergroupid);
@@ -241,8 +240,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
);
};
MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, analysesResults, layergroup, callback) {
MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, layergroup, callback) {
var self = this;
var username = req.context.user;
@@ -305,10 +303,6 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, an
layergroup.layergroupid = layergroup.layergroupid + ':' + result.getLastUpdatedAt();
layergroup.last_updated = new Date(result.getLastUpdatedAt()).toISOString();
// TODO this should take into account several URL patterns
addWidgetsUrl(username, layergroup);
addDataviewsUrls(username, layergroup, mapconfig.obj());
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');
@@ -353,6 +347,12 @@ function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery
});
}
// TODO this should take into account several URL patterns
function addDataviewsAndWidgetsUrls(username, layergroup, mapConfig) {
addDataviewsUrls(username, layergroup, mapConfig);
addWidgetsUrl(username, layergroup, mapConfig);
}
function addDataviewsUrls(username, layergroup, mapConfig) {
layergroup.metadata.dataviews = layergroup.metadata.dataviews || {};
var dataviews = mapConfig.dataviews || {};
@@ -365,20 +365,23 @@ function addDataviewsUrls(username, layergroup, mapConfig) {
});
}
function addWidgetsUrl(username, layergroup) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers)) {
function addWidgetsUrl(username, layergroup, mapConfig) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) {
if (layer.widgets) {
Object.keys(layer.widgets).forEach(function(widgetName) {
var mapConfigLayer = mapConfig.layers[layerIndex];
if (mapConfigLayer.options && mapConfigLayer.options.widgets) {
layer.widgets = layer.widgets || {};
Object.keys(mapConfigLayer.options.widgets).forEach(function(widgetName) {
var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName;
layer.widgets[widgetName].url = getUrls(username, resource);
layer.widgets[widgetName] = {
type: mapConfigLayer.options.widgets[widgetName].type,
url: getUrls(username, resource)
};
});
}
return layer;
});
}
}
function getUrls(username, resource) {

View File

@@ -102,7 +102,7 @@ Aggregation.prototype.constructor = Aggregation;
module.exports = Aggregation;
Aggregation.prototype.sql = function(psql, filters, override, callback) {
Aggregation.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};

View File

@@ -56,7 +56,7 @@ Formula.prototype.constructor = Formula;
module.exports = Formula;
Formula.prototype.sql = function(psql, filters, override, callback) {
Formula.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};

View File

@@ -34,7 +34,7 @@ List.prototype.constructor = List;
module.exports = List;
List.prototype.sql = function(psql, filters, override, callback) {
List.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
}

View File

@@ -0,0 +1,90 @@
function DataviewsWidgetsMapConfigAdapter() {
}
module.exports = DataviewsWidgetsMapConfigAdapter;
DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
if (!shouldAdapt(requestMapConfig)) {
return callback(null, requestMapConfig);
}
// prepare placeholders for new dataviews created from widgets
requestMapConfig.analyses = requestMapConfig.analyses || [];
requestMapConfig.dataviews = requestMapConfig.dataviews || {};
requestMapConfig.layers.forEach(function(layer, index) {
var layerSourceId = getLayerSourceId(layer);
var dataviewSourceId = layerSourceId || 'cdb-layer-source-' + index;
// Append a new analysis if layer has no source id but sql.
if (!layerSourceId) {
requestMapConfig.analyses.push(
{
id: dataviewSourceId,
type: 'source',
params: {
query: layer.options.sql
}
}
);
}
var source = { id: dataviewSourceId };
var layerWidgets = layer.options.widgets;
Object.keys(layerWidgets).forEach(function(widgetId) {
var dataview = layerWidgets[widgetId];
requestMapConfig.dataviews[widgetId] = {
source: source,
type: dataview.type,
options: dataview.options
};
});
layer.options.source = source;
delete layer.options.sql;
// don't delete widgets for now as it might be useful for old clients
//delete layer.options.widgets;
});
// filters have to be rewritten also
var filters = getFilters(params);
var layersFilters = filters.layers || [];
filters.dataviews = filters.dataviews || {};
layersFilters.forEach(function(layerFilters) {
Object.keys(layerFilters).forEach(function(filterName) {
if (!filters.dataviews.hasOwnProperty(filterName)) {
filters.dataviews[filterName] = layerFilters[filterName];
}
});
});
delete filters.layers;
params.filters = JSON.stringify(filters);
return callback(null, requestMapConfig);
};
function shouldAdapt(requestMapConfig) {
// return false;
return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(function hasWidgets(layer) {
return layer.options && layer.options.widgets && Object.keys(layer.options.widgets).length > 0;
});
}
function getLayerSourceId(layer) {
return layer.options.source && layer.options.source.id;
}
function getFilters(params) {
var filters = {};
if (params.filters) {
try {
filters = JSON.parse(params.filters);
} catch (e) {
// ignore
}
}
return filters;
}

View File

@@ -72,7 +72,7 @@ MapConfigOverviewsAdapter.prototype.getMapConfig = function(user, requestMapConf
layer = _.extend({}, layer);
layer.options = _.extend({}, layer.options, { query_rewrite_data: query_rewrite_data });
}
done(err, layer);
done(null, layer);
}
);
}

View File

@@ -41,6 +41,7 @@ var MapConfigNamedLayersAdapter = require('./models/mapconfig/adapter/mapconfig-
var AnalysisMapConfigAdapter = require('./models/mapconfig/adapter/analysis-mapconfig-adapter');
var MapConfigOverviewsAdapter = require('./models/mapconfig/adapter/mapconfig-overviews-adapter');
var TurboCartoAdapter = require('./models/mapconfig/adapter/turbo-carto-adapter');
var DataviewsWidgetsAdapter = require('./models/mapconfig/adapter/dataviews-widgets-adapter');
var MapConfigAdapter = require('./models/mapconfig/adapter');
module.exports = function(serverOptions) {
@@ -159,6 +160,7 @@ module.exports = function(serverOptions) {
var mapConfigAdapter = new MapConfigAdapter(
new MapConfigNamedLayersAdapter(templateMaps, pgConnection),
new SqlWrapMapConfigAdapter(),
new DataviewsWidgetsAdapter(),
new AnalysisMapConfigAdapter(analysisBackend),
new MapConfigOverviewsAdapter(overviewsMetadataApi, filterStatsApi),
new TurboCartoAdapter(turboCartoParser)
@@ -192,7 +194,6 @@ module.exports = function(serverOptions) {
tileBackend,
previewBackend,
attributesBackend,
new windshaft.backend.Widget(),
surrogateKeysCache,
userLimitsApi,
layergroupAffectedTablesCache,

241
npm-shrinkwrap.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "windshaft-cartodb",
"version": "2.44.1",
"version": "2.45.0",
"dependencies": {
"body-parser": {
"version": "1.14.2",
@@ -73,14 +73,14 @@
},
"unpipe": {
"version": "1.0.0",
"from": "unpipe@>=1.0.0 <1.1.0",
"from": "unpipe@1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
}
}
},
"type-is": {
"version": "1.6.13",
"from": "type-is@>=1.6.6 <1.7.0",
"from": "type-is@>=1.6.10 <1.7.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz",
"dependencies": {
"media-typer": {
@@ -105,13 +105,13 @@
}
},
"camshaft": {
"version": "0.11.0",
"from": "camshaft@0.11.0",
"resolved": "https://registry.npmjs.org/camshaft/-/camshaft-0.11.0.tgz",
"version": "0.12.1",
"from": "camshaft@0.12.1",
"resolved": "https://registry.npmjs.org/camshaft/-/camshaft-0.12.1.tgz",
"dependencies": {
"async": {
"version": "1.5.2",
"from": "async@>=1.0.0 <2.0.0",
"from": "async@>=1.5.2 <2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
},
"request": {
@@ -391,9 +391,9 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
},
"dashdash": {
"version": "1.13.1",
"version": "1.14.0",
"from": "dashdash@>=1.12.0 <2.0.0",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.1.tgz"
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz"
},
"getpass": {
"version": "0.1.6",
@@ -648,7 +648,7 @@
"dependencies": {
"unpipe": {
"version": "1.0.0",
"from": "unpipe@>=1.0.0 <1.1.0",
"from": "unpipe@1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
}
}
@@ -757,9 +757,50 @@
}
},
"serve-static": {
"version": "1.10.2",
"version": "1.10.3",
"from": "serve-static@>=1.10.2 <1.11.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.2.tgz"
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz",
"dependencies": {
"send": {
"version": "0.13.2",
"from": "send@0.13.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz",
"dependencies": {
"destroy": {
"version": "1.0.4",
"from": "destroy@>=1.0.4 <1.1.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
},
"http-errors": {
"version": "1.3.1",
"from": "http-errors@>=1.3.1 <1.4.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"from": "inherits@>=2.0.1 <2.1.0",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"mime": {
"version": "1.3.4",
"from": "mime@1.3.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
},
"ms": {
"version": "0.7.1",
"from": "ms@0.7.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
},
"statuses": {
"version": "1.2.1",
"from": "statuses@>=1.2.1 <1.3.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz"
}
}
}
}
},
"type-is": {
"version": "1.6.13",
@@ -976,7 +1017,7 @@
"dependencies": {
"async": {
"version": "1.5.2",
"from": "async@>=1.0.0 <2.0.0",
"from": "async@>=1.5.2 <2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
}
}
@@ -988,7 +1029,7 @@
},
"mime-types": {
"version": "2.1.11",
"from": "mime-types@>=2.1.2 <2.2.0",
"from": "mime-types@>=2.1.11 <2.2.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz",
"dependencies": {
"mime-db": {
@@ -1216,9 +1257,9 @@
"resolved": "https://registry.npmjs.org/step-profiler/-/step-profiler-0.3.0.tgz"
},
"turbo-carto": {
"version": "0.10.0",
"from": "turbo-carto@0.10.0",
"resolved": "https://registry.npmjs.org/turbo-carto/-/turbo-carto-0.10.0.tgz",
"version": "0.10.1",
"from": "turbo-carto@0.10.1",
"resolved": "https://registry.npmjs.org/turbo-carto/-/turbo-carto-0.10.1.tgz",
"dependencies": {
"colorbrewer": {
"version": "1.0.0",
@@ -1277,14 +1318,14 @@
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
},
"windshaft": {
"version": "1.19.0",
"from": "windshaft@1.19.0",
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-1.19.0.tgz",
"version": "2.0.1",
"from": "windshaft@2.0.1",
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-2.0.1.tgz",
"dependencies": {
"abaculus": {
"version": "1.1.0-cdb4",
"from": "https://github.com/CartoDB/abaculus/tarball/1.1.0-cdb4",
"resolved": "https://github.com/CartoDB/abaculus/tarball/1.1.0-cdb4"
"version": "1.1.0-cdb5",
"from": "https://github.com/CartoDB/abaculus/tarball/1.1.0-cdb5",
"resolved": "https://github.com/CartoDB/abaculus/tarball/1.1.0-cdb5"
},
"canvas": {
"version": "1.2.7-cdb1",
@@ -2916,9 +2957,9 @@
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-3.1.4.tgz",
"dependencies": {
"nan": {
"version": "2.3.3",
"version": "2.3.5",
"from": "nan@>=2.3.3 <2.4.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.3.3.tgz"
"resolved": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz"
},
"node-pre-gyp": {
"version": "0.6.28",
@@ -2955,16 +2996,16 @@
"from": "asn1@>=0.2.3 <0.3.0",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
},
"async": {
"version": "1.5.2",
"from": "async@>=1.5.2 <2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
},
"assert-plus": {
"version": "0.2.0",
"from": "assert-plus@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
},
"async": {
"version": "1.5.2",
"from": "async@>=1.5.2 <2.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
},
"aws-sign2": {
"version": "0.6.0",
"from": "aws-sign2@>=0.6.0 <0.7.0",
@@ -2995,16 +3036,16 @@
"from": "brace-expansion@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz"
},
"chalk": {
"version": "1.1.3",
"from": "chalk@>=1.1.1 <2.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
},
"caseless": {
"version": "0.11.0",
"from": "caseless@>=0.11.0 <0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
},
"chalk": {
"version": "1.1.3",
"from": "chalk@>=1.1.1 <2.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
},
"combined-stream": {
"version": "1.0.5",
"from": "combined-stream@>=1.0.5 <1.1.0",
@@ -3070,16 +3111,16 @@
"from": "extsprintf@1.0.2",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
},
"form-data": {
"version": "1.0.0-rc4",
"from": "form-data@>=1.0.0-rc3 <1.1.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz"
},
"forever-agent": {
"version": "0.6.1",
"from": "forever-agent@>=0.6.1 <0.7.0",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
},
"form-data": {
"version": "1.0.0-rc4",
"from": "form-data@>=1.0.0-rc3 <1.1.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz"
},
"fstream": {
"version": "1.0.9",
"from": "fstream@>=1.0.2 <2.0.0",
@@ -3095,26 +3136,21 @@
"from": "gauge@>=1.2.5 <1.3.0",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz"
},
"generate-function": {
"version": "2.0.0",
"from": "generate-function@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
},
"generate-object-property": {
"version": "1.2.0",
"from": "generate-object-property@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
},
"generate-function": {
"version": "2.0.0",
"from": "generate-function@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
},
"glob": {
"version": "7.0.3",
"from": "glob@>=7.0.0 <8.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.3.tgz"
},
"graceful-fs": {
"version": "4.1.4",
"from": "graceful-fs@>=4.1.2 <5.0.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz"
},
"graceful-readlink": {
"version": "1.0.1",
"from": "graceful-readlink@>=1.0.0",
@@ -3125,36 +3161,41 @@
"from": "har-validator@>=2.0.6 <2.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz"
},
"graceful-fs": {
"version": "4.1.4",
"from": "graceful-fs@>=4.1.2 <5.0.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz"
},
"has-ansi": {
"version": "2.0.0",
"from": "has-ansi@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
},
"hawk": {
"version": "3.1.3",
"from": "hawk@>=3.1.3 <3.2.0",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"
},
"has-unicode": {
"version": "2.0.0",
"from": "has-unicode@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.0.tgz"
},
"hawk": {
"version": "3.1.3",
"from": "hawk@>=3.1.3 <3.2.0",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"
},
"hoek": {
"version": "2.16.3",
"from": "hoek@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
},
"http-signature": {
"version": "1.1.1",
"from": "http-signature@>=1.1.0 <1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
},
"inflight": {
"version": "1.0.4",
"from": "inflight@>=1.0.4 <2.0.0",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz"
},
"http-signature": {
"version": "1.1.1",
"from": "http-signature@>=1.1.0 <1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
},
"inherits": {
"version": "2.0.1",
"from": "inherits@>=2.0.1 <2.1.0",
@@ -3265,16 +3306,16 @@
"from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
},
"mkdirp": {
"version": "0.5.1",
"from": "mkdirp@>=0.5.0 <0.6.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
},
"minimist": {
"version": "0.0.8",
"from": "minimist@0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
},
"mkdirp": {
"version": "0.5.1",
"from": "mkdirp@>=0.5.0 <0.6.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
},
"ms": {
"version": "0.7.1",
"from": "ms@0.7.1",
@@ -3330,16 +3371,16 @@
"from": "qs@>=6.1.0 <6.2.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.1.0.tgz"
},
"request": {
"version": "2.72.0",
"from": "request@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.72.0.tgz"
},
"readable-stream": {
"version": "2.1.2",
"from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.2.tgz"
},
"request": {
"version": "2.72.0",
"from": "request@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.72.0.tgz"
},
"rimraf": {
"version": "2.5.2",
"from": "rimraf@>=2.5.0 <2.6.0",
@@ -3385,16 +3426,16 @@
"from": "tar@>=2.2.0 <2.3.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
},
"tunnel-agent": {
"version": "0.4.3",
"from": "tunnel-agent@>=0.4.1 <0.5.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
},
"tough-cookie": {
"version": "2.2.2",
"from": "tough-cookie@>=2.2.0 <2.3.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz"
},
"tunnel-agent": {
"version": "0.4.3",
"from": "tunnel-agent@>=0.4.1 <0.5.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
},
"tweetnacl": {
"version": "0.13.3",
"from": "tweetnacl@>=0.13.0 <0.14.0",
@@ -3415,16 +3456,16 @@
"from": "verror@1.3.6",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
},
"wrappy": {
"version": "1.0.1",
"from": "wrappy@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
},
"xtend": {
"version": "4.0.1",
"from": "xtend@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
},
"wrappy": {
"version": "1.0.1",
"from": "wrappy@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
},
"bl": {
"version": "1.1.2",
"from": "bl@>=1.1.2 <1.2.0",
@@ -3437,10 +3478,10 @@
}
}
},
"dashdash": {
"version": "1.13.1",
"from": "dashdash@>=1.12.0 <2.0.0",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.1.tgz",
"getpass": {
"version": "0.1.6",
"from": "getpass@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -3449,10 +3490,10 @@
}
}
},
"getpass": {
"version": "0.1.6",
"from": "getpass@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
"dashdash": {
"version": "1.13.1",
"from": "dashdash@>=1.12.0 <2.0.0",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.1.tgz",
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -3538,9 +3579,9 @@
}
},
"mapnik": {
"version": "1.4.15-cdb6",
"from": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb6",
"resolved": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb6",
"version": "1.4.15-cdb8",
"from": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb8",
"resolved": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb8",
"dependencies": {
"nan": {
"version": "1.2.0",
@@ -3957,14 +3998,14 @@
}
},
"tilelive-bridge": {
"version": "1.3.0-cdb4",
"from": "https://github.com/CartoDB/tilelive-bridge/tarball/1.3.0-cdb4",
"resolved": "https://github.com/CartoDB/tilelive-bridge/tarball/1.3.0-cdb4",
"version": "1.3.0-cdb5",
"from": "https://github.com/CartoDB/tilelive-bridge/tarball/1.3.0-cdb5",
"resolved": "https://github.com/CartoDB/tilelive-bridge/tarball/1.3.0-cdb5",
"dependencies": {
"mapnik-pool": {
"version": "0.1.1-cdb4",
"from": "https://github.com/CartoDB/mapnik-pool/tarball/0.1.1-cdb4",
"resolved": "https://github.com/CartoDB/mapnik-pool/tarball/0.1.1-cdb4",
"version": "0.1.1-cdb5",
"from": "https://github.com/CartoDB/mapnik-pool/tarball/0.1.1-cdb5",
"resolved": "https://github.com/CartoDB/mapnik-pool/tarball/0.1.1-cdb5",
"dependencies": {
"generic-pool": {
"version": "2.1.1",
@@ -3981,9 +4022,9 @@
}
},
"tilelive-mapnik": {
"version": "0.6.15-cdb5",
"from": "https://github.com/CartoDB/tilelive-mapnik/tarball/0.6.15-cdb5",
"resolved": "https://github.com/CartoDB/tilelive-mapnik/tarball/0.6.15-cdb5",
"version": "0.6.15-cdb7",
"from": "https://github.com/CartoDB/tilelive-mapnik/tarball/0.6.15-cdb7",
"resolved": "https://github.com/CartoDB/tilelive-mapnik/tarball/0.6.15-cdb7",
"dependencies": {
"generic-pool": {
"version": "2.1.1",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "windshaft-cartodb",
"version": "2.44.1",
"version": "2.45.0",
"description": "A map tile server for CartoDB",
"keywords": [
"cartodb"
@@ -20,7 +20,7 @@
],
"dependencies": {
"body-parser": "~1.14.0",
"camshaft": "0.11.0",
"camshaft": "0.12.1",
"cartodb-psql": "~0.6.1",
"cartodb-query-tables": "~0.1.0",
"cartodb-redis": "~0.13.0",
@@ -37,9 +37,9 @@
"request": "~2.62.0",
"step": "~0.0.6",
"step-profiler": "~0.3.0",
"turbo-carto": "0.10.0",
"turbo-carto": "0.10.1",
"underscore": "~1.6.0",
"windshaft": "1.19.0"
"windshaft": "2.0.1"
},
"devDependencies": {
"istanbul": "~0.4.3",

View File

@@ -0,0 +1,171 @@
require('../support/test_helper');
var assert = require('../support/assert');
var TestClient = require('../support/test-client');
describe('use only needed columns', function() {
function getFeatureByCartodbId(features, cartodbId) {
for (var i = 0, len = features.length; i < len; i++) {
if (features[i].properties.cartodb_id === cartodbId) {
return features[i];
}
}
return {};
}
var options = { format: 'geojson', layer: 0 };
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
it('with aggregation widget, interactivity and cartocss columns', function(done) {
var widgetMapConfig = {
version: '1.5.0',
layers: [{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; [name="Madrid"] { marker-fill: green; } }',
cartocss_version: '2.0.1',
widgets: {
adm0name: {
type: 'aggregation',
options: {
column: 'adm0name',
aggregation: 'sum',
aggregationColumn: 'pop_max'
}
}
},
interactivity: "cartodb_id,pop_min"
}
}]
};
this.testClient = new TestClient(widgetMapConfig);
this.testClient.getTile(0, 0, 0, options, function (err, res, geojsonTile) {
assert.ok(!err, err);
assert.deepEqual(getFeatureByCartodbId(geojsonTile.features, 1109).properties, {
cartodb_id: 1109,
name: 'Mardin',
adm0name: 'Turkey',
pop_max: 71373,
pop_min: 57586
});
done();
});
});
it('should not duplicate columns', function(done) {
var widgetMapConfig = {
version: '1.5.0',
layers: [{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: ['#layer0 {',
'marker-fill: red;',
'marker-width: 10;',
'[name="Madrid"] { marker-fill: green; } ',
'[pop_max>100000] { marker-fill: black; } ',
'}'].join('\n'),
cartocss_version: '2.3.0',
widgets: {
adm0name: {
type: 'aggregation',
options: {
column: 'adm0name',
aggregation: 'sum',
aggregationColumn: 'pop_max'
}
}
},
interactivity: "cartodb_id,pop_max"
}
}]
};
this.testClient = new TestClient(widgetMapConfig);
this.testClient.getTile(0, 0, 0, options, function (err, res, geojsonTile) {
assert.ok(!err, err);
assert.deepEqual(getFeatureByCartodbId(geojsonTile.features, 1109).properties, {
cartodb_id: 1109,
name: 'Mardin',
adm0name: 'Turkey',
pop_max: 71373
});
done();
});
});
it('with formula widget, no interactivity and no cartocss columns', function(done) {
var formulaWidgetMapConfig = {
version: '1.5.0',
layers: [{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced where pop_max > 0 and pop_max < 600000',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
interactivity: 'cartodb_id',
widgets: {
pop_max_f: {
type: 'formula',
options: {
column: 'pop_max',
operation: 'count'
}
}
}
}
}]
};
this.testClient = new TestClient(formulaWidgetMapConfig);
this.testClient.getTile(0, 0, 0, options, function (err, res, geojsonTile) {
assert.ok(!err, err);
assert.deepEqual(getFeatureByCartodbId(geojsonTile.features, 1109).properties, {
cartodb_id: 1109,
pop_max: 71373
});
done();
});
});
it('with cartocss with multiple expressions', function(done) {
var formulaWidgetMapConfig = {
version: '1.5.0',
layers: [{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced where pop_max > 0 and pop_max < 600000',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }' +
'#layer0 { marker-width: 14; [name="Madrid"] { marker-width: 20; } }' +
'#layer0[pop_max>1000] { marker-width: 14; [name="Madrid"] { marker-width: 20; } }' +
'#layer0[adm0name=~".*Turkey*"] { marker-width: 14; [name="Madrid"] { marker-width: 20; } }',
cartocss_version: '2.0.1',
interactivity: 'cartodb_id'
}
}]
};
this.testClient = new TestClient(formulaWidgetMapConfig);
this.testClient.getTile(0, 0, 0, options, function (err, res, geojsonTile) {
assert.ok(!err, err);
assert.deepEqual(getFeatureByCartodbId(geojsonTile.features, 1109).properties, {
cartodb_id: 1109,
pop_max:71373,
name:"Mardin",
adm0name:"Turkey"
});
done();
});
});
});

View File

@@ -0,0 +1,329 @@
require('../../../support/test_helper');
var assert = require('../../../support/assert');
var TestClient = require('../../../support/test-client');
describe('widgets', function() {
describe('aggregations', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
var aggregationMapConfig = {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: {
adm0name: {
type: 'aggregation',
options: {
column: 'adm0name',
aggregation: 'count'
}
}
}
}
}
]
};
it('can be fetched from a valid aggregation', function(done) {
this.testClient = new TestClient(aggregationMapConfig);
this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) {
assert.ok(!err, err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.equal(aggregation.categories.length, 6);
assert.deepEqual(
aggregation.categories[0],
{ category: 'United States of America', value: 769, agg: false }
);
assert.deepEqual(
aggregation.categories[aggregation.categories.length - 1],
{ category: 'Other', value: 4914, agg: true }
);
done();
});
});
var filteredCategoriesScenarios = [
{ accept: ['Canada'], values: [256] },
{ accept: ['Canada', 'Spain', 'Chile', 'Thailand'], values: [256, 49, 83, 79] },
{ accept: ['Canada', 'Spain', 'Chile', 'Thailand', 'Japan'], values: [256, 49, 83, 79, 69] },
{ accept: ['Canada', 'Spain', 'Chile', 'Thailand', 'Japan', 'France'], values: [256, 49, 83, 79, 69, 71] },
{
accept: ['United States of America', 'Canada', 'Spain', 'Chile', 'Thailand', 'Japan', 'France'],
values: [769, 256, 49, 83, 79, 69, 71]
}
];
filteredCategoriesScenarios.forEach(function(scenario) {
it('can filter some categories: ' + scenario.accept.join(', '), function(done) {
this.testClient = new TestClient(aggregationMapConfig);
var adm0nameFilter = {
adm0name: {
accept: scenario.accept
}
};
var params = {
own_filter: 1,
filters: {
layers: [
adm0nameFilter
]
}
};
this.testClient.getWidget('adm0name', params, function (err, res, aggregation) {
assert.ok(!err, err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.equal(aggregation.categories.length, scenario.accept.length);
var categoriesByCategory = aggregation.categories.reduce(function(byCategory, row) {
byCategory[row.category] = row;
return byCategory;
}, {});
var scenarioByCategory = scenario.accept.reduce(function(byCategory, category, index) {
byCategory[category] = { category: category, value: scenario.values[index], agg: false };
return byCategory;
}, {});
Object.keys(categoriesByCategory).forEach(function(category) {
assert.deepEqual(categoriesByCategory[category], scenarioByCategory[category]);
});
done();
});
});
});
var aggregationSumMapConfig = {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: {
adm0name: {
type: 'aggregation',
options: {
column: 'adm0name',
aggregation: 'sum',
aggregationColumn: 'pop_max'
}
}
}
}
}
]
};
it('can sum other column for aggregation value', function(done) {
this.testClient = new TestClient(aggregationSumMapConfig);
this.testClient.getWidget('adm0name', { own_filter: 0 }, function (err, res, aggregation) {
assert.ok(!err, err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.equal(aggregation.categories.length, 6);
assert.deepEqual(
aggregation.categories[0],
{ category: 'China', value: 374537585, agg: false }
);
assert.deepEqual(
aggregation.categories[aggregation.categories.length - 1],
{ category: 'Other', value: 1412626289, agg: true }
);
done();
});
});
var filteredCategoriesSumScenarios = [
{ accept: [], values: [] },
{ accept: ['Canada'], values: [23955084] },
{ accept: ['Canada', 'Spain', 'Chile', 'Thailand'], values: [23955084, 22902774, 14356263, 17492483] },
{
accept: ['United States of America', 'Canada', 'Spain', 'Chile', 'Thailand', 'Japan', 'France'],
values: [239098994, 23955084, 22902774, 14356263, 17492483, 93577001, 25473876]
}
];
filteredCategoriesSumScenarios.forEach(function(scenario) {
it('can filter some categories with sum aggregation: ' + scenario.accept.join(', '), function(done) {
this.testClient = new TestClient(aggregationSumMapConfig);
var adm0nameFilter = {
adm0name: {
accept: scenario.accept
}
};
var params = {
own_filter: 1,
filters: {
layers: [
adm0nameFilter
]
}
};
this.testClient.getWidget('adm0name', params, function (err, res, aggregation) {
assert.ok(!err, err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.equal(aggregation.categories.length, scenario.accept.length);
var categoriesByCategory = aggregation.categories.reduce(function(byCategory, row) {
byCategory[row.category] = row;
return byCategory;
}, {});
var scenarioByCategory = scenario.accept.reduce(function(byCategory, category, index) {
byCategory[category] = { category: category, value: scenario.values[index], agg: false };
return byCategory;
}, {});
Object.keys(categoriesByCategory).forEach(function(category) {
assert.deepEqual(categoriesByCategory[category], scenarioByCategory[category]);
});
done();
});
});
});
var numericAggregationMapConfig = {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.3.0',
widgets: {
scalerank: {
type: 'aggregation',
options: {
column: 'scalerank',
aggregation: 'count'
}
}
}
}
}
]
};
['1', 1].forEach(function(filterValue) {
it('can filter numeric categories: ' + (typeof filterValue), function(done) {
this.testClient = new TestClient(numericAggregationMapConfig);
var scalerankFilter = {
scalerank: {
accept: [filterValue]
}
};
var params = {
own_filter: 1,
filters: {
layers: [scalerankFilter]
}
};
this.testClient.getWidget('scalerank', params, function (err, res, aggregation) {
assert.ok(!err, err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.equal(aggregation.categories.length, 1);
assert.deepEqual(aggregation.categories[0], { category: '1', value: 179, agg: false });
done();
});
});
});
describe('search', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
['1', 1].forEach(function(userQuery) {
it('can search numeric categories: ' + (typeof userQuery), function(done) {
this.testClient = new TestClient(numericAggregationMapConfig);
var scalerankFilter = {
scalerank: {
accept: [userQuery]
}
};
var params = {
own_filter: 0,
filters: {
layers: [scalerankFilter]
}
};
this.testClient.widgetSearch('scalerank', userQuery, params, function (err, res, searchResult) {
assert.ok(!err, err);
assert.ok(searchResult);
assert.equal(searchResult.type, 'aggregation');
assert.equal(searchResult.categories.length, 2);
assert.deepEqual(
searchResult.categories,
[{ category: 10, value: 515 }, { category: 1, value: 179 }]
);
done();
});
});
});
var adm0name = 'Argentina';
[adm0name, adm0name.toLowerCase(), adm0name.toUpperCase()].forEach(function(userQuery) {
it('should search with case insensitive: ' + userQuery, function(done) {
this.testClient = new TestClient(aggregationMapConfig);
this.testClient.widgetSearch('adm0name', userQuery, function (err, res, searchResult) {
assert.ok(!err, err);
assert.ok(searchResult);
assert.equal(searchResult.type, 'aggregation');
assert.equal(searchResult.categories.length, 1);
assert.deepEqual(
searchResult.categories,
[{ category:"Argentina", value:159 }]
);
done();
});
});
});
});
});
});

View File

@@ -0,0 +1,89 @@
require('../../../support/test_helper');
var assert = require('../../../support/assert');
var TestClient = require('../../../support/test-client');
describe('widgets', function() {
describe('formula', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
function widgetsMapConfig(widgets) {
return {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced where pop_max > 0 and pop_max < 600000',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: widgets
}
}
]
};
}
var operations = {
min: [10, 0],
max: [599579, 0],
count: [5822, 0],
avg: [112246.00893163861, 0],
sum: [653496264, 0]
};
Object.keys(operations).forEach(function(operation) {
it('should do ' + operation + ' over column', function(done) {
var widgets = {
pop_max_f: {
type: 'formula',
options: {
column: 'pop_max',
operation: operation
}
}
};
this.testClient = new TestClient(widgetsMapConfig(widgets));
this.testClient.getWidget('pop_max_f', function (err, res, result) {
assert.ok(!err, err);
assert.equal(result.operation, operation);
assert.equal(result.result, operations[operation][0]);
assert.equal(result.nulls, operations[operation][1]);
done();
});
});
});
it('does not require column for count formula', function(done) {
var operation = 'count';
var widgets = {
pop_max_count_f: {
type: 'formula',
options: {
operation: operation
}
}
};
this.testClient = new TestClient(widgetsMapConfig(widgets));
this.testClient.getWidget('pop_max_count_f', function (err, res, result) {
assert.ok(!err, err);
assert.equal(result.operation, operation);
assert.equal(result.result, operations[operation][0]);
assert.equal(result.nulls, operations[operation][1]);
done();
});
});
});
});

View File

@@ -0,0 +1,373 @@
require('../../../support/test_helper');
var assert = require('../../../support/assert');
var TestClient = require('../../../support/test-client');
describe('widgets', function() {
describe('histograms', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
function histogramsMapConfig(widgets) {
return {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: widgets || {
scalerank: {
type: 'histogram',
options: {
column: 'scalerank'
}
},
pop_max: {
type: 'histogram',
options: {
column: 'pop_max'
}
}
}
}
}
]
};
}
it('can be fetched from a valid histogram', function(done) {
this.testClient = new TestClient(histogramsMapConfig());
this.testClient.getWidget('scalerank', function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
validateHistogramBins(histogram);
assert.ok(histogram.bins.length);
assert.deepEqual(histogram.bins[0], { bin: 0, freq: 179, min: 1, max: 1, avg: 1 });
done();
});
});
it('can be fetched from a valid histogram', function(done) {
this.testClient = new TestClient(histogramsMapConfig());
this.testClient.getWidget('pop_max', function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
validateHistogramBins(histogram);
assert.ok(histogram.bins.length);
assert.deepEqual(
histogram.bins[histogram.bins.length - 1],
{ bin: 47, freq: 1, min: 35676000, max: 35676000, avg: 35676000 }
);
done();
});
});
it('can be fetched from a valid filtered histogram', function(done) {
this.testClient = new TestClient(histogramsMapConfig());
var popMaxFilter = {
pop_max: {
min: 1e5,
max: 1e7
}
};
var params = {
own_filter: 1,
filters: {
layers: [popMaxFilter]
}
};
this.testClient.getWidget('pop_max', params, function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
validateHistogramBins(histogram);
assert.ok(histogram.bins.length);
assert.deepEqual(
histogram.bins[histogram.bins.length - 1],
{ bin: 7, min: 8829000, max: 9904000, avg: 9340914.714285715, freq: 7 }
);
done();
});
});
it('returns array with freq=0 entries for empty bins', function(done) {
var histogram20binsMapConfig = {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: {
pop_max: {
type: 'histogram',
options: {
column: 'pop_max'
}
}
}
}
}
]
};
this.testClient = new TestClient(histogram20binsMapConfig);
this.testClient.getWidget('pop_max', { start: 0, end: 35676000, bins: 20 }, function (err, res, histogram) {
assert.ok(!err, err);
assert.equal(histogram.type, 'histogram');
validateHistogramBins(histogram);
assert.ok(histogram.bins.length);
assert.deepEqual(
histogram.bins[histogram.bins.length - 1],
{ bin: 19, freq: 1, min: 35676000, max: 35676000, avg: 35676000 }
);
var emptyBin = histogram.bins[18];
assert.ok(!emptyBin);
done();
});
});
it('can use a fixed number of bins', function(done) {
var fixedBinsHistogramMapConfig = histogramsMapConfig({
pop_max: {
type: 'histogram',
options: {
column: 'pop_max'
}
}
});
this.testClient = new TestClient(fixedBinsHistogramMapConfig);
this.testClient.getWidget('pop_max', { bins: 5 }, function (err, res, histogram) {
assert.ok(!err, err);
assert.equal(histogram.type, 'histogram');
assert.equal(histogram.bins_count, 5);
validateHistogramBins(histogram);
assert.ok(histogram.bins.length);
assert.deepEqual(
histogram.bins[0],
{ bin: 0, min: 0, max: 7067423, avg: 280820.0057731959, freq: 7275 }
);
assert.deepEqual(
histogram.bins[histogram.bins.length - 1],
{ bin: 4, freq: 1, min: 35676000, max: 35676000, avg: 35676000 }
);
done();
});
});
function validateHistogramBins(histogram) {
var binWidth = histogram.bin_width;
var start = histogram.bins_start;
var end = start + (histogram.bins_count * binWidth);
var firstBin = histogram.bins[0];
assert.equal(firstBin.min, start,
'First bin does not match min and start ' + JSON.stringify({
min: firstBin.min,
start: start
})
);
var lastBin = histogram.bins[histogram.bins.length - 1];
assert.equal(lastBin.max, end,
'Last bin does not match max and end ' + JSON.stringify({
max: lastBin.max,
end: end
})
);
function getBinStartEnd(binIndex) {
return {
start: start + (binIndex * binWidth),
end: start + ((binIndex + 1) * binWidth)
};
}
histogram.bins.forEach(function(bin) {
var binStartEnd = getBinStartEnd(bin.bin);
assert.ok(binStartEnd.start <= bin.min,
'Bin start bigger than bin min ' + JSON.stringify({
bin: bin.bin,
min: bin.min,
start: binStartEnd.start
})
);
assert.ok(binStartEnd.end >= bin.max,
'Bin end smaller than bin max ' + JSON.stringify({
bin: bin.bin,
max: bin.max,
end: binStartEnd.end
})
);
assert.ok(bin.avg >= bin.min && bin.avg <= bin.max,
'Bin avg not between min and max values' + JSON.stringify({
bin: bin.bin,
avg: bin.avg,
min: bin.min,
max: bin.max
})
);
});
}
describe('datetime column', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
var updatedAtFilter = {
updated_at: {
min: 0
}
};
it('can use a datetime column', function(done) {
this.testClient = new TestClient(histogramsMapConfig({
updated_at: {
type: 'histogram',
options: {
column: 'updated_at'
}
}
}));
this.testClient.getWidget('updated_at', function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
assert.ok(histogram.bins.length);
done();
});
});
it('can use a datetime filtered column', function(done) {
this.testClient = new TestClient(histogramsMapConfig({
updated_at: {
type: 'histogram',
options: {
column: 'updated_at'
}
}
}));
var params = {
own_filter: 1,
filters: {
layers: [updatedAtFilter]
}
};
this.testClient.getWidget('updated_at', params, function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
assert.ok(histogram.bins.length);
done();
});
});
it('can getTile with datetime filtered column', function(done) {
this.testClient = new TestClient(histogramsMapConfig({
updated_at: {
type: 'histogram',
options: {
column: 'updated_at'
}
}
}));
var params = {
own_filter: 1,
filters: {
layers: [updatedAtFilter]
}
};
this.testClient.getTile(0, 0, 0, params, function (err, res, tile) {
assert.ok(!err, err);
assert.ok(tile);
done();
});
});
it('can use two columns with different types', function(done) {
this.testClient = new TestClient(histogramsMapConfig({
updated_at: {
type: 'histogram',
options: {
column: 'updated_at'
}
},
pop_max: {
type: 'histogram',
options: {
column: 'pop_max'
}
}
}));
var popMaxFilter = {
pop_max: {
max: 1e7
}
};
var params = {
own_filter: 1,
filters: {
layers: [popMaxFilter]
}
};
this.testClient.getWidget('updated_at', params, function (err, res, histogram) {
assert.ok(!err, err);
assert.ok(histogram);
assert.equal(histogram.type, 'histogram');
assert.ok(histogram.bins.length);
done();
});
});
});
});
});

View File

@@ -0,0 +1,106 @@
require('../../../support/test_helper');
var assert = require('../../../support/assert');
var TestClient = require('../../../support/test-client');
var _ = require('underscore');
describe('widgets', function() {
describe('lists', function() {
afterEach(function(done) {
if (this.testClient) {
this.testClient.drain(done);
} else {
done();
}
});
function listsMapConfig(columns) {
return {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from test_table',
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: {
places: {
type: 'list',
options: {
columns: columns || ['name', 'address']
}
}
}
}
}
]
};
}
var EXPECTED_NAMES = ['Hawai', 'El Estocolmo', 'El Rey del Tallarín', 'El Lacón', 'El Pico'];
it('can be fetched from a valid list', function(done) {
var columns = ['name', 'address'];
this.testClient = new TestClient(listsMapConfig(columns));
this.testClient.getWidget('places', function (err, res, list) {
assert.ok(!err, err);
assert.ok(list);
assert.equal(list.type, 'list');
assert.equal(list.rows.length, 5);
assert.ok(onlyHasFields(list, columns));
var names = list.rows.map(function (item) {
return item.name;
});
assert.deepEqual(names, EXPECTED_NAMES);
var expectedAddresses = [
'Calle de Pérez Galdós 9, Madrid, Spain',
'Calle de la Palma 72, Madrid, Spain',
'Plaza Conde de Toreno 2, Madrid, Spain',
'Manuel Fernández y González 8, Madrid, Spain',
'Calle Divino Pastor 12, Madrid, Spain'
];
var addresses = list.rows.map(function (item) {
return item.address;
});
assert.deepEqual(addresses, expectedAddresses);
done();
});
});
it('should fetch just one column', function(done) {
var columns = ['name'];
this.testClient = new TestClient(listsMapConfig(columns));
this.testClient.getWidget('places', function (err, res, list) {
assert.ok(!err, err);
assert.ok(list);
assert.equal(list.type, 'list');
assert.equal(list.rows.length, 5);
assert.ok(onlyHasFields(list, columns));
var names = list.rows.map(function (item) {
return item.name;
});
assert.deepEqual(names, EXPECTED_NAMES);
done();
});
});
function onlyHasFields(list, expectedFields) {
var fields = (!!list.rows[0]) ? Object.keys(list.rows[0]) : [];
return _.difference(fields, expectedFields).length === 0 &&
_.difference(expectedFields, fields).length === 0;
}
});
});

View File

@@ -62,6 +62,7 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
return next(err);
}
var parsedBody = JSON.parse(res.body);
var expectedWidgetURLS = {
http: "/api/v1/map/" + parsedBody.layergroupid + "/0/widget/" + widgetName
};
@@ -69,6 +70,15 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
assert.ok(
parsedBody.metadata.layers[0].widgets[widgetName].url.http.match(expectedWidgetURLS.http)
);
var expectedDataviewsURLS = {
http: "/api/v1/map/" + parsedBody.layergroupid + "/dataview/" + widgetName
};
assert.ok(parsedBody.metadata.dataviews[widgetName]);
assert.ok(
parsedBody.metadata.dataviews[widgetName].url.http.match(expectedDataviewsURLS.http)
);
return next(null, parsedBody.layergroupid);
}
);
@@ -82,9 +92,12 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
var urlParams = {
own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1
};
if (params && params.bbox) {
urlParams.bbox = params.bbox;
}
['bbox', 'bins', 'start', 'end'].forEach(function(extraParam) {
if (params.hasOwnProperty(extraParam)) {
urlParams[extraParam] = params[extraParam];
}
});
url = '/api/v1/map/' + layergroupId + '/0/widget/' + widgetName + '?' + qs.stringify(urlParams);
assert.response(server,
@@ -113,7 +126,120 @@ TestClient.prototype.getWidget = function(widgetName, params, callback) {
function finish(err, res) {
self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
self.keysToDelete['user:localhost:mapviews:global'] = 5;
return callback(err, res);
var widget;
if (!err && res.body) {
widget = JSON.parse(res.body);
}
return callback(err, res, widget);
}
);
};
TestClient.prototype.widgetSearch = function(widgetName, userQuery, params, callback) {
var self = this;
if (!callback) {
callback = params;
params = {};
}
var url = '/api/v1/map';
if (params && params.filters) {
url += '?' + qs.stringify({ filters: JSON.stringify(params.filters) });
}
var layergroupId;
step(
function createLayergroup() {
var next = this;
assert.response(server,
{
url: url,
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
data: JSON.stringify(self.mapConfig)
},
{
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
},
function(res, err) {
if (err) {
return next(err);
}
var parsedBody = JSON.parse(res.body);
var expectedWidgetURLS = {
http: "/api/v1/map/" + parsedBody.layergroupid + "/0/widget/" + widgetName
};
assert.ok(parsedBody.metadata.layers[0].widgets[widgetName]);
assert.ok(
parsedBody.metadata.layers[0].widgets[widgetName].url.http.match(expectedWidgetURLS.http)
);
var expectedDataviewsURLS = {
http: "/api/v1/map/" + parsedBody.layergroupid + "/dataview/" + widgetName
};
assert.ok(parsedBody.metadata.dataviews[widgetName]);
assert.ok(
parsedBody.metadata.dataviews[widgetName].url.http.match(expectedDataviewsURLS.http)
);
return next(null, parsedBody.layergroupid);
}
);
},
function getWidgetSearchResult(err, _layergroupId) {
assert.ifError(err);
var next = this;
layergroupId = _layergroupId;
var urlParams = {
q: userQuery,
own_filter: params.hasOwnProperty('own_filter') ? params.own_filter : 1
};
if (params && params.bbox) {
urlParams.bbox = params.bbox;
}
url = '/api/v1/map/' + layergroupId + '/0/widget/' + widgetName + '/search?' + qs.stringify(urlParams);
assert.response(server,
{
url: url,
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
},
function(res, err) {
if (err) {
return next(err);
}
next(null, res);
}
);
},
function finish(err, res) {
self.keysToDelete['map_cfg|' + LayergroupToken.parse(layergroupId).token] = 0;
self.keysToDelete['user:localhost:mapviews:global'] = 5;
var searchResult;
if (!err && res.body) {
searchResult = JSON.parse(res.body);
}
return callback(err, res, searchResult);
}
);
};

View File

@@ -0,0 +1,331 @@
//require('../../../support/test_helper');
var assert = require('assert');
var DataviewsMapConfigAdapter = require('../../../../lib/cartodb/models/mapconfig/adapter/dataviews-widgets-adapter');
describe('dataviews-widgets-adapter', function() {
var widgetsMapConfigs = [
{
"input": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
"widgets": {
"country_places_count": {
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
}
}
}
}
]
},
"expected": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"source": {
"id": "cdb-layer-source-0"
},
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
// keep them for now
"widgets": {
"country_places_count": {
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
}
}
}
}
],
"analyses": [
{
"id": "cdb-layer-source-0",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
],
"dataviews": {
"country_places_count": {
"source": {
"id": "cdb-layer-source-0"
},
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
}
}
}
},
{
"input": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
"widgets": {
"pop_max": {
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
}
]
},
"expected": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"source": {
"id": "cdb-layer-source-0"
},
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
// keep them for now
"widgets": {
"pop_max": {
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
}
],
"analyses": [
{
"id": "cdb-layer-source-0",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
],
"dataviews": {
"pop_max": {
"source": {
"id": "cdb-layer-source-0"
},
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
},
{
"input": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"sql": "select * from test_table",
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
"widgets": {
"names": {
"type": "list",
"options": {
"columns": [
"name"
]
}
}
}
}
}
]
},
"expected": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"source": {
"id": "cdb-layer-source-0"
},
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
// keep them for now
"widgets": {
"names": {
"type": "list",
"options": {
"columns": [
"name"
]
}
}
}
}
}
],
"analyses": [
{
"id": "cdb-layer-source-0",
"type": "source",
"params": {
"query": "select * from test_table"
}
}
],
"dataviews": {
"names": {
"source": {
"id": "cdb-layer-source-0"
},
"type": "list",
"options": {
"columns": [
"name"
]
}
}
}
}
},
{
"input": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
"widgets": {
"country_places_count": {
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
},
"country_places_histogram": {
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
}
]
},
"expected": {
"version": "1.4.0",
"layers": [
{
"type": "mapnik",
"options": {
"source": {
"id": "cdb-layer-source-0"
},
"cartocss": "#layer { marker-fill: red; marker-width: 32; marker-allow-overlap: true; }",
"cartocss_version": "2.3.0",
// keep them for now
"widgets": {
"country_places_count": {
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
},
"country_places_histogram": {
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
}
],
"analyses": [
{
"id": "cdb-layer-source-0",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
}
}
],
"dataviews": {
"country_places_count": {
"source": {
"id": "cdb-layer-source-0"
},
"type": "aggregation",
"options": {
"column": "adm0_a3",
"aggregation": "count"
}
},
"country_places_histogram": {
"source": {
"id": "cdb-layer-source-0"
},
"type": "histogram",
"options": {
"column": "pop_max"
}
}
}
}
}
];
var user = 'wadus';
function params() {
return {};
}
function context() {
return {};
}
var dataviewsMapConfigAdapter = new DataviewsMapConfigAdapter();
widgetsMapConfigs.forEach(function(mapConfig, index) {
it('should adapt widgets ' + index, function(done) {
dataviewsMapConfigAdapter.getMapConfig(user, mapConfig.input, params(), context(), function(err, result) {
assert.deepEqual(result, mapConfig.expected);
done();
});
});
});
});

View File

@@ -0,0 +1,129 @@
require('../../../../support/test_helper');
var util = require('util');
var assert = require('../../../../support/assert');
var BboxFilter = require('../../../../../lib/cartodb/models/filter/bbox');
var MAX_EXTENT_MERCATOR_REF = [
-BboxFilter.LONGITUDE_MAX_VALUE,
-BboxFilter.LATITUDE_MAX_VALUE,
BboxFilter.LONGITUDE_MAX_VALUE,
BboxFilter.LATITUDE_MAX_VALUE
];
describe('Bounding box filter', function() {
describe('wrap longitude', function() {
var longitudesScenarios = [
[[0, 90], [0, 90]],
[[-90, 0], [-90, 0]],
[[-90, 90], [-90, 90]],
[[-990, -720], [90, 360]],
[[810, 1080], [90, 360]],
[[-180, 180], [-180, 180]]
];
longitudesScenarios.forEach(function(scenario) {
it(util.format('should adjust from %j to %j', scenario[0], scenario[1]), function() {
var we = BboxFilter.adjustLongitudeRange(scenario[0]);
assert.equal(
we[0], scenario[1][0],
util.format('west, got %d, expected %d, scenario: %s',
we[1], scenario[1][1], JSON.stringify(scenario)
)
);
assert.equal(
we[1], scenario[1][1],
util.format('east, got %d, expected %d, scenario: %s',
we[1], scenario[1][1], JSON.stringify(scenario)
)
);
});
});
});
function createFilter(bbox) {
return new BboxFilter({}, { bbox: bbox.join(',') });
}
function createRef(bbox) {
return bbox;
// return mercator.forward([bbox[0], bbox[1]]).concat(mercator.forward([bbox[2], bbox[3]]));
}
it('happy case', function() {
var bbox = [-90, -45, 90, 45];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 1);
assert.deepEqual(bboxFilter.bboxes[0], createRef(bbox));
});
describe('latitude', function() {
it('(hardcoded) clipping out of bounds', function() {
var bbox = [-180, -90, 180, 90];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 1);
assert.deepEqual(bboxFilter.bboxes[0], MAX_EXTENT_MERCATOR_REF);
});
it('clipping out of bounds', function() {
var bbox = [-180, -90, 180, 90];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 1);
assert.deepEqual(
bboxFilter.bboxes[0],
createRef([-180, -BboxFilter.LATITUDE_MAX_VALUE, 180, BboxFilter.LATITUDE_MAX_VALUE])
);
});
});
describe('longitude', function() {
it('generating multiple bbox for east out of bounds', function() {
var bbox = [90, -45, 360, 45];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 2, JSON.stringify([bboxFilter.bboxes, bbox]));
assert.deepEqual(
bboxFilter.bboxes[0],
createRef([90, -45, 180, 45])
);
assert.deepEqual(
bboxFilter.bboxes[1],
createRef([-180, -45, 0, 45])
);
});
it('generating multiple bbox for east out of bounds', function() {
var bbox = [-270, -45, 0, 45];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 2);
assert.deepEqual(
bboxFilter.bboxes[0],
createRef([90, -45, 180, 45])
);
assert.deepEqual(
bboxFilter.bboxes[1],
createRef([-180, -45, 0, 45])
);
});
});
describe('out of bounds', function() {
it('wraps longitude', function () {
var bbox = [-190, -45, 190, 45];
var bboxFilter = createFilter(bbox);
assert.equal(bboxFilter.bboxes.length, 1);
assert.deepEqual(
bboxFilter.bboxes[0],
createRef([-180, -45, 180, 45])
);
});
});
});