Windshaft-cartodb/lib/utils/query-utils.js

141 lines
4.6 KiB
JavaScript
Raw Normal View History

'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;
2018-05-09 02:07:20 +08:00
module.exports.getQueryActualRowCount = function (query) {
return `select COUNT(*) AS rows FROM (${substituteDummyTokens(query)}) AS __cdb_query`;
2018-05-09 02:07:20 +08:00
};
2019-10-22 01:07:24 +08:00
function getQueryRowEstimation (query) {
return 'select CDB_EstimateRowCount($windshaft$' + substituteDummyTokens(query) + '$windshaft$) as rows';
}
2018-05-09 02:07:20 +08:00
module.exports.getQueryRowEstimation = getQueryRowEstimation;
2019-10-22 01:07:24 +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;
module.exports.getAggregationMetadata = ctx => `
WITH
rowEstimation AS (
${getQueryRowEstimation(ctx.query)}
),
geometryType AS (
${getQueryGeometryType(ctx.query, ctx.geometryColumn)}
)
SELECT
rows AS count,
geom_type AS type
FROM rowEstimation, geometryType;
`;
/** Cast the column to epoch */
2019-10-22 01:07:24 +08:00
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) */
2019-10-22 01:07:24 +08:00
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 */
2019-10-22 01:07:24 +08:00
module.exports.countNULLs = function countNULLs (ctx) {
return `sum(CASE WHEN (${ctx.column} IS NULL) THEN 1 ELSE 0 END)`;
};
/** Count only infinity (positive and negative) appearances */
2019-10-22 01:07:24 +08:00
module.exports.countInfinites = function countInfinites (ctx) {
return `${!ctx.isFloatColumn ? '0'
: `sum(CASE WHEN (${ctx.column} = 'infinity'::float OR ${ctx.column} = '-infinity'::float) THEN 1 ELSE 0 END)`
}`;
};
2019-10-22 01:07:24 +08:00
/** Count only NaNs appearances */
module.exports.countNaNs = function countNaNs (ctx) {
return `${!ctx.isFloatColumn ? '0'
: `sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)`
}`;
};
2018-05-08 01:03:19 +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
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
2019-10-22 01:07:24 +08:00
function columnSelector (columns) {
if (!columns) {
return '*';
}
if (typeof columns === 'string') {
return columns;
}
if (Array.isArray(columns)) {
return columns.map(name => `"${name}"`).join(', ');
}
throw new TypeError(`Bad argument type for columns: ${typeof columns}`);
}
2019-08-23 23:25:37 +08:00
module.exports.getMaxMinSpanColumnQuery = function (query, column = 'cartodb_id') {
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;
`;
};
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
WHERE ${column} IN (${ids.join(',')})
`;
};
2018-05-08 01:03:19 +08:00
2019-10-22 01:07:24 +08:00
function getQueryLimited (query, limit = 0) {
2018-05-08 01:03:19 +08:00
return `
SELECT *
FROM (${substituteDummyTokens(query)}) AS __cdb_query
2018-05-08 01:03:19 +08:00
LIMIT ${limit}
`;
}
2019-10-22 01:07:24 +08:00
function queryPromise (dbConnection, query) {
2018-06-01 00:37:43 +08:00
return new Promise((resolve, reject) => {
2019-10-22 01:07:24 +08:00
dbConnection.query(query, (err, res) => err ? reject(err) : resolve(res));
2018-06-01 00:37:43 +08:00
});
}
2019-10-22 01:07:24 +08:00
function substituteDummyTokens (sql) {
2019-09-13 22:32:37 +08:00
return SubstitutionTokens.replace(sql);
}
2019-10-22 01:07:24 +08:00
function substituteTokensForZoom (sql, zoom) {
const extent = new WebMercatorHelper().getExtent({ x: 0, y: 0, z: 0 });
2019-09-13 22:32:37 +08:00
const bbox = `ST_MakeEnvelope(${extent.xmin}, ${extent.ymin}, ${extent.xmax}, ${extent.ymax}, 3857)`;
2019-10-22 01:07:24 +08:00
return SubstitutionTokens.replaceXYZ(sql, { z: zoom, bbox: bbox });
}
2018-06-01 00:37:43 +08:00
module.exports.queryPromise = queryPromise;
module.exports.getQueryLimited = getQueryLimited;
module.exports.substituteDummyTokens = substituteDummyTokens;
2019-09-13 22:32:37 +08:00
module.exports.substituteTokensForZoom = substituteTokensForZoom;