Remove support for arbitrary aggregation SQL expressions.

Only the supported aggregate functions can be used now, currently count, sum, avg, min & max.
This commit is contained in:
Javier Goizueta 2017-12-12 16:17:42 +01:00
parent eb2825eea8
commit 4405d61845

View File

@ -9,7 +9,25 @@ module.exports = (options) => {
return templateFn;
};
const aggregate_columns = ctx => {
const SUPPORTED_AGGREGATE_FUNCTIONS = {
'count': {
sql: (column_name, params) => `count(${params.aggregated_column || '*'})`
},
'avg': {
sql: (column_name, params) => `avg(${params.aggregated_column || column_name})`
},
'sum': {
sql: (column_name, params) => `sum(${params.aggregated_column || column_name})`
},
'min': {
sql: (column_name, params) => `min(${params.aggregated_column || column_name})`
},
'max': {
sql: (column_name, params) => `max(${params.aggregated_column || column_name})`
}
};
const aggregateColumns = ctx => {
let columns = ctx.columns || {};
if (Object.keys(columns).length === 0) {
// default aggregation
@ -20,21 +38,22 @@ const aggregate_columns = ctx => {
};
}
return Object.keys(columns).map(column_name => {
let aggregate_expression = columns[column_name].aggregate_expression;
if (!aggregate_expression) {
const aggregate_function = columns[column_name].aggregate_function || 'count';
const aggregated_column = columns[column_name].aggregated_column || '*';
aggregate_expression = `${aggregate_function}(${aggregated_column})`;
const aggregate_definition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregate_function];
if (!aggregate_definition) {
throw new Error("Invalid Aggregate function: '" + aggregate_function + "'");
}
const aggregate_expression = aggregate_definition.sql(column_name, columns[column_name]);
return `${aggregate_expression} AS ${column_name}`;
}).join(', ');
};
// Notes:
// * ${ctx.res*0.00028/256}*!scale_denominator! is equivalent to
// * ${ctx.res/256}*CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!))
// * We need to filter spatially using !bbox! to make the queries efficient because the filter added by Mapnik
// * (wrapping the query) is only applied after the aggregation.
// ${ctx.res/256}*CDB_XYZ_Resolution(CDB_ZoomFromScale(!scale_denominator!))
// * We need to filter spatially using !bbox! to make the queries efficient because
// the filter added by Mapnik (wrapping the query)
// is only applied after the aggregation.
// * This queries are used for rendering and the_geom is omitted in the results for better performance
const aggregationQueryTemplates = {
@ -52,7 +71,7 @@ const aggregationQueryTemplates = {
AVG(ST_Y(_cdb_query.the_geom_webmercator))
), 3857
) AS the_geom_webmercator,
${aggregate_columns(ctx)}
${aggregateColumns(ctx)}
FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params
WHERE _cdb_query.the_geom_webmercator && _cdb_params.bbox
GROUP BY
@ -77,7 +96,7 @@ const aggregationQueryTemplates = {
) AS the_geom_webmercator,
Floor(ST_X(_cdb_query.the_geom_webmercator)/_cdb_params.res)::int AS _cdb_gx,
Floor(ST_Y(_cdb_query.the_geom_webmercator)/_cdb_params.res)::int AS _cdb_gy,
${aggregate_columns(ctx)}
${aggregateColumns(ctx)}
FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params
WHERE the_geom_webmercator && _cdb_params.bbox
GROUP BY _cdb_gx, _cdb_gy
@ -97,7 +116,7 @@ const aggregationQueryTemplates = {
), _cdb_clusters AS (
SELECT
MIN(cartodb_id) AS cartodb_id,
${aggregate_columns(ctx)}
${aggregateColumns(ctx)}
FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params
WHERE _cdb_query.the_geom_webmercator && _cdb_params.bbox
GROUP BY