diff --git a/lib/cartodb/models/mapconfig/provider/base-mapconfig-adapter.js b/lib/cartodb/models/mapconfig/provider/base-mapconfig-adapter.js new file mode 100644 index 00000000..c783bdd4 --- /dev/null +++ b/lib/cartodb/models/mapconfig/provider/base-mapconfig-adapter.js @@ -0,0 +1,65 @@ +const QueryTables = require('cartodb-query-tables'); + +module.exports = class BaseMapConfigProvider { + createAffectedTables (callback) { + this.getMapConfig((err, mapConfig) => { + if (err) { + return callback(err); + } + + const { dbname } = this.params; + const token = mapConfig.id(); + + const queries = []; + + this.mapConfig.getLayers().forEach(layer => { + queries.push(layer.options.sql); + if (layer.options.affected_tables) { + layer.options.affected_tables.map(table => { + queries.push(`SELECT * FROM ${table} LIMIT 0`); + }); + } + }); + + const sql = queries.length ? queries.join(';') : null; + + if (!sql) { + return callback(); + } + + this.pgConnection.getConnection(this.user, (err, connection) => { + if (err) { + return callback(err); + } + + QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => { + if (err) { + return callback(err); + } + + this.affectedTablesCache.set(dbname, token, affectedTables); + + callback(null, affectedTables); + }); + }); + }); + } + + getAffectedTables (callback) { + this.getMapConfig((err, mapConfig) => { + if (err) { + return callback(err); + } + + const { dbname } = this.params; + const token = mapConfig.id(); + + if (this.affectedTablesCache.hasAffectedTables(dbname, token)) { + const affectedTables = this.affectedTablesCache.get(dbname, token); + return callback(null, affectedTables); + } + + return this.createAffectedTables(callback); + }); + } +}; diff --git a/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js b/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js index bc36d3ae..6d33c912 100644 --- a/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js +++ b/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js @@ -1,128 +1,27 @@ -var assert = require('assert'); -var step = require('step'); +const MapStoreMapConfigProvider = require('./map-store-provider'); -var MapStoreMapConfigProvider = require('./map-store-provider'); -const QueryTables = require('cartodb-query-tables'); - -/** - * @param {MapConfig} mapConfig - * @param {String} user - * @param {UserLimitsBackend} userLimitsBackend - * @param {Object} params - * @constructor - * @type {CreateLayergroupMapConfigProvider} - */ - -function CreateLayergroupMapConfigProvider( - mapConfig, - user, - userLimitsBackend, - pgConnection, - affectedTablesCache, - params -) { - this.mapConfig = mapConfig; - this.user = user; - this.userLimitsBackend = userLimitsBackend; - this.pgConnection = pgConnection; - this.affectedTablesCache = affectedTablesCache; - this.params = params; - this.cacheBuster = params.cache_buster || 0; -} - -module.exports = CreateLayergroupMapConfigProvider; - -CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) { - var self = this; - - if (this.mapConfig && this.params && this.context) { - return callback(null, this.mapConfig, this.params, this.context); +module.exports = class CreateLayergroupMapConfigProvider extends MapStoreMapConfigProvider { + constructor (mapConfig, user, userLimitsBackend, pgConnection, affectedTablesCache, params) { + super(null, user, userLimitsBackend, pgConnection, affectedTablesCache, params); + this.mapConfig = mapConfig; } - var context = {}; - - step( - function prepareContextLimits() { - self.userLimitsBackend.getRenderLimits(self.user, self.params.api_key, this); - }, - function handleRenderLimits(err, renderLimits) { - assert.ifError(err); - context.limits = renderLimits; - self.context = context; - return null; - }, - function finish(err) { - return callback(err, self.mapConfig, self.params, context); - } - ); -}; - -CreateLayergroupMapConfigProvider.prototype.getKey = MapStoreMapConfigProvider.prototype.getKey; - -CreateLayergroupMapConfigProvider.prototype.getCacheBuster = MapStoreMapConfigProvider.prototype.getCacheBuster; - -CreateLayergroupMapConfigProvider.prototype.filter = MapStoreMapConfigProvider.prototype.filter; - -CreateLayergroupMapConfigProvider.prototype.createKey = MapStoreMapConfigProvider.prototype.createKey; - -CreateLayergroupMapConfigProvider.prototype.createAffectedTables = function (callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); + getMapConfig (callback) { + if (this.mapConfig && this.params && this.context) { + return callback(null, this.mapConfig, this.params, this.context); } - const { dbname } = this.params; - const token = mapConfig.id(); + const context = {}; - const queries = []; - - this.mapConfig.getLayers().forEach(layer => { - queries.push(layer.options.sql); - if (layer.options.affected_tables) { - layer.options.affected_tables.map(table => { - queries.push(`SELECT * FROM ${table} LIMIT 0`); - }); - } - }); - - const sql = queries.length ? queries.join(';') : null; - - if (!sql) { - return callback(); - } - - this.pgConnection.getConnection(this.user, (err, connection) => { + this.userLimitsBackend.getRenderLimits(this.user, this.params.api_key, (err, renderLimits) => { if (err) { return callback(err); } - QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => { - if (err) { - return callback(err); - } + context.limits = renderLimits; + this.context = context; - this.affectedTablesCache.set(dbname, token, affectedTables); - - callback(null, affectedTables); - }); + return callback(null, this.mapConfig, this.params, context); }); - }); -}; - -CreateLayergroupMapConfigProvider.prototype.getAffectedTables = function (callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); - } - - const { dbname } = this.params; - const token = mapConfig.id(); - - if (this.affectedTablesCache.hasAffectedTables(dbname, token)) { - const affectedTables = this.affectedTablesCache.get(dbname, token); - return callback(null, affectedTables); - } - - return this.createAffectedTables(callback); - }); + } }; diff --git a/lib/cartodb/models/mapconfig/provider/map-store-provider.js b/lib/cartodb/models/mapconfig/provider/map-store-provider.js index 1fd9dadf..abc9eca2 100644 --- a/lib/cartodb/models/mapconfig/provider/map-store-provider.js +++ b/lib/cartodb/models/mapconfig/provider/map-store-provider.js @@ -1,152 +1,86 @@ -var _ = require('underscore'); -var assert = require('assert'); -var dot = require('dot'); -var step = require('step'); -const QueryTables = require('cartodb-query-tables'); - -/** - * @param {MapStore} mapStore - * @param {String} user - * @param {UserLimitsBackend} userLimitsBackend - * @param {Object} params - * @constructor - * @type {MapStoreMapConfigProvider} - */ -function MapStoreMapConfigProvider(mapStore, user, userLimitsBackend, pgConnection, affectedTablesCache, params) { - this.mapStore = mapStore; - this.user = user; - this.userLimitsBackend = userLimitsBackend; - this.pgConnection = pgConnection; - this.affectedTablesCache = affectedTablesCache; - this.token = params.token; - this.cacheBuster = params.cache_buster || 0; - this.mapConfig = null; - this.params = params; - this.context = null; -} - -module.exports = MapStoreMapConfigProvider; - -MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) { - var self = this; - - if (this.mapConfig !== null) { - return callback(null, this.mapConfig, this.params, this.context); - } - - var context = {}; - - step( - function prepareContextLimits() { - self.userLimitsBackend.getRenderLimits(self.user, self.params.api_key, this); - }, - function handleRenderLimits(err, renderLimits) { - assert.ifError(err); - context.limits = renderLimits; - return null; - }, - function loadMapConfig(err) { - assert.ifError(err); - self.mapStore.load(self.token, this); - }, - function finish(err, mapConfig) { - self.mapConfig = mapConfig; - self.context = context; - return callback(err, mapConfig, self.params, context); - } - ); -}; - -MapStoreMapConfigProvider.prototype.getKey = function() { - return this.createKey(false); -}; - -MapStoreMapConfigProvider.prototype.getCacheBuster = function() { - return this.cacheBuster; -}; - -MapStoreMapConfigProvider.prototype.filter = function(key) { - var regex = new RegExp('^' + this.createKey(true) + '.*'); - return key && key.match(regex); -}; +const BaseMapConfigProvider = require('./base-mapconfig-adapter'); +const dot = require('dot'); // Configure bases for cache keys suitable for string interpolation -var baseKey = '{{=it.dbname}}:{{=it.token}}'; -var rendererKey = baseKey + ':{{=it.dbuser}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}'; +const baseKey = '{{=it.dbname}}:{{=it.token}}'; +const rendererKey = baseKey + ':{{=it.dbuser}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}'; -var baseKeyTpl = dot.template(baseKey); -var rendererKeyTpl = dot.template(rendererKey); +const baseKeyTpl = dot.template(baseKey); +const rendererKeyTpl = dot.template(rendererKey); -MapStoreMapConfigProvider.prototype.createKey = function(base) { - var tplValues = _.defaults({}, this.params, { - dbname: '', - token: '', - dbuser: '', - format: '', - layer: '', - scale_factor: 1 - }); - return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues); -}; +module.exports = class MapStoreMapConfigProvider extends BaseMapConfigProvider { + /** + * @param {MapStore} mapStore + * @param {String} user + * @param {UserLimitsBackend} userLimitsBackend + * @param {Object} params + * @constructor + * @type {MapStoreMapConfigProvider} + */ + constructor (mapStore, user, userLimitsBackend, pgConnection, affectedTablesCache, params) { + super(); + this.mapStore = mapStore; + this.user = user; + this.userLimitsBackend = userLimitsBackend; + this.pgConnection = pgConnection; + this.affectedTablesCache = affectedTablesCache; + this.params = params; + this.token = params.token; + this.cacheBuster = params.cache_buster || 0; + this.mapConfig = null; + this.context = null; + } -MapStoreMapConfigProvider.prototype.createAffectedTables = function(callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); + getMapConfig (callback) { + if (this.mapConfig !== null) { + return callback(null, this.mapConfig, this.params, this.context); } - const { dbname } = this.params; - const token = mapConfig.id(); + const context = {}; - const queries = []; - - mapConfig.getLayers().forEach(layer => { - queries.push(layer.options.sql); - if (layer.options.affected_tables) { - layer.options.affected_tables.map(table => { - queries.push(`SELECT * FROM ${table} LIMIT 0`); - }); - } - }); - - const sql = queries.length ? queries.join(';') : null; - - if (!sql) { - return callback(); - } - - this.pgConnection.getConnection(this.user, (err, connection) => { + this.userLimitsBackend.getRenderLimits(this.user, this.params.api_key, (err, renderLimits) => { if (err) { return callback(err); } - QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => { + context.limits = renderLimits; + + this.mapStore.load(this.token, (err, mapConfig) => { if (err) { return callback(err); } - this.affectedTablesCache.set(dbname, token, affectedTables); + this.mapConfig = mapConfig; + this.context = context; - callback(err, affectedTables); + return callback(null, mapConfig, this.params, context); }); }); - }); -}; + } -MapStoreMapConfigProvider.prototype.getAffectedTables = function (callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); - } + getKey () { + return this.createKey(false); + } - const { dbname } = this.params; - const token = mapConfig.id(); + getCacheBuster () { + return this.cacheBuster; + } - if (this.affectedTablesCache.hasAffectedTables(dbname, token)) { - const affectedTables = this.affectedTablesCache.get(dbname, token); - return callback(null, affectedTables); - } + filter (key) { + const regex = new RegExp('^' + this.createKey(true) + '.*'); + return key && key.match(regex); + } - return this.createAffectedTables(callback); - }); + createKey (base) { + const tplValues = Object.assign({ + dbname: '', + token: '', + dbuser: '', + format: '', + layer: '', + scale_factor: 1 + }, this.params); + + return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues); + } }; diff --git a/lib/cartodb/models/mapconfig/provider/named-map-provider.js b/lib/cartodb/models/mapconfig/provider/named-map-provider.js index 2d9a88c2..e3889aff 100644 --- a/lib/cartodb/models/mapconfig/provider/named-map-provider.js +++ b/lib/cartodb/models/mapconfig/provider/named-map-provider.js @@ -1,325 +1,279 @@ -var _ = require('underscore'); -var assert = require('assert'); -var crypto = require('crypto'); -var dot = require('dot'); -var step = require('step'); -var MapConfig = require('windshaft').model.MapConfig; -var templateName = require('../../../backends/template_maps').templateName; -var QueryTables = require('cartodb-query-tables'); - -/** - * @constructor - * @type {NamedMapMapConfigProvider} - */ -function NamedMapMapConfigProvider( - templateMaps, - pgConnection, - metadataBackend, - userLimitsBackend, - mapConfigAdapter, - affectedTablesCache, - owner, - templateId, - config, - authToken, - params -) { - this.templateMaps = templateMaps; - this.pgConnection = pgConnection; - this.metadataBackend = metadataBackend; - this.userLimitsBackend = userLimitsBackend; - this.mapConfigAdapter = mapConfigAdapter; - - this.owner = owner; - this.templateName = templateName(templateId); - this.config = config; - this.authToken = authToken; - this.params = params; - - this.cacheBuster = Date.now(); - - // use template after call to mapConfig - this.template = null; - - this.affectedTablesCache = affectedTablesCache; - - // providing - this.err = null; - this.mapConfig = null; - this.rendererParams = null; - this.context = {}; - this.analysesResults = []; -} - -module.exports = NamedMapMapConfigProvider; - -NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) { - if (!!this.err || this.mapConfig !== null) { - return callback(this.err, this.mapConfig, this.rendererParams, this.context); - } - - var self = this; - - var mapConfig = null; - var rendererParams; - var apiKey; - - var context = {}; - - step( - function getTemplate() { - self.getTemplate(this); - }, - function prepareDbParams(err, tpl) { - assert.ifError(err); - self.template = tpl; - - rendererParams = _.extend({}, self.params, { - user: self.owner - }); - self.setDBParams(self.owner, rendererParams, this); - }, - function getUserApiKey(err) { - assert.ifError(err); - self.metadataBackend.getUserMapKey(self.owner, this); - }, - function prepareParams(err, _apiKey) { - assert.ifError(err); - - apiKey = _apiKey; - - var templateParams = {}; - if (self.config) { - try { - templateParams = _.isString(self.config) ? JSON.parse(self.config) : self.config; - } catch (e) { - throw new Error('malformed config parameter, should be a valid JSON'); - } - } - - return templateParams; - }, - function instantiateTemplate(err, templateParams) { - assert.ifError(err); - context.templateParams = templateParams; - return self.templateMaps.instance(self.template, templateParams); - }, - function prepareAdapterMapConfig(err, requestMapConfig) { - assert.ifError(err); - context.analysisConfiguration = { - user: self.owner, - db: { - host: rendererParams.dbhost, - port: rendererParams.dbport, - dbname: rendererParams.dbname, - user: rendererParams.dbuser, - pass: rendererParams.dbpassword - }, - batch: { - username: self.owner, - apiKey: apiKey - } - }; - self.mapConfigAdapter.getMapConfig(self.owner, requestMapConfig, rendererParams, context, this); - }, - function prepareContextLimits(err, _mapConfig) { - assert.ifError(err); - mapConfig = _mapConfig; - self.userLimitsBackend.getRenderLimits(self.owner, self.params.api_key, this); - }, - function cacheAndReturnMapConfig(err, renderLimits) { - self.err = err; - self.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource); - self.analysesResults = context.analysesResults || []; - self.rendererParams = rendererParams; - self.context = context; - self.context.limits = renderLimits || {}; - return callback(self.err, self.mapConfig, self.rendererParams, self.context); - } - ); -}; - -NamedMapMapConfigProvider.prototype.getTemplate = function(callback) { - var self = this; - - if (!!this.err || this.template !== null) { - return callback(this.err, this.template); - } - - step( - function getTemplate() { - self.templateMaps.getTemplate(self.owner, self.templateName, this); - }, - function checkExists(err, tpl) { - assert.ifError(err); - if (!tpl) { - var notFoundErr = new Error( - "Template '" + self.templateName + "' of user '" + self.owner + "' not found" - ); - notFoundErr.http_status = 404; - throw notFoundErr; - } - return tpl; - }, - function checkAuthorized(err, tpl) { - assert.ifError(err); - - var authorized = false; - try { - authorized = self.templateMaps.isAuthorized(tpl, self.authToken); - } catch (err) { - // we catch to add http_status - var authorizationFailedErr = new Error('Failed to authorize template'); - authorizationFailedErr.http_status = 403; - throw authorizationFailedErr; - } - if ( ! authorized ) { - var unauthorizedErr = new Error('Unauthorized template instantiation'); - unauthorizedErr.http_status = 403; - throw unauthorizedErr; - } - - return tpl; - }, - function cacheAndReturnTemplate(err, template) { - self.err = err; - self.template = template; - return callback(self.err, self.template); - } - ); -}; - -NamedMapMapConfigProvider.prototype.getKey = function() { - return this.createKey(false); -}; - -NamedMapMapConfigProvider.prototype.getCacheBuster = function() { - return this.cacheBuster; -}; - -NamedMapMapConfigProvider.prototype.reset = function() { - this.template = null; - - this.affectedTables = null; - - this.err = null; - this.mapConfig = null; - - this.cacheBuster = Date.now(); -}; - -NamedMapMapConfigProvider.prototype.filter = function(key) { - var regex = new RegExp('^' + this.createKey(true) + '.*'); - return key && key.match(regex); -}; +const BaseMapConfigProvider = require('./base-mapconfig-adapter'); +const crypto = require('crypto'); +const dot = require('dot'); +const MapConfig = require('windshaft').model.MapConfig; +const templateName = require('../../../backends/template_maps').templateName; // Configure bases for cache keys suitable for string interpolation -var baseKey = '{{=it.dbname}}:{{=it.owner}}:{{=it.templateName}}'; -var rendererKey = baseKey + ':{{=it.authToken}}:{{=it.configHash}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}'; +const baseKey = '{{=it.dbname}}:{{=it.user}}:{{=it.templateName}}'; +const rendererKey = baseKey + ':{{=it.authToken}}:{{=it.configHash}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}'; -var baseKeyTpl = dot.template(baseKey); -var rendererKeyTpl = dot.template(rendererKey); +const baseKeyTpl = dot.template(baseKey); +const rendererKeyTpl = dot.template(rendererKey); -NamedMapMapConfigProvider.prototype.createKey = function(base) { - var tplValues = _.defaults({}, this.params, { - dbname: '', - owner: this.owner, - templateName: this.templateName, - authToken: this.authToken || '', - configHash: configHash(this.config), - layer: '', - scale_factor: 1 - }); - return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues); +module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider { + constructor ( + templateMaps, + pgConnection, + metadataBackend, + userLimitsBackend, + mapConfigAdapter, + affectedTablesCache, + user, + templateId, + config, + authToken, + params + ) { + super(); + this.templateMaps = templateMaps; + this.pgConnection = pgConnection; + this.metadataBackend = metadataBackend; + this.userLimitsBackend = userLimitsBackend; + this.mapConfigAdapter = mapConfigAdapter; + + this.user = user; + this.templateName = templateName(templateId); + this.config = config; + this.authToken = authToken; + this.params = params; + + this.cacheBuster = Date.now(); + + // use template after call to mapConfig + this.template = null; + + this.affectedTablesCache = affectedTablesCache; + + // providing + this.err = null; + this.mapConfig = null; + this.rendererParams = null; + this.context = {}; + this.analysesResults = []; + } + + getMapConfig (callback) { + if (!!this.err || this.mapConfig !== null) { + return callback(this.err, this.mapConfig, this.rendererParams, this.context); + } + + this.getContext((err, context) => { + if (err) { + this.err = err; + return callback(err); + } + + let templateParams = {}; + + if (this.config) { + try { + templateParams = Object.prototype.toString.call(this.config) === '[object String]' ? + JSON.parse(this.config) : + this.config; + } catch (e) { + const error = new Error('malformed config parameter, should be a valid JSON'); + this.err = error; + + return callback(err); + } + } + + context.templateParams = templateParams; + + this.getTemplate((err, template) => { + if (err) { + this.err = err; + return callback(err); + } + + let requestMapConfig; + + try { + requestMapConfig = this.templateMaps.instance(template, templateParams); + } catch (err) { + this.err = err; + return callback(err); + } + + const { user, rendererParams } = this; + + this.mapConfigAdapter.getMapConfig( + user, requestMapConfig, rendererParams, context, (err, mapConfig) => { + if (err) { + this.err = err; + return callback(err); + } + + this.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource); + this.analysesResults = context.analysesResults || []; + + return callback(null, this.mapConfig, this.rendererParams, this.context); + }); + }); + }); + } + + getContext (callback) { + this.getDBParams(this.user, (err, rendererParams) => { + if (err) { + return callback(err); + } + + this.rendererParams = rendererParams; + + this.metadataBackend.getUserMapKey(this.user, (err, apiKey) => { + if (err) { + return callback(err); + } + + const context = {}; + + context.analysisConfiguration = { + user: this.user, + db: { + host: rendererParams.dbhost, + port: rendererParams.dbport, + dbname: rendererParams.dbname, + user: rendererParams.dbuser, + pass: rendererParams.dbpassword + }, + batch: { + username: this.user, + apiKey: apiKey + } + }; + + this.userLimitsBackend.getRenderLimits(this.user, this.params.api_key, (err, renderLimits) => { + if (err) { + this.err = err; + return callback(err); + } + + context.limits = renderLimits || {}; + + this.context = context; + + return callback(null, context); + }); + }); + }); + } + + getTemplate (callback) { + if (!!this.err || this.template !== null) { + return callback(this.err, this.template); + } + + this.templateMaps.getTemplate(this.user, this.templateName, (err, tpl) => { + if (err) { + this.err = err; + return callback(err); + } + + if (!tpl) { + const error = new Error(`Template '${this.templateName}' of user '${this.user}' not found`); + error.http_status = 404; + + this.err = error; + + return callback(error); + } + + let authorized = false; + + try { + authorized = this.templateMaps.isAuthorized(tpl, this.authToken); + } catch (err) { + const error = new Error('Failed to authorize template'); + error.http_status = 403; + + this.err = error; + + return callback(error); + } + + if (!authorized) { + const error = new Error('Unauthorized template instantiation'); + error.http_status = 403; + this.err = error; + + return callback(error); + } + + this.template = tpl; + + return callback(null, this.template); + }); + } + + getKey () { + return this.createKey(false); + } + + getCacheBuster () { + return this.cacheBuster; + } + + reset () { + this.template = null; + + this.affectedTables = null; + + this.err = null; + this.mapConfig = null; + + this.cacheBuster = Date.now(); + } + + filter (key) { + const regex = new RegExp('^' + this.createKey(true) + '.*'); + return key && key.match(regex); + } + + createKey (base) { + const tplValues = Object.assign({ + dbname: '', + user: this.user, + templateName: this.templateName, + authToken: this.authToken || '', + configHash: configHash(this.config), + layer: '', + scale_factor: 1 + }, this.params); + + return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues); + } + + getDBParams (cdbuser, callback) { + const dbParams = Object.assign({ user: this.user }, this.params); + + this.pgConnection.getDatabaseParams(cdbuser, (err, databaseParams) => { + if (err) { + return callback(err); + } + + dbParams.dbuser = databaseParams.dbuser; + dbParams.dbpass = databaseParams.dbpass; + dbParams.dbhost = databaseParams.dbhost; + dbParams.dbport = databaseParams.dbport; + dbParams.dbname = databaseParams.dbname; + + return callback(null, dbParams); + }); + } + + getTemplateName () { + return this.templateName; + } }; function configHash(config) { if (!config) { return ''; } + return crypto.createHash('md5').update(JSON.stringify(config)).digest('hex').substring(0,8); } module.exports.configHash = configHash; - -NamedMapMapConfigProvider.prototype.setDBParams = function(cdbuser, params, callback) { - this.pgConnection.getDatabaseParams(cdbuser, (err, databaseParams) => { - if (err) { - return callback(err); - } - - params.dbuser = databaseParams.dbuser; - params.dbpass = databaseParams.dbpass; - params.dbhost = databaseParams.dbhost; - params.dbport = databaseParams.dbport; - params.dbname = databaseParams.dbname; - - callback(); - }); -}; - -NamedMapMapConfigProvider.prototype.getTemplateName = function() { - return this.templateName; -}; - -NamedMapMapConfigProvider.prototype.createAffectedTables = function(callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); - } - - const { dbname } = this.rendererParams; - const token = mapConfig.id(); - - const queries = []; - - mapConfig.getLayers().forEach(layer => { - queries.push(layer.options.sql); - if (layer.options.affected_tables) { - layer.options.affected_tables.map(table => { - queries.push(`SELECT * FROM ${table} LIMIT 0`); - }); - } - }); - - const sql = queries.length ? queries.join(';') : null; - - if (!sql) { - return callback(); - } - - this.pgConnection.getConnection(this.owner, (err, connection) => { - if (err) { - return callback(err); - } - - QueryTables.getAffectedTablesFromQuery(connection, sql, (err, affectedTables) => { - if (err) { - return callback(err); - } - - this.affectedTablesCache.set(dbname, token, affectedTables); - - callback(err, affectedTables); - }); - }); - }); -}; - -NamedMapMapConfigProvider.prototype.getAffectedTables = function (callback) { - this.getMapConfig((err, mapConfig) => { - if (err) { - return callback(err); - } - - const { dbname } = this.params; - const token = mapConfig.id(); - - if (this.affectedTablesCache.hasAffectedTables(dbname, token)) { - const affectedTables = this.affectedTablesCache.get(dbname, token); - return callback(null, affectedTables); - } - - return this.createAffectedTables(callback); - }); -};