From 8a48b96c53134c75caefb7adf881a22faebb49fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 18 Dec 2017 19:06:01 +0100 Subject: [PATCH] Rename file --- .../aggregation/aggregation-mapconfig.js | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 lib/cartodb/models/aggregation/aggregation-mapconfig.js diff --git a/lib/cartodb/models/aggregation/aggregation-mapconfig.js b/lib/cartodb/models/aggregation/aggregation-mapconfig.js new file mode 100644 index 00000000..379d7739 --- /dev/null +++ b/lib/cartodb/models/aggregation/aggregation-mapconfig.js @@ -0,0 +1,165 @@ +const MapConfig = require('windshaft').model.MapConfig; +const aggregationQuery = require('./aggregation-query'); + +module.exports = class AggregationMapConfig extends MapConfig { + static get PLACEMENTS () { + return [ + 'centroid', + 'point-grid', + 'point-sample' + ]; + } + + static get PLACEMENT () { + return AggregationMapConfig.PLACEMENTS[0]; + } + + static get THRESHOLD () { + return 1e5; // 100K + } + + static get RESOLUTION () { + return 1; + } + + static get SUPPORTED_GEOMETRY_TYPES () { + return [ + 'ST_Point' + ]; + } + + static supportsGeometryType(geometryType) { + return AggregationMapConfig.SUPPORTED_GEOMETRY_TYPES.includes(geometryType); + } + + constructor (config, datasource) { + super(config, datasource); + + this.validate(); + } + + getAggregatedQuery (index) { + const { sql_raw, sql } = this.getLayer(index).options; + const { + resolution = AggregationMapConfig.RESOLUTION, + threshold = AggregationMapConfig.THRESHOLD, + placement = AggregationMapConfig.PLACEMENT, + columns = {}, + dimmensions = {} + } = this.getAggregation(index); + + return aggregationQuery({ + query: sql_raw || sql, + resolution, + threshold, + placement, + columns, + dimmensions + }); + } + + isAggregationMapConfig () { + return this.isVectorOnlyMapConfig() || this.hasAnyLayerAggregation(); + } + + isAggregationLayer (index) { + return this.isVectorOnlyMapConfig() || this.hasLayerAggregation(index); + } + + hasAnyLayerAggregation () { + const layers = this.getLayers(); + + for (let index = 0; index < layers.length; index++) { + if (this.hasLayerAggregation(index)) { + return true; + } + } + + return false; + } + + hasLayerAggregation (index) { + const layer = this.getLayer(index); + const { aggregation } = layer.options; + + return aggregation !== undefined && (typeof aggregation === 'object' || typeof aggregation === 'boolean'); + } + + getAggregation (index) { + if (!this.hasLayerAggregation(index)) { + return; + } + + const { aggregation } = this.getLayer(index).options; + + if (typeof aggregation === 'boolean') { + return {}; + } + + return aggregation; + } + + doesLayerReachThreshold(index, featureCount) { + const threshold = this.getAggregation(index) && this.getAggregation(index).threshold ? + this.getAggregation(index).threshold : + AggregationMapConfig.THRESHOLD; + + return featureCount >= threshold; + } + + validate () { + const validate = aggregationValidator(this); + const numberValidator = createNumberValidator(this); + const includesValidPlacementsValidator = createIncludesValueValidator(this, AggregationMapConfig.PLACEMENTS); + + validate('resolution', numberValidator); + validate('placement', includesValidPlacementsValidator); + validate('threshold', numberValidator); + } +}; + +function aggregationValidator (mapconfig) { + return function validateProperty (prop, validator) { + for (let index = 0; index < mapconfig.getLayers().length; index++) { + const aggregation = mapconfig.getAggregation(index); + + if (aggregation === undefined || aggregation[prop] === undefined) { + continue; + } + + validator(aggregation[prop], prop, index); + } + }; +} + +function createIncludesValueValidator(mapconfig, validValues) { + return function validateIncludesValue (prop, key, index) { + if (!validValues.includes(prop)) { + const error = new Error(`Invalid ${key}. Valid values: ${validValues.join(', ')}`); + error.type = 'layer'; + error.layer = { + id: mapconfig.getLayerId(index), + index: index, + type: mapconfig.layerType(index) + }; + + throw error; + } + }; +} + +function createNumberValidator(mapconfig) { + return function validateNumber (prop, key, index) { + if (!Number.isFinite(prop) || prop <= 0) { + const error = new Error(`Invalid ${key}, should be a number greather than 0`); + error.type = 'layer'; + error.layer = { + id: mapconfig.getLayerId(index), + index: index, + type: mapconfig.layerType(index) + }; + + throw error; + } + }; +}