2017-12-19 02:05:49 +08:00
|
|
|
const AggregationMapConfig = require('../../aggregation/aggregation-mapconfig');
|
2017-12-12 00:32:06 +08:00
|
|
|
const queryUtils = require('../../../utils/query-utils');
|
2017-12-01 02:20:59 +08:00
|
|
|
|
2017-12-12 00:32:06 +08:00
|
|
|
const unsupportedGeometryTypeErrorMessage = ctx =>
|
2017-12-19 01:53:44 +08:00
|
|
|
`Unsupported geometry type: ${ctx.geometryType}. ` +
|
|
|
|
`Aggregation is available only for geometry type: ${AggregationMapConfig.SUPPORTED_GEOMETRY_TYPES}`;
|
2017-12-05 02:48:06 +08:00
|
|
|
|
2017-12-13 02:23:21 +08:00
|
|
|
const invalidAggregationParamValueErrorMessage = ctx =>
|
|
|
|
`Invalid value for 'aggregation' query param: ${ctx.value}. Valid ones are 'true' or 'false'`;
|
|
|
|
|
2017-12-01 02:20:59 +08:00
|
|
|
module.exports = class AggregationMapConfigAdapter {
|
2017-12-12 00:32:06 +08:00
|
|
|
constructor (pgConnection) {
|
|
|
|
this.pgConnection = pgConnection;
|
|
|
|
}
|
|
|
|
|
2017-12-01 02:20:59 +08:00
|
|
|
getMapConfig (user, requestMapConfig, params, context, callback) {
|
2017-12-19 17:50:53 +08:00
|
|
|
if (!this._isValidAggregationQueryParam(params)) {
|
2017-12-13 02:23:21 +08:00
|
|
|
return callback(new Error(invalidAggregationParamValueErrorMessage({ value: params.aggregation })));
|
|
|
|
}
|
|
|
|
|
2017-12-19 19:23:54 +08:00
|
|
|
let mapConfig;
|
|
|
|
try {
|
2017-12-23 01:19:57 +08:00
|
|
|
mapConfig = new AggregationMapConfig(user, requestMapConfig, this.pgConnection);
|
2017-12-19 19:23:54 +08:00
|
|
|
} catch (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
2017-12-05 02:48:06 +08:00
|
|
|
|
2017-12-13 03:10:42 +08:00
|
|
|
if (!this._shouldAdapt(mapConfig, params)) {
|
|
|
|
return callback(null, requestMapConfig);
|
|
|
|
}
|
|
|
|
|
2017-12-12 02:12:10 +08:00
|
|
|
this.pgConnection.getConnection(user, (err, connection) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._adaptLayers(connection, mapConfig, requestMapConfig, context, callback);
|
|
|
|
});
|
2017-12-01 02:20:59 +08:00
|
|
|
}
|
|
|
|
|
2017-12-19 17:50:53 +08:00
|
|
|
_isValidAggregationQueryParam (params) {
|
2017-12-13 02:23:21 +08:00
|
|
|
const { aggregation } = params;
|
|
|
|
return aggregation === undefined || aggregation === 'true' || aggregation === 'false';
|
|
|
|
}
|
|
|
|
|
2017-12-13 00:58:42 +08:00
|
|
|
_shouldAdapt (mapConfig, params) {
|
2017-12-05 19:59:32 +08:00
|
|
|
const { aggregation } = params;
|
2017-12-02 00:06:42 +08:00
|
|
|
|
2017-12-05 19:59:32 +08:00
|
|
|
if (aggregation === 'false') {
|
2017-12-12 17:57:50 +08:00
|
|
|
return false;
|
2017-12-12 17:49:05 +08:00
|
|
|
}
|
|
|
|
|
2017-12-13 02:23:21 +08:00
|
|
|
if (aggregation === 'true' || mapConfig.isAggregationMapConfig()) {
|
2017-12-12 17:57:50 +08:00
|
|
|
return true;
|
2017-12-12 17:56:23 +08:00
|
|
|
}
|
|
|
|
|
2017-12-01 02:20:59 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-12 02:12:10 +08:00
|
|
|
_adaptLayers (connection, mapConfig, requestMapConfig, context, callback) {
|
|
|
|
const adaptLayerPromises = requestMapConfig.layers.map((layer, index) => {
|
2017-12-13 00:58:42 +08:00
|
|
|
return this._adaptLayer(connection, mapConfig, layer, index);
|
2017-12-01 22:43:15 +08:00
|
|
|
});
|
2017-12-12 02:12:10 +08:00
|
|
|
|
|
|
|
Promise.all(adaptLayerPromises)
|
|
|
|
.then(results => {
|
|
|
|
context.aggregation = {
|
|
|
|
layers: []
|
|
|
|
};
|
|
|
|
|
|
|
|
results.forEach(({ layer, index, adapted }) => {
|
|
|
|
if (adapted) {
|
|
|
|
requestMapConfig.layers[index] = layer;
|
|
|
|
}
|
2017-12-13 00:58:42 +08:00
|
|
|
const aggregatedFormats = this._getAggregationMetadata(mapConfig, layer, adapted);
|
2017-12-12 02:12:10 +08:00
|
|
|
context.aggregation.layers.push(aggregatedFormats);
|
|
|
|
});
|
|
|
|
|
2017-12-12 02:35:59 +08:00
|
|
|
callback(null, requestMapConfig);
|
2017-12-12 02:12:10 +08:00
|
|
|
})
|
|
|
|
.catch(err => callback(err));
|
2017-12-01 22:43:15 +08:00
|
|
|
}
|
2017-12-04 19:40:53 +08:00
|
|
|
|
2017-12-13 00:58:42 +08:00
|
|
|
_adaptLayer (connection, mapConfig, layer, index) {
|
2017-12-12 01:34:22 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
2017-12-13 00:58:42 +08:00
|
|
|
this._shouldAdaptLayer(connection, mapConfig, layer, index, (err, shouldAdapt) => {
|
2017-12-12 01:34:22 +08:00
|
|
|
if (err) {
|
2017-12-12 02:06:53 +08:00
|
|
|
return reject(err);
|
2017-12-12 01:34:22 +08:00
|
|
|
}
|
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
if (!shouldAdapt) {
|
|
|
|
return resolve({ layer, index, adapted: shouldAdapt });
|
|
|
|
}
|
2017-12-12 01:47:20 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
const sqlQueryWrap = layer.options.sql_wrap;
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
let aggregationSql = mapConfig.getAggregatedQuery(index);
|
2017-12-22 03:00:17 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
if (sqlQueryWrap) {
|
|
|
|
aggregationSql = sqlQueryWrap.replace(/<%=\s*sql\s*%>/g, aggregationSql);
|
|
|
|
}
|
2017-12-22 03:00:17 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
if (!mapConfig.isDefaultLayerAggregation(index)) {
|
|
|
|
layer.options.sql = aggregationSql;
|
|
|
|
return resolve({ layer, index, adapted: shouldAdapt });
|
|
|
|
}
|
2017-12-23 01:19:57 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
const skipGeoms = true;
|
|
|
|
mapConfig.getLayerColumns(index, skipGeoms, (err, columns) => {
|
|
|
|
if (err) {
|
|
|
|
return reject(err);
|
2017-12-23 01:19:57 +08:00
|
|
|
}
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-28 03:08:43 +08:00
|
|
|
layer.options.sql = aggregationSql;
|
|
|
|
layer.options.columns = columns;
|
|
|
|
|
|
|
|
return resolve({ layer, index, adapted: shouldAdapt });
|
|
|
|
});
|
2017-12-12 02:06:53 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-13 00:58:42 +08:00
|
|
|
_shouldAdaptLayer (connection, mapConfig, layer, index, callback) {
|
|
|
|
if (!mapConfig.isAggregationLayer(index)) {
|
2017-12-19 01:55:32 +08:00
|
|
|
return callback(null, false);
|
2017-12-12 02:06:53 +08:00
|
|
|
}
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-13 23:34:36 +08:00
|
|
|
const aggregationMetadata = queryUtils.getAggregationMetadata({
|
|
|
|
query: layer.options.sql_raw ? layer.options.sql_raw : layer.options.sql
|
|
|
|
});
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-12 02:06:53 +08:00
|
|
|
connection.query(aggregationMetadata, (err, res) => {
|
|
|
|
if (err) {
|
2017-12-19 01:55:32 +08:00
|
|
|
return callback(null, false);
|
2017-12-12 02:06:53 +08:00
|
|
|
}
|
2017-12-12 01:34:22 +08:00
|
|
|
|
2017-12-12 19:53:29 +08:00
|
|
|
const result = res.rows[0] || {};
|
2017-12-12 02:06:53 +08:00
|
|
|
|
2017-12-19 01:53:44 +08:00
|
|
|
if (!AggregationMapConfig.supportsGeometryType(result.type)) {
|
2017-12-19 17:54:20 +08:00
|
|
|
const message = unsupportedGeometryTypeErrorMessage({ geometryType: result.type });
|
|
|
|
const error = new Error(message);
|
2017-12-19 02:35:12 +08:00
|
|
|
error.type = 'layer';
|
|
|
|
error.layer = {
|
|
|
|
id: mapConfig.getLayerId(index),
|
|
|
|
index: index,
|
|
|
|
type: mapConfig.layerType(index)
|
|
|
|
};
|
|
|
|
|
|
|
|
return callback(error);
|
2017-12-12 02:06:53 +08:00
|
|
|
}
|
|
|
|
|
2017-12-19 01:56:53 +08:00
|
|
|
if (!mapConfig.doesLayerReachThreshold(index, result.count)) {
|
|
|
|
return callback(null, false);
|
|
|
|
}
|
|
|
|
|
2017-12-19 01:55:32 +08:00
|
|
|
callback(null, true);
|
2017-12-12 01:34:22 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-13 00:58:42 +08:00
|
|
|
_getAggregationMetadata (mapConfig, layer, adapted) {
|
2017-12-12 17:43:49 +08:00
|
|
|
if (!adapted) {
|
|
|
|
return { png: false, mvt: false };
|
|
|
|
}
|
2017-12-12 00:32:06 +08:00
|
|
|
|
2017-12-13 00:58:42 +08:00
|
|
|
if (mapConfig.isVectorOnlyMapConfig()) {
|
2017-12-12 17:43:49 +08:00
|
|
|
return { png: false, mvt: true };
|
2017-12-06 03:39:30 +08:00
|
|
|
}
|
|
|
|
|
2017-12-12 17:43:49 +08:00
|
|
|
return { png: true, mvt: true };
|
2017-12-04 19:40:53 +08:00
|
|
|
}
|
2017-12-01 02:20:59 +08:00
|
|
|
};
|