Compare commits

..

35 Commits

Author SHA1 Message Date
Daniel García Aubert
06885e2ba3 Release 2.87.4 2017-01-20 11:32:11 +01:00
Daniel
89a268d087 Merge pull request #617 from CartoDB/497-null-category
Be able to not compute NULL categories and null values
2017-01-20 11:26:12 +01:00
csobier
3648b8b0b1 removed "default" from descriptions
As per a customer Support inquiry, I removed "default" from the Static Maps Limits section, as it was confusing to the user that it implied
2017-01-17 11:21:23 -05:00
Daniel García Aubert
83301238d2 Port changes to overviews 2017-01-17 17:10:08 +01:00
Daniel García Aubert
a4a1fb930a Be able to not compute NULL categories and null values wheter aggregation operation is not 'count' 2017-01-17 17:09:17 +01:00
Daniel García Aubert
6555353e0e Improve test to handle NULL values in category and aggregation columns using any operation 2017-01-16 19:23:08 +01:00
Daniel García Aubert
f5f0601e53 Add test to check if NULL category count values properly 2017-01-16 17:00:28 +01:00
Raul Ochoa
2598595e42 Merge pull request #614 from CartoDB/zipfile-cartodb
Use zipfile from cartodb
2016-12-23 14:47:40 +01:00
Raul Ochoa
49b78a85c9 Use zipfile from cartodb
Adding it as dependency in combination with loose definition in
millstone makes it to use the top level defined dependency.
2016-12-22 19:12:30 +01:00
Javier Goizueta
0918c8e68c Stub next version 2016-12-19 17:20:18 +01:00
Javier Goizueta
1603a07de1 Release 2.87.3 2016-12-19 17:13:12 +01:00
Javier Goizueta
0a37aa4ba1 Merge pull request #604 from CartoDB/fix-overviews-dataviews
Fixes for dataviews using overviews
2016-12-19 16:55:13 +01:00
Javier Goizueta
b721a80fcc Merge branch 'master' into fix-overviews-dataviews 2016-12-19 16:45:28 +01:00
Rafa de la Torre
01365d035e Stub version 2.87.3 2016-12-19 16:38:27 +01:00
Rafa de la Torre
a4f059e20f Merge pull request #605 from CartoDB/update-camshaft-0.48.5
Update camshaft to 0.48.5
2016-12-19 16:33:27 +01:00
Rafa de la Torre
79c35118d7 Update camshaft to 0.48.5
Use exception safe Dataservices API functions. See
https://github.com/CartoDB/dataservices-api/issues/314 and
https://github.com/CartoDB/camshaft/issues/242
2016-12-19 15:52:25 +01:00
Javier Goizueta
6a4f5d52ec Don't use overviews for date histograms 2016-12-16 17:51:36 +01:00
Javier Goizueta
ccaae2dd66 Remove spurious parameter from overviews dataviews functions
In the overviews-specialized dataview classes the sql-generating
functions had an unneeded parameter filters.
In some cases, since this parameter was not being paaased from
the base dataviews class it was masking the override parameter.
2016-12-16 17:37:05 +01:00
Raul Ochoa
d335e64f88 Stubs next version 2016-12-13 14:16:49 +01:00
Raul Ochoa
177d7ed07a Release 2.87.1 2016-12-13 14:15:50 +01:00
Raul Ochoa
85a1e15b58 Merge pull request #603 from CartoDB/upgrade-deps
Upgrade windshaft and request deps
2016-12-13 14:15:04 +01:00
Raul Ochoa
432b58a078 Upgrade windshaft and request deps 2016-12-13 14:10:42 +01:00
xavijam
75e3c5daef Ready for next release 2016-12-13 10:43:16 +01:00
Raul Ochoa
deb71c27b0 Merge pull request #601 from CartoDB/update-turbocarto
Update turbocarto package version
2016-12-12 18:56:54 +01:00
Raul Ochoa
8f5e1de6d8 Merge branch 'master' into update-turbocarto 2016-12-12 18:51:04 +01:00
Raul Ochoa
4836d62d7a Merge pull request #602 from CartoDB/travis-improvements
Travis improvements
2016-12-12 18:50:39 +01:00
Raul Ochoa
d27b0617b2 Remove comments 2016-12-12 18:44:25 +01:00
Raul Ochoa
28a2c29a39 Attempt to use postgis 2.3 2016-12-12 18:39:57 +01:00
Raul Ochoa
fcb6478407 Attempt to use postgis 2.2 2016-12-12 18:33:19 +01:00
Raul Ochoa
6d72afe40e Test sudoless travis 2016-12-12 17:30:14 +01:00
Raul Ochoa
e775266c64 Remove notifications 2016-12-12 17:29:32 +01:00
xavijam
12f25b38c0 Updated news 2016-12-12 17:03:56 +01:00
xavijam
c67a1107cb Package version updated with turbo-carto cahnges 2016-12-12 17:02:31 +01:00
xavijam
34bfb0d62c Updated news 2016-12-12 17:02:15 +01:00
Javier Goizueta
ede45cad1f Stub next version 2016-12-02 15:25:52 +01:00
11 changed files with 1145 additions and 1753 deletions

View File

@@ -1,13 +1,10 @@
dist: trusty # only environment that supports Postgres 9.5 at this time
sudo: required
dist: trusty
addons:
postgresql: "9.5"
apt:
packages:
- postgresql-9.5-postgis-2.3
- postgresql-contrib-9.5
- postgresql-plpython-9.5
- postgis
- pkg-config
- libcairo2-dev
- libjpeg8-dev
@@ -25,9 +22,3 @@ env:
language: node_js
node_js:
- "0.10"
notifications:
irc:
channels:
- "irc.freenode.org#cartodb"
use_notice: true

33
NEWS.md
View File

@@ -1,12 +1,39 @@
# Changelog
## 2.86.2
Released 2017-09-01
## 2.87.4
Released 2017-01-20
Bug fixes:
- Adding a new cartodb-psql fixing a pg vulnerability
- Be able to not compute NULL categories and null values in aggregation dataviews #617.
## 2.87.3
Released 2016-12-19
Bug fixes:
- Fix overviews-related dataviews problems. See https://github.com/CartoDB/Windshaft-cartodb/pull/604
## 2.87.2
Released 2016-12-19
- Use exception safe Dataservices API functions. See https://github.com/CartoDB/dataservices-api/issues/314 and https://github.com/CartoDB/camshaft/issues/242
## 2.87.1
Released 2016-12-13
Announcements:
- Upgrades windshaft to [2.6.4](https://github.com/CartoDB/Windshaft/releases/tag/2.6.4).
- Upgrades request dependency.
- Regenerate npm-shrinkwrap.json: missing dependency updates.
## 2.87.0
Released 2016-12-12
Enhancements:
- Upgrade turbo-carto dependency to version 0.19.0.
## 2.86.1
Released 2016-12-02

View File

@@ -146,9 +146,9 @@ It is important to note that generated images are cached from the live data refe
### Limits
* While images can encompass an entirety of a map, the default limit for pixel range is 8192 x 8192.
* Image resolution by default is set to 72 DPI
* JPEG quality by default is 85%
* While images can encompass an entirety of a map, the limit for pixel range is 8192 x 8192.
* Image resolution is set to 72 DPI
* JPEG quality is 85%
* Timeout limits for generating static maps are the same across CARTO Builder and CARTO Engine. It is important to ensure timely processing of queries.
## Examples

View File

@@ -19,25 +19,37 @@ var rankedCategoriesQueryTpl = dot.template([
' SELECT {{=it._column}} AS category, {{=it._aggregation}} AS value,',
' row_number() OVER (ORDER BY {{=it._aggregation}} desc) as rank',
' FROM ({{=it._query}}) _cdb_aggregation_all',
' {{?it._aggregationColumn!==null}}WHERE {{=it._aggregationColumn}} IS NOT NULL{{?}}',
' GROUP BY {{=it._column}}',
' ORDER BY 2 DESC',
')'
].join('\n'));
var categoriesSummaryQueryTpl = dot.template([
'categories_summary AS(',
' SELECT count(1) categories_count, max(value) max_val, min(value) min_val',
var categoriesSummaryMinMaxQueryTpl = dot.template([
'categories_summary_min_max AS(',
' SELECT max(value) max_val, min(value) min_val',
' FROM categories',
')'
].join('\n'));
var categoriesSummaryCountQueryTpl = dot.template([
'categories_summary_count AS(',
' SELECT count(1) AS categories_count',
' FROM (',
' SELECT {{=it._column}} AS category',
' FROM ({{=it._query}}) _cdb_categories',
' GROUP BY {{=it._column}}',
' ) _cdb_categories_count',
')'
].join('\n'));
var rankedAggregationQueryTpl = dot.template([
'SELECT CAST(category AS text), value, false as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' FROM categories, summary, categories_summary_min_max, categories_summary_count',
' WHERE rank < {{=it._limit}}',
'UNION ALL',
'SELECT \'Other\' category, sum(value), true as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' FROM categories, summary, categories_summary_min_max, categories_summary_count',
' WHERE rank >= {{=it._limit}}',
'GROUP BY nulls_count, min_val, max_val, count, categories_count'
].join('\n'));
@@ -45,7 +57,7 @@ var rankedAggregationQueryTpl = dot.template([
var aggregationQueryTpl = dot.template([
'SELECT CAST({{=it._column}} AS text) AS category, {{=it._aggregation}} AS value, false as agg,',
' nulls_count, min_val, max_val, count, categories_count',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary_min_max, categories_summary_count',
'GROUP BY category, nulls_count, min_val, max_val, count, categories_count',
'ORDER BY value DESC'
].join('\n'));
@@ -114,6 +126,7 @@ Aggregation.prototype.sql = function(psql, override, callback) {
var _query = this.query;
var aggregationSql;
if (!!override.ownFilter) {
aggregationSql = [
"WITH",
@@ -125,9 +138,14 @@ Aggregation.prototype.sql = function(psql, override, callback) {
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
_aggregation: this.getAggregationSql(),
_aggregationColumn: this.aggregation !== 'count' ? this.aggregationColumn : null
}),
categoriesSummaryQueryTpl({
categoriesSummaryMinMaxQueryTpl({
_query: _query,
_column: this.column
}),
categoriesSummaryCountQueryTpl({
_query: _query,
_column: this.column
})
@@ -150,9 +168,14 @@ Aggregation.prototype.sql = function(psql, override, callback) {
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
_aggregation: this.getAggregationSql(),
_aggregationColumn: this.aggregation !== 'count' ? this.aggregationColumn : null
}),
categoriesSummaryQueryTpl({
categoriesSummaryMinMaxQueryTpl({
_query: _query,
_column: this.column
}),
categoriesSummaryCountQueryTpl({
_query: _query,
_column: this.column
})

View File

@@ -18,25 +18,37 @@ var rankedCategoriesQueryTpl = dot.template([
' SELECT {{=it._column}} AS category, {{=it._aggregation}} AS value,',
' row_number() OVER (ORDER BY {{=it._aggregation}} desc) as rank',
' FROM ({{=it._query}}) _cdb_aggregation_all',
' {{?it._aggregationColumn!==null}}WHERE {{=it._aggregationColumn}} IS NOT NULL{{?}}',
' GROUP BY {{=it._column}}',
' ORDER BY 2 DESC',
')'
].join('\n'));
var categoriesSummaryQueryTpl = dot.template([
'categories_summary AS(',
' SELECT count(1) categories_count, max(value) max_val, min(value) min_val',
var categoriesSummaryMinMaxQueryTpl = dot.template([
'categories_summary_min_max AS(',
' SELECT max(value) max_val, min(value) min_val',
' FROM categories',
')'
].join('\n'));
var categoriesSummaryCountQueryTpl = dot.template([
'categories_summary_count AS(',
' SELECT count(1) AS categories_count',
' FROM (',
' SELECT {{=it._column}} AS category',
' FROM ({{=it._query}}) _cdb_categories',
' GROUP BY {{=it._column}}',
' ) _cdb_categories_count',
')'
].join('\n'));
var rankedAggregationQueryTpl = dot.template([
'SELECT CAST(category AS text), value, false as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' FROM categories, summary, categories_summary_min_max, categories_summary_count',
' WHERE rank < {{=it._limit}}',
'UNION ALL',
'SELECT \'Other\' category, sum(value), true as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' FROM categories, summary, categories_summary_min_max, categories_summary_count',
' WHERE rank >= {{=it._limit}}',
'GROUP BY nulls_count, min_val, max_val, count, categories_count'
].join('\n'));
@@ -44,7 +56,7 @@ var rankedAggregationQueryTpl = dot.template([
var aggregationQueryTpl = dot.template([
'SELECT CAST({{=it._column}} AS text) AS category, {{=it._aggregation}} AS value, false as agg,',
' nulls_count, min_val, max_val, count, categories_count',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary_min_max, categories_summary_count',
'GROUP BY category, nulls_count, min_val, max_val, count, categories_count',
'ORDER BY value DESC'
].join('\n'));
@@ -65,7 +77,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 = {};
@@ -85,9 +97,14 @@ Aggregation.prototype.sql = function(psql, filters, override, callback) {
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
_aggregation: this.getAggregationSql(),
_aggregationColumn: this.aggregation !== 'count' ? this.aggregationColumn : null
}),
categoriesSummaryQueryTpl({
categoriesSummaryMinMaxQueryTpl({
_query: _query,
_column: this.column
}),
categoriesSummaryCountQueryTpl({
_query: _query,
_column: this.column
})
@@ -110,9 +127,14 @@ Aggregation.prototype.sql = function(psql, filters, override, callback) {
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
_aggregation: this.getAggregationSql(),
_aggregationColumn: this.aggregation !== 'count' ? this.aggregationColumn : null
}),
categoriesSummaryQueryTpl({
categoriesSummaryMinMaxQueryTpl({
_query: _query,
_column: this.column
}),
categoriesSummaryCountQueryTpl({
_query: _query,
_column: this.column
})

View File

@@ -55,20 +55,20 @@ BaseOverviewsDataview.prototype.rewrittenQuery = function(query) {
};
// Default behaviour
BaseOverviewsDataview.prototype.defaultSql = function(psql, filters, override, callback) {
BaseOverviewsDataview.prototype.defaultSql = function(psql, override, callback) {
var query = this.query;
var dataview = this.baseDataview;
if ( SETTINGS.defaultOverviews ) {
query = this.rewrittenQuery(query);
dataview = new this.BaseDataview(query, this.queryOptions);
}
return dataview.sql(psql, filters, override, callback);
return dataview.sql(psql, override, callback);
};
// default implementation that can be override in derived classes:
BaseOverviewsDataview.prototype.sql = function(psql, filters, override, callback) {
return this.defaultSql(psql, filters, override, callback);
BaseOverviewsDataview.prototype.sql = function(psql, override, callback) {
return this.defaultSql(psql, override, callback);
};
BaseOverviewsDataview.prototype.search = function(psql, userQuery, callback) {

View File

@@ -36,7 +36,7 @@ Formula.prototype.constructor = Formula;
module.exports = Formula;
Formula.prototype.sql = function(psql, filters, override, callback) {
Formula.prototype.sql = function(psql, override, callback) {
var formulaQueryTpl = formulaQueryTpls[this.operation];
if ( formulaQueryTpl ) {
@@ -52,5 +52,5 @@ Formula.prototype.sql = function(psql, filters, override, callback) {
}
// default behaviour
return this.defaultSql(psql, filters, override, callback);
return this.defaultSql(psql, override, callback);
};

View File

@@ -8,7 +8,6 @@ dot.templateSettings.strip = false;
var columnTypeQueryTpl = dot.template(
'SELECT pg_typeof({{=it.column}})::oid FROM ({{=it.query}}) _cdb_histogram_column_type limit 1'
);
var columnCastTpl = dot.template("date_part('epoch', {{=it.column}})");
var BIN_MIN_NUMBER = 6;
var BIN_MAX_NUMBER = 48;
@@ -149,7 +148,9 @@ Histogram.prototype.sql = function(psql, override, callback) {
}
if (this._columnType === 'date') {
_column = columnCastTpl({column: _column});
// overviews currently aggregate dates to NULL
// to avoid problem we don't use overviews for histograms of date columns
return this.defaultSql(psql, override, callback);
}
var _query = this.rewrittenQuery(this.query);

2650
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.86.2",
"version": "2.87.4",
"description": "A map tile server for CartoDB",
"keywords": [
"cartodb"
@@ -20,8 +20,8 @@
],
"dependencies": {
"body-parser": "~1.14.0",
"camshaft": "0.48.4",
"cartodb-psql": "0.10.1",
"camshaft": "0.48.5",
"cartodb-psql": "~0.6.1",
"cartodb-query-tables": "~0.1.0",
"cartodb-redis": "0.13.1",
"debug": "~2.2.0",
@@ -34,13 +34,14 @@
"node-statsd": "~0.0.7",
"queue-async": "~1.0.7",
"redis-mpool": "~0.4.0",
"request": "~2.62.0",
"request": "~2.79.0",
"step": "~0.0.6",
"step-profiler": "~0.3.0",
"turbo-carto": "0.18.0",
"turbo-carto": "0.19.0",
"underscore": "~1.6.0",
"windshaft": "2.6.3",
"yargs": "~5.0.0"
"windshaft": "2.6.5",
"yargs": "~5.0.0",
"zipfile": "cartodb/node-zipfile#0.5.11-cdb1"
},
"devDependencies": {
"istanbul": "~0.4.3",

View File

@@ -3,7 +3,7 @@ require('../../support/test_helper');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
describe('aggregations', function() {
describe('aggregations happy cases', function() {
afterEach(function(done) {
if (this.testClient) {
@@ -13,30 +13,36 @@ describe('aggregations', function() {
}
});
function aggregationOperationMapConfig(operation) {
return {
function aggregationOperationMapConfig(operation, query, column, aggregationColumn) {
column = column || 'adm0name';
aggregationColumn = aggregationColumn || 'pop_max';
query = query || 'select * from populated_places_simple_reduced';
var mapConfig = {
version: '1.5.0',
layers: [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
sql: query,
cartocss: '#layer0 { marker-fill: red; marker-width: 10; }',
cartocss_version: '2.0.1',
widgets: {
adm0name: {
type: 'aggregation',
options: {
column: 'adm0name',
aggregation: operation,
aggregationColumn: 'pop_max'
}
}
}
widgets: {}
}
}
]
};
mapConfig.layers[0].options.widgets[column] = {
type: 'aggregation',
options: {
column: column,
aggregation: operation,
aggregationColumn: aggregationColumn
}
};
return mapConfig;
}
var operations = ['count', 'sum', 'avg', 'max', 'min'];
@@ -56,4 +62,49 @@ describe('aggregations', function() {
});
});
});
var query = [
'select 1 as val, \'a\' as cat, ST_Transform(ST_SetSRID(ST_MakePoint(0,0),4326),3857) as the_geom_webmercator',
'select null, \'b\', ST_Transform(ST_SetSRID(ST_MakePoint(0,1),4326),3857)',
'select null, \'b\', ST_Transform(ST_SetSRID(ST_MakePoint(1,0),4326),3857)',
'select null, null, ST_Transform(ST_SetSRID(ST_MakePoint(1,1),4326),3857)'
].join(' UNION ALL ');
operations.forEach(function (operation) {
var not = operation === 'count' ? ' not ' : ' ';
var description = 'should' +
not +
'handle NULL values in category and aggregation columns using "' +
operation +
'" as aggregation operation';
it(description, function (done) {
this.testClient = new TestClient(aggregationOperationMapConfig(operation, query, 'cat', 'val'));
this.testClient.getDataview('cat', { own_filter: 0 }, function (err, aggregation) {
assert.ifError(err);
assert.ok(aggregation);
assert.equal(aggregation.type, 'aggregation');
assert.ok(aggregation.categories);
assert.equal(aggregation.categoriesCount, 3);
assert.equal(aggregation.count, 4);
assert.equal(aggregation.nulls, 1);
var hasNullCategory = false;
aggregation.categories.forEach(function (category) {
if (category.category === null) {
hasNullCategory = true;
}
});
if (operation === 'count') {
assert.ok(hasNullCategory, 'aggregation has not a category NULL');
} else {
assert.ok(!hasNullCategory, 'aggregation has category NULL');
}
done();
});
});
});
});