2018-10-23 23:45:42 +08:00
|
|
|
'use strict';
|
|
|
|
|
2019-09-13 22:32:37 +08:00
|
|
|
const SubstitutionTokens = require('cartodb-query-tables').utils.substitutionTokens;
|
|
|
|
const WebMercatorHelper = require('cartodb-query-tables').utils.webMercatorHelper;
|
2017-05-18 02:16:43 +08:00
|
|
|
|
2018-05-09 02:07:20 +08:00
|
|
|
module.exports.getQueryActualRowCount = function (query) {
|
2019-07-15 20:16:21 +08:00
|
|
|
return `select COUNT(*) AS rows FROM (${substituteDummyTokens(query)}) AS __cdb_query`;
|
2018-05-09 02:07:20 +08:00
|
|
|
};
|
|
|
|
|
2017-12-12 00:32:06 +08:00
|
|
|
function getQueryRowEstimation(query) {
|
2019-07-15 20:16:21 +08:00
|
|
|
return 'select CDB_EstimateRowCount($windshaft$' + substituteDummyTokens(query) + '$windshaft$) as rows';
|
2017-12-12 00:32:06 +08:00
|
|
|
}
|
2018-05-09 02:07:20 +08:00
|
|
|
module.exports.getQueryRowEstimation = getQueryRowEstimation;
|
2017-12-12 00:32:06 +08:00
|
|
|
|
2019-07-15 20:16:21 +08:00
|
|
|
function getQueryGeometryType(query, geometryColumn) {
|
|
|
|
return `
|
|
|
|
SELECT ST_GeometryType(${geometryColumn}) AS geom_type
|
|
|
|
FROM (${substituteDummyTokens(query)}) AS __cdb_query
|
|
|
|
WHERE ${geometryColumn} IS NOT NULL
|
|
|
|
LIMIT 1
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
module.exports.getQueryGeometryType = getQueryGeometryType;
|
|
|
|
|
2017-12-12 00:32:06 +08:00
|
|
|
module.exports.getAggregationMetadata = ctx => `
|
|
|
|
WITH
|
|
|
|
rowEstimation AS (
|
|
|
|
${getQueryRowEstimation(ctx.query)}
|
|
|
|
),
|
|
|
|
geometryType AS (
|
2019-07-15 20:16:21 +08:00
|
|
|
${getQueryGeometryType(ctx.query, ctx.geometryColumn)}
|
2017-12-12 00:32:06 +08:00
|
|
|
)
|
|
|
|
SELECT
|
|
|
|
rows AS count,
|
|
|
|
geom_type AS type
|
|
|
|
FROM rowEstimation, geometryType;
|
|
|
|
`;
|
2017-11-29 20:07:59 +08:00
|
|
|
|
|
|
|
/** Cast the column to epoch */
|
|
|
|
module.exports.columnCastTpl = function columnCastTpl(ctx) {
|
|
|
|
return `date_part('epoch', ${ctx.column})`;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** If the column type is float, ignore any non numeric result (infinity / NaN) */
|
|
|
|
module.exports.handleFloatColumn = function handleFloatColumn(ctx) {
|
|
|
|
return `${!ctx.isFloatColumn ? `${ctx.column}` :
|
|
|
|
`nullif(nullif(nullif(${ctx.column}, 'infinity'::float), '-infinity'::float), 'NaN'::float)`
|
|
|
|
}`;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Count NULL appearances */
|
2018-05-31 18:41:34 +08:00
|
|
|
module.exports.countNULLs = function countNULLs(ctx) {
|
2017-11-29 20:07:59 +08:00
|
|
|
return `sum(CASE WHEN (${ctx.column} IS NULL) THEN 1 ELSE 0 END)`;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Count only infinity (positive and negative) appearances */
|
|
|
|
module.exports.countInfinites = function countInfinites(ctx) {
|
2018-05-31 18:41:34 +08:00
|
|
|
return `${!ctx.isFloatColumn ? '0' :
|
2017-11-29 20:07:59 +08:00
|
|
|
`sum(CASE WHEN (${ctx.column} = 'infinity'::float OR ${ctx.column} = '-infinity'::float) THEN 1 ELSE 0 END)`
|
|
|
|
}`;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Count only NaNs appearances*/
|
|
|
|
module.exports.countNaNs = function countNaNs(ctx) {
|
2018-05-31 18:41:34 +08:00
|
|
|
return `${!ctx.isFloatColumn ? '0' :
|
2017-11-29 20:07:59 +08:00
|
|
|
`sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)`
|
|
|
|
}`;
|
2017-12-12 00:36:58 +08:00
|
|
|
};
|
2018-05-08 01:03:19 +08:00
|
|
|
|
2018-05-31 18:41:34 +08:00
|
|
|
module.exports.getQueryTopCategories = function (query, column, topN, includeNulls = false) {
|
2018-05-08 01:03:19 +08:00
|
|
|
const where = includeNulls ? '' : `WHERE ${column} IS NOT NULL`;
|
|
|
|
return `
|
|
|
|
SELECT ${column} AS category, COUNT(*) AS frequency
|
2019-07-15 20:16:21 +08:00
|
|
|
FROM (${substituteDummyTokens(query)}) AS __cdb_query
|
2018-05-08 01:03:19 +08:00
|
|
|
${where}
|
|
|
|
GROUP BY ${column} ORDER BY 2 DESC
|
|
|
|
LIMIT ${topN}
|
|
|
|
`;
|
2018-05-08 17:07:47 +08:00
|
|
|
};
|
2018-05-08 01:03:19 +08:00
|
|
|
|
2018-05-28 22:08:31 +08:00
|
|
|
function columnSelector(columns) {
|
|
|
|
if (!columns) {
|
|
|
|
return '*';
|
|
|
|
}
|
2018-05-28 23:36:58 +08:00
|
|
|
if (typeof columns === 'string') {
|
2018-05-28 22:08:31 +08:00
|
|
|
return columns;
|
|
|
|
}
|
2018-05-28 23:36:58 +08:00
|
|
|
if (Array.isArray(columns)) {
|
|
|
|
return columns.map(name => `"${name}"`).join(', ');
|
|
|
|
}
|
|
|
|
throw new TypeError(`Bad argument type for columns: ${typeof columns}`);
|
2018-05-28 22:08:31 +08:00
|
|
|
}
|
|
|
|
|
2019-08-23 23:25:37 +08:00
|
|
|
module.exports.getMaxMinSpanColumnQuery = function (query, column = 'cartodb_id') {
|
2019-08-23 23:10:46 +08:00
|
|
|
return `
|
|
|
|
SELECT
|
|
|
|
min(${column}) AS min_id,
|
|
|
|
max(${column}) AS max_id,
|
|
|
|
(max(${column}) - min(${column})) AS id_span
|
2019-08-23 23:25:37 +08:00
|
|
|
FROM (${substituteDummyTokens(query)}) _cdb_metadata_max_min_span;
|
2019-08-23 23:10:46 +08:00
|
|
|
`;
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports.getSampleFromIdsQuery = function (query, ids, columns, column = 'cartodb_id') {
|
|
|
|
return `
|
|
|
|
SELECT
|
|
|
|
${columnSelector(columns)}
|
2019-08-23 23:21:01 +08:00
|
|
|
FROM (${substituteDummyTokens(query)}) _cdb_metadata_sample
|
2019-08-23 23:10:46 +08:00
|
|
|
WHERE ${column} IN (${ids.join(',')})
|
|
|
|
`;
|
|
|
|
};
|
2018-05-08 01:03:19 +08:00
|
|
|
|
2018-05-31 18:41:34 +08:00
|
|
|
function getQueryLimited(query, limit = 0) {
|
2018-05-08 01:03:19 +08:00
|
|
|
return `
|
|
|
|
SELECT *
|
2019-07-15 20:16:21 +08:00
|
|
|
FROM (${substituteDummyTokens(query)}) AS __cdb_query
|
2018-05-08 01:03:19 +08:00
|
|
|
LIMIT ${limit}
|
|
|
|
`;
|
2018-05-31 18:41:34 +08:00
|
|
|
}
|
|
|
|
|
2018-06-01 00:37:43 +08:00
|
|
|
function queryPromise(dbConnection, query) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
dbConnection.query(query, (err, res) => err ? reject(err) : resolve(res));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-06-18 19:15:45 +08:00
|
|
|
function substituteDummyTokens(sql) {
|
2019-09-13 22:32:37 +08:00
|
|
|
return SubstitutionTokens.replace(sql);
|
2018-06-18 19:15:45 +08:00
|
|
|
}
|
|
|
|
|
2019-09-13 22:32:37 +08:00
|
|
|
function substituteTokensForZoom(sql, zoom) {
|
|
|
|
const extent = new WebMercatorHelper().getExtent({ x : 0, y : 0, z : 0 });
|
|
|
|
const bbox = `ST_MakeEnvelope(${extent.xmin}, ${extent.ymin}, ${extent.xmax}, ${extent.ymax}, 3857)`;
|
|
|
|
return SubstitutionTokens.replaceXYZ(sql, { z : zoom, bbox: bbox });
|
2018-06-18 19:15:45 +08:00
|
|
|
}
|
|
|
|
|
2018-06-01 00:37:43 +08:00
|
|
|
module.exports.queryPromise = queryPromise;
|
2018-06-18 19:15:45 +08:00
|
|
|
module.exports.getQueryLimited = getQueryLimited;
|
|
|
|
module.exports.substituteDummyTokens = substituteDummyTokens;
|
2019-09-13 22:32:37 +08:00
|
|
|
module.exports.substituteTokensForZoom = substituteTokensForZoom;
|