Merge pull request #1136 from CartoDB/eslint

Eslint
This commit is contained in:
Daniel G. Aubert 2019-11-14 16:16:47 +01:00 committed by GitHub
commit 69afee61e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
257 changed files with 15196 additions and 13756 deletions

22
.eslintrc.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
env: {
commonjs: true,
es6: true,
node: true,
mocha: true
},
extends: [
'standard'
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018
},
rules: {
"indent": ["error", 4],
"semi": ["error", "always"]
}
}

View File

@ -1,95 +0,0 @@
{
// // JSHint Default Configuration File (as on JSHint website)
// // See http://jshint.com/docs/ for more details
//
// "maxerr" : 50, // {int} Maximum error before stopping
//
// // Enforcing
// "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
// "camelcase" : false, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
"immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
// "indent" : 4, // {int} Number of spaces to use for indentation
// "latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
// "noempty" : true, // true: Prohibit use of empty blocks
"nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
"nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
// "plusplus" : false, // true: Prohibit use of `++` & `--`
// "quotmark" : false, // Quotation mark consistency:
// // false : do nothing (default)
// // true : ensure whatever is used is consistent
// // "single" : require single quotes
// // "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
// "strict" : true, // true: Requires all functions run in ES5 Strict Mode
// "maxparams" : false, // {int} Max number of formal params allowed per function
// "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
// "maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : 6, // {int} Max cyclomatic complexity per function
"maxlen" : 120, // {int} Max number of characters per line
//
// // Relaxing
// "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
// "boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
// "eqnull" : false, // true: Tolerate use of `== null`
// "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
"esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`)
// "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// // (ex: `for each`, multiple try/catch, function expression…)
// "evil" : false, // true: Tolerate use of `eval` and `new Function()`
// "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
// "funcscope" : false, // true: Tolerate defining variables inside control statements
// "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
// "iterator" : false, // true: Tolerate using the `__iterator__` property
// "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
// "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
// "laxcomma" : false, // true: Tolerate comma-first style coding
// "loopfunc" : false, // true: Tolerate functions being defined in loops
// "multistr" : false, // true: Tolerate multi-line strings
// "noyield" : false, // true: Tolerate generator functions with no yield statement in them.
// "notypeof" : false, // true: Tolerate invalid typeof operator values
// "proto" : false, // true: Tolerate using the `__proto__` property
// "scripturl" : false, // true: Tolerate script-targeted URLs
// "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
// "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
// "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
// "validthis" : false, // true: Tolerate using this in a non-constructor function
//
// // Environments
// "browser" : true, // Web Browser (window, document, etc)
// "browserify" : false, // Browserify (node.js code in the browser)
// "couch" : false, // CouchDB
// "devel" : true, // Development/debugging (alert, confirm, etc)
// "dojo" : false, // Dojo Toolkit
// "jasmine" : false, // Jasmine
// "jquery" : false, // jQuery
// "mocha" : true, // Mocha
// "mootools" : false, // MooTools
"node" : true, // Node.js
// "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
// "prototypejs" : false, // Prototype and Scriptaculous
// "qunit" : false, // QUnit
// "rhino" : false, // Rhino
// "shelljs" : false, // ShellJS
// "worker" : false, // Web Workers
// "wsh" : false, // Windows Scripting Host
// "yui" : false, // Yahoo User Interface
// Custom predefined global variables
"predef": [
"-console", // disallows console, use debug
"beforeEach",
"afterEach",
"before",
"after",
"describe",
"it"
]
}

View File

@ -39,15 +39,15 @@ test-acceptance: config/environments/test.js
@echo "***tests***"
@$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE_ACCEPTANCE)
jshint:
@echo "***jshint***"
@./node_modules/.bin/jshint lib/ test/ app.js
lint:
@echo "***eslint***"
@./node_modules/.bin/eslint app.js "lib/**/*.js" "test/**/*.js"
test-all: test jshint
test-all: test lint
coverage:
@RUNTESTFLAGS=--with-coverage make test
check: test
.PHONY: pre-install test jshint coverage
.PHONY: pre-install test lint coverage

View File

@ -3,6 +3,9 @@
## 8.0.1
Released 2019-mm-dd
Announcements:
- Removed `jshint` as linter in favour of `eslint` to check syntax, find problems, and enforce code style.
## 8.0.0
Released 2019-11-13

21
app.js
View File

@ -76,7 +76,6 @@ var agentOptions = _.defaults(global.environment.httpAgent || {}, {
http.globalAgent = new http.Agent(agentOptions);
https.globalAgent = new https.Agent(agentOptions);
global.log4js = require('log4js');
var log4jsConfig = {
appenders: [],
@ -87,16 +86,16 @@ if ( global.environment.log_filename ) {
var logFilename = path.resolve(global.environment.log_filename);
var logDirectory = path.dirname(logFilename);
if (!fs.existsSync(logDirectory)) {
logError("Log filename directory does not exist: " + logDirectory);
logError('Log filename directory does not exist: ' + logDirectory);
process.exit(1);
}
log("Logs will be written to " + logFilename);
log('Logs will be written to ' + logFilename);
log4jsConfig.appenders.push(
{ type: "file", absolute: true, filename: logFilename }
{ type: 'file', absolute: true, filename: logFilename }
);
} else {
log4jsConfig.appenders.push(
{ type: "console", layout: { type:'basic' } }
{ type: 'console', layout: { type: 'basic' } }
);
}
@ -118,13 +117,13 @@ var backlog = global.environment.maxConnections || 128;
var listener = server.listen(serverOptions.bind.port, serverOptions.bind.host, backlog);
var version = require("./package").version;
var version = require('./package').version;
listener.on('listening', function () {
log("Using Node.js %s", process.version);
log('Using Node.js %s', process.version);
log('Using configuration file "%s"', configurationFile);
log(
"Windshaft tileserver %s started on %s:%s PID=%d (%s)",
'Windshaft tileserver %s started on %s:%s PID=%d (%s)',
version, serverOptions.bind.host, serverOptions.bind.port, process.pid, ENVIRONMENT
);
});
@ -179,9 +178,9 @@ process.on('SIGHUP', function() {
});
if (global.gc) {
var gcInterval = Number.isFinite(global.environment.gc_interval) ?
global.environment.gc_interval :
10000;
var gcInterval = Number.isFinite(global.environment.gc_interval)
? global.environment.gc_interval
: 10000;
if (gcInterval > 0) {
setInterval(function gcForcedCycle () {

View File

@ -1,5 +1,7 @@
'use strict';
const path = require('path');
const { Router: router } = require('express');
const RedisPool = require('redis-mpool');
@ -83,10 +85,9 @@ module.exports = class ApiRouter {
const metadataBackend = cartodbRedis({ pool: redisPool });
const pgConnection = new PgConnection(metadataBackend);
const windshaftLogger = environmentOptions.log_windshaft && global.log4js ?
global.log4js.getLogger('[windshaft]') :
null;
const windshaftLogger = environmentOptions.log_windshaft && global.log4js
? global.log4js.getLogger('[windshaft]')
: null;
const mapStore = new windshaft.storage.MapStore({
pool: redisPool,
expire_time: serverOptions.grainstore.default_layergroup_ttl,
@ -237,7 +238,6 @@ module.exports = class ApiRouter {
}
};
function createTemplateMaps ({ redisPool, surrogateKeysCache }) {
const templateMaps = new TemplateMaps(redisPool, {
max_user_templates: global.environment.maxUserTemplates
@ -250,7 +250,7 @@ function createTemplateMaps ({ redisPool, surrogateKeysCache }) {
username: owner,
type: 'named_map_invalidation',
elapsed: Date.now() - startTime,
error: !!err ? JSON.stringify(err.message) : undefined
error: err ? JSON.stringify(err.message) : undefined
});
if (err) {
global.logger.warn(logMessage);
@ -260,7 +260,6 @@ function createTemplateMaps ({ redisPool, surrogateKeysCache }) {
});
}
['update', 'delete'].forEach(function (eventType) {
templateMaps.on(eventType, invalidateNamedMap);
});
@ -287,14 +286,13 @@ function createSurrogateKeysCacheBackends(serverOptions) {
return cacheBackends;
}
const timeoutErrorTilePath = __dirname + '/../../assets/render-timeout-fallback.png';
const timeoutErrorTilePath = path.join(__dirname, '/../../assets/render-timeout-fallback.png');
const timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, { encoding: null });
function createRendererFactory ({ redisPool, serverOptions, environmentOptions }) {
var onTileErrorStrategy;
if (environmentOptions.enabledFeatures.onTileErrorStrategy !== false) {
onTileErrorStrategy = function onTileErrorStrategy$TimeoutTile (err, tile, headers, stats, format, callback) {
function isRenderTimeoutError (err) {
return err.message === 'Render timed out';
}
@ -313,7 +311,7 @@ function createRendererFactory ({ redisPool, serverOptions, environmentOptions }
if (isTimeoutError(err) && isRasterFormat(format)) {
return callback(null, timeoutErrorTile, {
'Content-Type': 'image/png',
'Content-Type': 'image/png'
}, {});
} else {
return callback(err, tile, headers, stats);

View File

@ -82,7 +82,7 @@ function prepareResponse () {
}, {});
const analysisCatalog = catalog.map(analysis => {
if (analysisIdToTable.hasOwnProperty(analysis.node_id)) {
if (Object.prototype.hasOwnProperty.call(analysisIdToTable, analysis.node_id)) {
analysis.table = analysisIdToTable[analysis.node_id];
}
@ -93,11 +93,11 @@ function prepareResponse () {
return analysisB.table.size - analysisA.table.size;
}
if (!!analysisA.table) {
if (analysisA.table) {
return -1;
}
if (!!analysisB.table) {
if (analysisB.table) {
return 1;
}

View File

@ -133,7 +133,7 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
return function prepareAdapterMapConfigMiddleware (req, res, next) {
const requestMapConfig = req.body;
const { user, api_key } = res.locals;
const { user, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const params = Object.assign({ dbuser, dbname, dbpassword, dbhost, dbport }, req.query);
@ -149,7 +149,7 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
},
batch: {
username: user,
apiKey: api_key
apiKey
}
}
};
@ -164,7 +164,6 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
stats.mapType = 'anonymous';
req.profiler.add(stats);
if (err) {
return next(err);
}
@ -182,12 +181,17 @@ function createLayergroup (mapBackend, userLimitsBackend, pgConnection, affected
const requestMapConfig = req.body;
const { context } = res.locals;
const { user, cache_buster, api_key } = res.locals;
const { user, cache_buster: cacheBuster, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const params = {
cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport
cache_buster: cacheBuster,
api_key: apiKey,
dbuser,
dbname,
dbpassword,
dbhost,
dbport
};
const datasource = context.datasource || Datasource.EmptyDatasource();

View File

@ -70,8 +70,13 @@ function getFeatureAttributes (attributesBackend) {
const params = {
token,
dbuser, dbname, dbpassword, dbhost, dbport,
layer, fid
dbuser,
dbname,
dbpassword,
dbhost,
dbport,
layer,
fid
};
attributesBackend.getFeatureAttributes(mapConfigProvider, params, false, (err, tile, stats = {}) => {

View File

@ -71,9 +71,16 @@ function getClusteredFeatures (clusterBackend) {
const { aggregation } = req.query;
const params = {
user, token,
dbuser, dbname, dbpassword, dbhost, dbport,
layer, zoom, clusterId,
user,
token,
dbuser,
dbname,
dbpassword,
dbhost,
dbport,
layer,
zoom,
clusterId,
aggregation
};

View File

@ -25,7 +25,7 @@ const ALLOWED_DATAVIEW_QUERY_PARAMS = [
'aggregation', // string
'offset', // number
'q', // widgets search
'categories', // number
'categories' // number
];
module.exports = class DataviewLayergroupController {

View File

@ -60,7 +60,8 @@ module.exports = class PreviewTemplateController {
checkStaticImageFormat(),
namedMapProvider({
namedMapProviderCache: this.namedMapProviderCache,
label: 'STATIC_VIZ_MAP', forcedFormat: 'png'
label: 'STATIC_VIZ_MAP',
forcedFormat: 'png'
}),
getTemplate({ label: 'STATIC_VIZ_MAP' }),
prepareLayerFilterFromPreviewLayers({
@ -99,7 +100,7 @@ function getTemplate ({ label }) {
function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) {
return function prepareLayerFilterFromPreviewLayersMiddleware (req, res, next) {
const { template } = res.locals;
const { config, auth_token } = req.query;
const { config, auth_token: authToken } = req.query;
if (!template || !template.view || !template.view.preview_layers) {
return next();
@ -118,21 +119,29 @@ function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label })
return next();
}
const { user, token, cache_buster, api_key } = res.locals;
const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id, format } = req.params;
const { template_id: templateId, format } = req.params;
const params = {
user, token, cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport,
template_id, format
user,
token,
cache_buster: cacheBuster,
api_key: apiKey,
dbuser,
dbname,
dbpassword,
dbhost,
dbport,
template_id: templateId,
format
};
// overwrites 'all' default filter
params.layer = layerVisibilityFilter.join(',');
// recreates the provider
namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, provider) => {
namedMapProviderCache.get(user, templateId, config, authToken, params, (err, provider) => {
if (err) {
err.label = label;
return next(err);

View File

@ -45,14 +45,14 @@ module.exports = class TileLayergroupController {
route (mapRouter) {
// REGEXP: doesn't match with `val`
const not = (val) => `(?!${val})([^\/]+?)`;
const not = (val) => `(?!${val})([^\/]+?)`; // eslint-disable-line no-useless-escape
// Sadly the path that matches 1 also matches with 2 so we need to tell to express
// that performs only the middlewares of the first path that matches
// for that we use one array to group all paths.
mapRouter.get([
`/:token/:z/:x/:y@:scale_factor?x.:format`, // 1
`/:token/:z/:x/:y.:format`, // 2
'/:token/:z/:x/:y@:scale_factor?x.:format', // 1
'/:token/:z/:x/:y.:format', // 2
`/:token${not('static')}/:layer/:z/:x/:y.(:format)`
], this.middlewares());
}
@ -149,7 +149,6 @@ function incrementErrorMetrics (statsClient) {
function tileError () {
return function tileErrorMiddleware (err, req, res, next) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
let errMsg = err.message ? ('' + err.message) : ('' + err);

View File

@ -10,7 +10,7 @@ module.exports = function authorize (authBackend) {
}
if (!authorized) {
err = new Error("Sorry, you are unauthorized (permission denied)");
err = new Error('Sorry, you are unauthorized (permission denied)');
err.http_status = 403;
return next(err);
}

View File

@ -13,8 +13,8 @@ module.exports = function cors () {
headers.push('Content-Type');
}
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Headers", headers.join(', '));
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Headers', headers.join(', '));
next();
};

View File

@ -17,10 +17,10 @@ module.exports = function credentials () {
function getApikeyCredentialsFromRequest (req) {
let apikeyCredentials = {
token: null,
username: null,
username: null
};
for (let getter of apikeyGetters) {
for (const getter of apikeyGetters) {
apikeyCredentials = getter(req);
if (apikeyTokenFound(apikeyCredentials)) {
break;
@ -33,7 +33,7 @@ function getApikeyCredentialsFromRequest(req) {
const apikeyGetters = [
getApikeyTokenFromHeaderAuthorization,
getApikeyTokenFromRequestQueryString,
getApikeyTokenFromRequestBody,
getApikeyTokenFromRequestBody
];
function getApikeyTokenFromHeaderAuthorization (req) {
@ -47,7 +47,7 @@ function getApikeyTokenFromHeaderAuthorization(req) {
} else {
return {
username: null,
token: null,
token: null
};
}
}
@ -63,7 +63,7 @@ function getApikeyTokenFromRequestQueryString(req) {
return {
username: null,
token: token,
token: token
};
}
@ -78,7 +78,7 @@ function getApikeyTokenFromRequestBody(req) {
return {
username: null,
token: token,
token: token
};
}

View File

@ -10,7 +10,7 @@ module.exports = function dbConnSetup (pgConnection) {
req.profiler.done('dbConnSetup');
if (err) {
if (err.message && -1 !== err.message.indexOf('name not found')) {
if (err.message && err.message.indexOf('name not found') !== -1) {
err.http_status = 404;
}

View File

@ -55,7 +55,7 @@ function isTimeoutError (errorTypes) {
function getErrorTypes (error) {
return {
renderTimeoutError: isRenderTimeoutError(error),
datasourceTimeoutError: isDatasourceTimeoutError(error),
datasourceTimeoutError: isDatasourceTimeoutError(error)
};
}
@ -115,17 +115,14 @@ function statusFromErrorMessage(errMsg) {
// Find an appropriate statusCode based on message
// jshint maxcomplexity:7
var statusCode = 400;
if ( -1 !== errMsg.indexOf('permission denied') ) {
if (errMsg.indexOf('permission denied') !== -1) {
statusCode = 403;
}
else if ( -1 !== errMsg.indexOf('authentication failed') ) {
} else if (errMsg.indexOf('authentication failed') !== -1) {
statusCode = 403;
}
else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) {
} else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) {
statusCode = 400;
}
else if ( -1 !== errMsg.indexOf('does not exist') ) {
if ( -1 !== errMsg.indexOf(' role ') ) {
} else if (errMsg.indexOf('does not exist') !== -1) {
if (errMsg.indexOf(' role ') !== -1) {
statusCode = 403; // role 'xxx' does not exist
} else if (errMsg.match(/function .* does not exist/)) {
statusCode = 400; // invalid SQL (SQL function does not exist)
@ -134,7 +131,6 @@ function statusFromErrorMessage(errMsg) {
}
}
return statusCode;
}
@ -174,12 +170,12 @@ function errorMessageWithContext(err) {
var error = {
type: err.type || 'unknown',
message: stripConnectionInfo(message),
message: stripConnectionInfo(message)
};
for (var prop in err) {
// type & message are properties from Error's prototype and will be skipped
if (err.hasOwnProperty(prop) && shouldBeExposed(prop)) {
if (Object.prototype.hasOwnProperty.call(err, prop) && shouldBeExposed(prop)) {
error[prop] = err[prop];
}
}
@ -188,10 +184,10 @@ function errorMessageWithContext(err) {
}
function setErrorHeader (errors, statusCode, res) {
let errorsCopy = errors.slice(0);
const errorsCopy = errors.slice(0);
const mainError = errorsCopy.shift();
let errorsLog = {
const errorsLog = {
mainError: {
statusCode: statusCode || 200,
message: mainError.message,
@ -228,7 +224,7 @@ function stringifyForLogs(object) {
} else if (typeof object[key] === 'object') {
stringifyForLogs(object[key]);
} else if (object[key] instanceof Array) {
for (let element of object[key]) {
for (const element of object[key]) {
stringifyForLogs(element);
}
}

View File

@ -6,13 +6,13 @@ module.exports = function setLastModifiedHeader () {
return next();
}
const { mapConfigProvider, cache_buster } = res.locals;
const { mapConfigProvider, cache_buster: cacheBuster } = res.locals;
if (cache_buster) {
const cacheBuster = parseInt(cache_buster, 10);
const lastModifiedDate = Number.isFinite(cacheBuster) && cacheBuster !== 0 ?
new Date(cacheBuster) :
new Date();
if (cacheBuster) {
const cacheBusterTimestamp = parseInt(cacheBuster, 10);
const lastModifiedDate = Number.isFinite(cacheBusterTimestamp) && cacheBusterTimestamp !== 0
? new Date(cacheBusterTimestamp)
: new Date();
res.set('Last-Modified', lastModifiedDate.toUTCString());

View File

@ -6,12 +6,12 @@ module.exports = function lzma () {
const lzmaWorker = new LZMA();
return function lzmaMiddleware (req, res, next) {
if (!req.query.hasOwnProperty('lzma')) {
if (!Object.prototype.hasOwnProperty.call(req.query, 'lzma')) {
return next();
}
// Decode (from base64)
var lzma = new Buffer(req.query.lzma, 'base64')
var lzma = Buffer.from(req.query.lzma, 'base64')
.toString('binary')
.split('')
.map(function (c) {

View File

@ -10,15 +10,27 @@ module.exports = function createMapStoreMapConfigProvider (
forcedFormat = null
) {
return function createMapStoreMapConfigProviderMiddleware (req, res, next) {
const { user, token, cache_buster, api_key } = res.locals;
const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { layer: layerFromParams, z, x, y, scale_factor, format } = req.params;
const { layer: layerFromParams, z, x, y, scale_factor: scaleFactor, format } = req.params;
const { layer: layerFromQuery } = req.query;
const params = {
user, token, cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport,
layer: (layerFromQuery || layerFromParams), z, x, y, scale_factor, format
user,
token,
cache_buster: cacheBuster,
api_key: apiKey,
dbuser,
dbname,
dbpassword,
dbhost,
dbport,
layer: (layerFromQuery || layerFromParams),
z,
x,
y,
scale_factor: scaleFactor,
format
};
if (forcedFormat) {

View File

@ -2,15 +2,27 @@
module.exports = function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = null }) {
return function getNamedMapProviderMiddleware (req, res, next) {
const { user, token, cache_buster, api_key } = res.locals;
const { user, token, cache_buster: cacheBuster, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id, layer: layerFromParams, z, x, y, format } = req.params;
const { template_id: templateId, layer: layerFromParams, z, x, y, format } = req.params;
const { layer: layerFromQuery } = req.query;
const params = {
user, token, cache_buster, api_key,
dbuser, dbname, dbpassword, dbhost, dbport,
template_id, layer: (layerFromQuery || layerFromParams), z, x, y, format
user,
token,
cache_buster: cacheBuster,
api_key: apiKey,
dbuser,
dbname,
dbpassword,
dbhost,
dbport,
template_id: templateId,
layer: (layerFromQuery || layerFromParams),
z,
x,
y,
format
};
if (forcedFormat) {
@ -18,9 +30,9 @@ module.exports = function getNamedMapProvider ({ namedMapProviderCache, label, f
params.layer = params.layer || 'all';
}
const { config, auth_token } = req.query;
const { config, auth_token: authToken } = req.query;
namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => {
namedMapProviderCache.get(user, templateId, config, authToken, params, (err, namedMapProvider) => {
if (err) {
err.label = label;
return next(err);

View File

@ -46,7 +46,7 @@ function rateLimit(userLimitsBackend, endpointGroup = null) {
// retry is floor rounded in seconds by redis-cell
res.set('Retry-After', retry + 1);
let rateLimitError = new Error(
const rateLimitError = new Error(
'You are over platform\'s limits: too many requests.' +
' Please contact us to know more details'
);
@ -61,7 +61,6 @@ function rateLimit(userLimitsBackend, endpointGroup = null) {
};
}
function isRateLimitEnabled (endpointGroup) {
return global.environment.enabledFeatures.rateLimitsEnabled &&
endpointGroup &&

View File

@ -20,7 +20,7 @@ module.exports = function stats (options) {
// May throw due to dns, see: http://github.com/CartoDB/Windshaft/issues/166
req.profiler.sendStats();
} catch (err) {
debug("error sending profiling stats: " + err);
debug('error sending profiling stats: ' + err);
}
});

View File

@ -1,12 +1,12 @@
'use strict';
const fs = require('fs');
const timeoutErrorVectorTile = fs.readFileSync(__dirname + '/../../../assets/render-timeout-fallback.mvt');
const path = require('path');
const timeoutErrorVectorTile = fs.readFileSync(path.join(__dirname, '/../../../assets/render-timeout-fallback.mvt'));
module.exports = function vectorError () {
return function vectorErrorMiddleware (err, req, res, next) {
if (req.params.format === 'mvt') {
if (isTimeoutError(err) || isRateLimitError(err)) {
res.set('Content-Type', 'application/x-protobuf');
return res.status(429).send(timeoutErrorVectorTile);
@ -17,7 +17,6 @@ module.exports = function vectorError() {
};
};
function isRenderTimeoutError (err) {
return err.message === 'Render timed out';
}

View File

@ -19,7 +19,7 @@ module.exports = class AdminTemplateController {
}
route (templateRouter) {
templateRouter.options(`/:template_id`);
templateRouter.options('/:template_id');
templateRouter.post('/', this.middlewares({
action: 'create',

View File

@ -148,8 +148,8 @@ function getTemplate (
return function getTemplateMiddleware (req, res, next) {
const templateParams = req.body;
const { user, dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id } = req.params;
const { auth_token } = req.query;
const { template_id: templateId } = req.params;
const { auth_token: authToken } = req.query;
const params = Object.assign({ dbuser, dbname, dbpassword, dbhost, dbport }, req.query);
@ -161,9 +161,9 @@ function getTemplate (
mapConfigAdapter,
affectedTablesCache,
user,
template_id,
templateId,
templateParams,
auth_token,
authToken,
params
);

View File

@ -21,7 +21,7 @@ module.exports = class TemplateRouter {
authBackend,
layergroupMetadata,
namedMapProviderCache,
tileBackend,
tileBackend
} = collaborators;
this.namedMapController = new NamedMapController(

View File

@ -53,6 +53,7 @@ AnalysisBackend.prototype.create = function(analysisConfiguration, analysisDefin
};
this.getAnalysesLimits(analysisConfiguration.user, function (err, limits) {
if (err) {}
analysisConfiguration.limits = limits || {};
camshaft.create(analysisConfiguration, analysisDefinition, callback);
});
@ -76,6 +77,7 @@ AnalysisBackend.prototype.getAnalysesLimits = function(username, callback) {
var analysesLimitsKey = REDIS_LIMITS.PREFIX + username;
this.metadataBackend.redisCmd(REDIS_LIMITS.DB, 'HGETALL', [analysesLimitsKey], function (err, analysesTimeouts) {
if (err) {}
// analysesTimeouts wil be something like: { moran: 3000, intersection: 5000 }
analysesTimeouts = analysesTimeouts || {};

View File

@ -32,15 +32,15 @@ AuthBackend.prototype.authorizedBySigner = function(req, res, callback) {
var self = this;
var layergroup_id = res.locals.token;
var auth_token = req.query.auth_token;
var layergroupId = res.locals.token;
var authToken = req.query.auth_token;
this.mapStore.load(layergroup_id, function(err, mapConfig) {
this.mapStore.load(layergroupId, function (err, mapConfig) {
if (err) {
return callback(err);
}
var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, auth_token);
var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, authToken);
return callback(null, authorized);
});
@ -109,7 +109,7 @@ AuthBackend.prototype.authorizedByAPIKey = function(user, res, callback) {
};
function isNameNotFoundError (err) {
return err.message && -1 !== err.message.indexOf('name not found');
return err.message && err.message.indexOf('name not found') !== -1;
}
function usernameMatches (basicAuthUsername, requestUsername) {

View File

@ -71,8 +71,8 @@ function getFeatures (pg, layer, params, callback) {
}
const SKIP_COLUMNS = {
'the_geom': true,
'the_geom_webmercator': true
the_geom: true,
the_geom_webmercator: true
};
function getColumnsName (pg, query, callback) {
@ -194,9 +194,8 @@ function parseAggregation (aggregation) {
try {
aggregation = JSON.parse(aggregation);
} catch (err) {
throw new Error(`Invalid aggregation input, should be a a valid JSON`);
throw new Error('Invalid aggregation input, should be a a valid JSON');
}
}
return aggregation;
@ -207,7 +206,7 @@ function validateAggregation (aggregation) {
const { columns, expressions } = aggregation;
if (!hasColumns(columns)) {
throw new Error(`Invalid aggregation input, columns should be and array of column names`);
throw new Error('Invalid aggregation input, columns should be and array of column names');
}
validateExpressions(expressions);
@ -221,16 +220,16 @@ function hasColumns (columns) {
function validateExpressions (expressions) {
if (expressions !== undefined) {
if (!isValidExpression(expressions)) {
throw new Error(`Invalid aggregation input, expressions should be and object with valid functions`);
throw new Error('Invalid aggregation input, expressions should be and object with valid functions');
}
for (const { aggregate_function, aggregated_column } of Object.values(expressions)) {
if (typeof aggregated_column !== 'string') {
throw new Error(`Invalid aggregation input, aggregated column should be an string`);
for (const { aggregate_function: aggregateFunction, aggregated_column: aggregatedColumn } of Object.values(expressions)) {
if (typeof aggregatedColumn !== 'string') {
throw new Error('Invalid aggregation input, aggregated column should be an string');
}
if (typeof aggregate_function !== 'string') {
throw new Error(`Invalid aggregation input, aggregate function should be an string`);
if (typeof aggregateFunction !== 'string') {
throw new Error('Invalid aggregation input, aggregate function should be an string');
}
}
}

View File

@ -115,7 +115,7 @@ function getQueryRewriteData(mapConfig, dataviewDefinition, params) {
}
if (params.bbox && queryRewriteData) {
var bbox_filter_definition = {
var bboxFilterDefinition = {
type: 'bbox',
options: {
column: 'the_geom_webmercator',
@ -125,7 +125,7 @@ function getQueryRewriteData(mapConfig, dataviewDefinition, params) {
bbox: params.bbox
}
};
queryRewriteData = _.extend(queryRewriteData, { bbox_filter: bbox_filter_definition });
queryRewriteData = _.extend(queryRewriteData, { bbox_filter: bboxFilterDefinition });
}
return queryRewriteData;

View File

@ -10,24 +10,24 @@ function FilterStatsBackends(pgQueryRunner) {
module.exports = FilterStatsBackends;
function getEstimatedRows (pgQueryRunner, username, query, callback) {
pgQueryRunner.run(username, "EXPLAIN (FORMAT JSON)"+query, function(err, result_rows) {
pgQueryRunner.run(username, 'EXPLAIN (FORMAT JSON)' + query, function (err, resultRows) {
if (err) {
callback(err);
return;
}
var rows;
if ( result_rows[0] && result_rows[0]['QUERY PLAN'] &&
result_rows[0]['QUERY PLAN'][0] && result_rows[0]['QUERY PLAN'][0].Plan ) {
rows = result_rows[0]['QUERY PLAN'][0].Plan['Plan Rows'];
if (resultRows[0] && resultRows[0]['QUERY PLAN'] &&
resultRows[0]['QUERY PLAN'][0] && resultRows[0]['QUERY PLAN'][0].Plan) {
rows = resultRows[0]['QUERY PLAN'][0].Plan['Plan Rows'];
}
return callback(null, rows);
});
}
FilterStatsBackends.prototype.getFilterStats = function (username, unfiltered_query, filters, callback) {
FilterStatsBackends.prototype.getFilterStats = function (username, unfilteredQuery, filters, callback) {
var stats = {};
getEstimatedRows(this.pgQueryRunner, username, unfiltered_query, (err, rows) => {
getEstimatedRows(this.pgQueryRunner, username, unfilteredQuery, (err, rows) => {
if (err) {
return callback(err);
}
@ -39,7 +39,7 @@ FilterStatsBackends.prototype.getFilterStats = function (username, unfiltered_qu
}
var analysisFilter = new AnalysisFilter(filters);
var query = analysisFilter.sql(unfiltered_query);
var query = analysisFilter.sql(unfilteredQuery);
getEstimatedRows(this.pgQueryRunner, username, query, (err, rows) => {
if (err) {

View File

@ -41,7 +41,6 @@ LayerStats.prototype.getStats = function (mapConfig, dbConnection, callback) {
return callback(err, stats);
});
};
module.exports = LayerStats;

View File

@ -32,8 +32,7 @@ function _getSQL(ctx, query, type='pre', zoom=0) {
let sql;
if (type === 'pre') {
sql = ctx.preQuery;
}
else {
} else {
sql = ctx.aggrQuery;
}
sql = queryUtils.substituteTokensForZoom(sql, zoom || 0);
@ -56,7 +55,7 @@ function _featureCount(ctx) {
}
function _aggrFeatureCount (ctx) {
if (ctx.metaOptions.hasOwnProperty('aggrFeatureCount')) {
if (Object.prototype.hasOwnProperty.call(ctx.metaOptions, 'aggrFeatureCount')) {
// We expect as zoom level as the value of aggrFeatureCount
// TODO: it'd be nice to admit an array of zoom levels to
// return metadata for multiple levels.
@ -114,9 +113,9 @@ function mergeColumns(results) {
return {};
}
return results.reduce((a, b) => {
let c = Object.assign({}, b || {}, a || {});
const c = Object.assign({}, b || {}, a || {});
Object.keys(c).forEach(key => {
if (b.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(b, key)) {
c[key] = Object.assign(c[key], b[key]);
}
});
@ -176,7 +175,7 @@ function _columnStats(ctx, columns, dimensions) {
return Promise.resolve();
}
if (_columnsMetadataRequired(ctx.metaOptions)) {
let queries = [];
const queries = [];
let aggr = [];
if (ctx.metaOptions.columnStats) {
queries.push(new Promise(resolve => resolve({ columns }))); // add columns as first result
@ -187,9 +186,9 @@ function _columnStats(ctx, columns, dimensions) {
);
if (columns[name].type === 'string') {
const topN = ctx.metaOptions.columnStats.topCategories || 1024;
const includeNulls = ctx.metaOptions.columnStats.hasOwnProperty('includeNulls') ?
ctx.metaOptions.columnStats.includeNulls :
true;
const includeNulls = Object.prototype.hasOwnProperty.call(ctx.metaOptions.columnStats, 'includeNulls')
? ctx.metaOptions.columnStats.includeNulls
: true;
// TODO: ctx.metaOptions.columnStats.maxCategories
// => use PG stats to dismiss columns with more distinct values
@ -223,7 +222,7 @@ function _columnStats(ctx, columns, dimensions) {
ctx.dbConnection,
_getSQL(ctx, sql => `SELECT ${aggr.join(',')} FROM (${sql}) AS __cdb_query`)
).then(res => {
let stats = { columns: {}, dimensions: {} };
const stats = { columns: {}, dimensions: {} };
Object.keys(columns).forEach(name => {
stats.columns[name] = {};
columnAggregations(columns[name]).forEach(fn => {
@ -284,8 +283,8 @@ function fieldTypeSafe(dbConnection, field) {
// columns are returned as an object { columnName1: { type1: ...}, ..}
// for consistency with SQL API
function formatResultFields (dbConnection, fields = []) {
let nfields = {};
for (let field of fields) {
const nfields = {};
for (const field of fields) {
nfields[field.name] = { type: fieldTypeSafe(dbConnection, field) };
}
return nfields;
@ -293,14 +292,14 @@ function formatResultFields(dbConnection, fields = []) {
MapnikLayerStats.prototype.getStats =
function (layer, dbConnection, callback) {
let aggrQuery = layer.options.sql;
let preQuery = layer.options.sql_raw || aggrQuery;
const aggrQuery = layer.options.sql;
const preQuery = layer.options.sql_raw || aggrQuery;
let ctx = {
const ctx = {
dbConnection,
preQuery,
aggrQuery,
metaOptions: layer.options.metadata || {},
metaOptions: layer.options.metadata || {}
};
// TODO: could save some queries if queryUtils.getAggregationMetadata() has been used and kept somewhere

View File

@ -11,7 +11,6 @@ function PgConnection(metadataBackend) {
module.exports = PgConnection;
// Set db authentication parameters to those of the given username
//
// @param username the cartodb username, mapped to a database username
@ -71,10 +70,9 @@ PgConnection.prototype.setDBAuth = function(username, params, apikeyType, callba
};
function isNameNotFoundError (err) {
return err.message && -1 !== err.message.indexOf('name not found');
return err.message && err.message.indexOf('name not found') !== -1;
}
// Set db connection parameters to those for the given username
//
// @param dbowner cartodb username of database owner,
@ -119,7 +117,7 @@ PgConnection.prototype.setDBConn = function(dbowner, params, callback) {
*/
PgConnection.prototype.getConnection = function (username, callback) {
debug("getConn1");
debug('getConn1');
this.getDatabaseParams(username, (err, databaseParams) => {
if (err) {

View File

@ -17,7 +17,6 @@ module.exports = PgQueryRunner;
* @param {Function} callback function({Error}, {Array}) second argument is guaranteed to be an array
*/
PgQueryRunner.prototype.run = function (username, query, callback) {
this.pgConnection.getDatabaseParams(username, (err, databaseParams) => {
if (err) {
return callback(err);

View File

@ -21,16 +21,16 @@ TablesExtentBackend.prototype.getBounds = function (username, tables, callback)
});
var query = [
"WITH ext as (" +
"SELECT ST_Transform(ST_SetSRID(ST_Extent(ST_Union(ARRAY[",
'WITH ext as (' +
'SELECT ST_Transform(ST_SetSRID(ST_Extent(ST_Union(ARRAY[',
estimatedExtentSQLs.join(','),
"])), 3857), 4326) geom)",
"SELECT",
"ST_XMin(geom) west,",
"ST_YMin(geom) south,",
"ST_XMax(geom) east,",
"ST_YMax(geom) north",
"FROM ext"
'])), 3857), 4326) geom)',
'SELECT',
'ST_XMin(geom) west,',
'ST_YMin(geom) south,',
'ST_XMax(geom) east,',
'ST_YMax(geom) north',
'FROM ext'
].join(' ');
this.pgQueryRunner.run(username, query, function handleBoundsResult (err, rows) {

View File

@ -5,16 +5,14 @@ var debug = require('debug')('windshaft:templates');
var _ = require('underscore');
var dot = require('dot');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// Class handling map templates
//
// See http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps
//
// @param redis_pool an instance of a "redis-mpool"
// @param redisPool an instance of a "redis-mpool"
// See https://github.com/CartoDB/node-redis-mpool
// Needs version 0.x.x of the API.
//
@ -22,14 +20,14 @@ var util = require('util');
// 'max_user_templates' limit on the number of per-user
//
//
function TemplateMaps(redis_pool, opts) {
function TemplateMaps (redisPool, opts) {
if (!(this instanceof TemplateMaps)) {
return new TemplateMaps();
}
EventEmitter.call(this);
this.redis_pool = redis_pool;
this.redisPool = redisPool;
this.opts = opts || {};
// Database containing templates
@ -46,15 +44,14 @@ function TemplateMaps(redis_pool, opts) {
//
// 1. User templates: set of per-user map templates
// User templates (HASH:tpl_id->tpl_val)
this.key_usr_tpl = dot.template("map_tpl|{{=it.owner}}");
// User templates (HASH:tplId->tpl_val)
this.key_usr_tpl = dot.template('map_tpl|{{=it.owner}}');
}
util.inherits(TemplateMaps, EventEmitter);
module.exports = TemplateMaps;
// --------------- PRIVATE METHODS --------------------------------
TemplateMaps.prototype._userTemplateLimit = function () {
@ -69,13 +66,13 @@ TemplateMaps.prototype._userTemplateLimit = function() {
* @param callback - function to pass results too.
*/
TemplateMaps.prototype._redisCmd = function (redisFunc, redisArgs, callback) {
this.redis_pool.acquire(this.db_signatures, (err, redisClient) => {
this.redisPool.acquire(this.db_signatures, (err, redisClient) => {
if (err) {
return callback(err);
}
redisClient[redisFunc.toUpperCase()](...redisArgs, (err, data) => {
this.redis_pool.release(this.db_signatures, redisClient);
this.redisPool.release(this.db_signatures, redisClient);
if (err) {
return callback(err);
}
@ -84,16 +81,16 @@ TemplateMaps.prototype._redisCmd = function(redisFunc, redisArgs, callback) {
});
};
var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_\-]*$/i;
var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_-]*$/i;
var _reValidPlaceholderIdentifier = /^[a-z][0-9a-z_]*$/i;
// jshint maxcomplexity:15
TemplateMaps.prototype._checkInvalidTemplate = function (template) {
if (template.version !== '0.0.1') {
return new Error("Unsupported template version " + template.version);
return new Error('Unsupported template version ' + template.version);
}
var tplname = template.name;
if (!tplname) {
return new Error("Missing template name");
return new Error('Missing template name');
}
if (!tplname.match(_reValidNameIdentifier)) {
return new Error("Invalid characters in template name '" + tplname + "'");
@ -113,10 +110,10 @@ TemplateMaps.prototype._checkInvalidTemplate = function(template) {
if (!placeholderKey.match(_reValidPlaceholderIdentifier)) {
return new Error("Invalid characters in placeholder name '" + placeholderKey + "'");
}
if ( ! placeholders[placeholderKey].hasOwnProperty('default') ) {
if (!Object.prototype.hasOwnProperty.call(placeholders[placeholderKey], 'default')) {
return new Error("Missing default for placeholder '" + placeholderKey + "'");
}
if ( ! placeholders[placeholderKey].hasOwnProperty('type') ) {
if (!Object.prototype.hasOwnProperty.call(placeholders[placeholderKey], 'type')) {
return new Error("Missing type for placeholder '" + placeholderKey + "'");
}
}
@ -135,7 +132,7 @@ TemplateMaps.prototype._checkInvalidTemplate = function(template) {
}
break;
default:
return new Error("Unsupported authentication method: " + auth.method);
return new Error('Unsupported authentication method: ' + auth.method);
}
return false;
@ -218,7 +215,7 @@ TemplateMaps.prototype._checkUserTemplatesLimit = function(userTemplatesKey, own
// @param template layergroup template, see
// http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format
//
// @param callback function(err, tpl_id)
// @param callback function(err, tplId)
// Return template identifier (only valid for given user)
//
TemplateMaps.prototype.addTemplate = function (owner, template, callback) {
@ -263,22 +260,22 @@ TemplateMaps.prototype.addTemplate = function(owner, template, callback) {
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned
// @param tplId template identifier as returned
// by addTemplate or listTemplates
//
// @param callback function(err)
//
TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) {
this._redisCmd('HDEL', [ this.key_usr_tpl({ owner:owner }), tpl_id ], (err, deleted) => {
TemplateMaps.prototype.delTemplate = function (owner, tplId, callback) {
this._redisCmd('HDEL', [this.key_usr_tpl({ owner: owner }), tplId], (err, deleted) => {
if (err) {
return callback(err);
}
if (!deleted) {
return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`));
return callback(new Error(`Template '${tplId}' of user '${owner}' does not exist`));
}
this.emit('delete', owner, tpl_id);
this.emit('delete', owner, tplId);
return callback();
});
};
@ -292,14 +289,14 @@ TemplateMaps.prototype.delTemplate = function(owner, tpl_id, callback) {
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned by addTemplate
// @param tplId template identifier as returned by addTemplate
//
// @param template layergroup template, see
// http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format
//
// @param callback function(err)
//
TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback) {
TemplateMaps.prototype.updTemplate = function (owner, tplId, template, callback) {
template = templateDefaults(template);
var invalidError = this._checkInvalidTemplate(template);
@ -307,19 +304,19 @@ TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback)
return callback(invalidError);
}
if (tpl_id !== template.name) {
return callback(new Error(`Cannot update name of a map template ('${tpl_id}' != '${template.name}')`));
if (tplId !== template.name) {
return callback(new Error(`Cannot update name of a map template ('${tplId}' != '${template.name}')`));
}
var userTemplatesKey = this.key_usr_tpl({ owner });
this._redisCmd('HGET', [userTemplatesKey, tpl_id], (err, beforeUpdateTemplate) => {
this._redisCmd('HGET', [userTemplatesKey, tplId], (err, beforeUpdateTemplate) => {
if (err) {
return callback(err);
}
if (!beforeUpdateTemplate) {
return callback(new Error(`Template '${tpl_id}' of user '${owner}' does not exist`));
return callback(new Error(`Template '${tplId}' of user '${owner}' does not exist`));
}
let templateString;
@ -358,7 +355,7 @@ TemplateMaps.prototype.updTemplate = function(owner, tpl_id, template, callback)
//
// @param owner cartodb username of the templates owner
//
// @param callback function(err, tpl_id_list)
// @param callback function(err, tplId_list)
// Returns a list of template identifiers
//
TemplateMaps.prototype.listTemplates = function (owner, callback) {
@ -369,14 +366,14 @@ TemplateMaps.prototype.listTemplates = function(owner, callback) {
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned
// @param tplId template identifier as returned
// by addTemplate or listTemplates
//
// @param callback function(err, template)
// Return full template definition
//
TemplateMaps.prototype.getTemplate = function(owner, tpl_id, callback) {
this._redisCmd('HGET', [this.key_usr_tpl({owner:owner}), tpl_id], (err, template) => {
TemplateMaps.prototype.getTemplate = function (owner, tplId, callback) {
this._redisCmd('HGET', [this.key_usr_tpl({ owner: owner }), tplId], (err, template) => {
if (err) {
return callback(err);
}
@ -432,14 +429,14 @@ TemplateMaps.prototype.isAuthorized = function(template, authTokens) {
//
// @throws Error on malformed template or parameter
//
var _reNumber = /^([-+]?[\d\.]?\d+([eE][+-]?\d+)?)$/,
_reCSSColorName = /^[a-zA-Z]+$/,
_reCSSColorVal = /^#[0-9a-fA-F]{3,6}$/;
var _reNumber = /^([-+]?[\d\.]?\d+([eE][+-]?\d+)?)$/; // eslint-disable-line no-useless-escape
var _reCSSColorName = /^[a-zA-Z]+$/;
var _reCSSColorVal = /^#[0-9a-fA-F]{3,6}$/;
function _replaceVars (str, params) {
// Construct regular expressions for each param
Object.keys(params).forEach(function (k) {
str = str.replace(new RegExp("<%=\\s*" + k + "\\s*%>", "g"), params[k]);
str = str.replace(new RegExp('<%=\\s*' + k + '\\s*%>', 'g'), params[k]);
});
return str;
}
@ -449,38 +446,34 @@ function isObject(val) {
}
TemplateMaps.prototype.instance = function (template, params) {
var all_params = {};
var allParams = {};
var phold = template.placeholders || {};
Object.keys(phold).forEach(function (k) {
var val = params.hasOwnProperty(k) ? params[k] : phold[k].default;
var val = Object.prototype.hasOwnProperty.call(params, k) ? params[k] : phold[k].default;
var type = phold[k].type;
// properly escape
if (type === 'sql_literal') {
// duplicate any single-quote
val = val.replace(/'/g, "''");
}
else if ( type === 'sql_ident' ) {
} else if (type === 'sql_ident') {
// duplicate any double-quote
val = val.replace(/"/g, '""');
}
else if ( type === 'number' ) {
} else if (type === 'number') {
// check it's a number
if (typeof (val) !== 'number' && !val.match(_reNumber)) {
throw new Error("Invalid number value for template parameter '" + k + "': " + val);
}
}
else if ( type === 'css_color' ) {
} else if (type === 'css_color') {
// check it only contains letters or
// starts with # and only contains hexdigits
if (!val.match(_reCSSColorName) && !val.match(_reCSSColorVal)) {
throw new Error("Invalid css_color value for template parameter '" + k + "': " + val);
}
}
else {
} else {
// NOTE: should be checked at template create/update time
throw new Error("Invalid placeholder type '" + type + "'");
}
all_params[k] = val;
allParams[k] = val;
});
// NOTE: we're deep-cloning the layergroup here
@ -488,7 +481,7 @@ TemplateMaps.prototype.instance = function(template, params) {
if (layergroup.buffersize && isObject(layergroup.buffersize)) {
Object.keys(layergroup.buffersize).forEach(function (k) {
layergroup.buffersize[k] = parseInt(_replaceVars(layergroup.buffersize[k], all_params), 10);
layergroup.buffersize[k] = parseInt(_replaceVars(layergroup.buffersize[k], allParams), 10);
});
}
@ -499,10 +492,10 @@ TemplateMaps.prototype.instance = function(template, params) {
// dynamic styling for this layer
lyropt.cartocss = params.styles[i];
} else if (lyropt.cartocss) {
lyropt.cartocss = _replaceVars(lyropt.cartocss, all_params);
lyropt.cartocss = _replaceVars(lyropt.cartocss, allParams);
}
if (lyropt.sql) {
lyropt.sql = _replaceVars(lyropt.sql, all_params);
lyropt.sql = _replaceVars(lyropt.sql, allParams);
}
// Anything else ?
}

View File

@ -68,7 +68,7 @@ PostgresDatasource.prototype.getName = function () {
};
PostgresDatasource.prototype.getRamp = function (column, buckets, method, callback) {
if (method && !methodTemplates.hasOwnProperty(method)) {
if (method && !Object.prototype.hasOwnProperty.call(methodTemplates, method)) {
return callback(new Error(
'Invalid method "' + method + '", valid methods: [' + Object.keys(methodTemplates).join(',') + ']'
));

View File

@ -10,7 +10,6 @@ function NamedMaps(owner, name) {
module.exports = NamedMaps;
NamedMaps.prototype.key = function () {
return this.namespace + ':' + shortHashKey(this.owner + ':' + this.name);
};

View File

@ -34,7 +34,7 @@ module.exports = class NamedMapProviderCache {
const namedMapProviders = this.providerCache.get(namedMapKey) || {};
const providerKey = createProviderKey(config, authToken, params);
if (namedMapProviders.hasOwnProperty(providerKey)) {
if (Object.prototype.hasOwnProperty.call(namedMapProviders, providerKey)) {
return callback(null, namedMapProviders[providerKey]);
}

View File

@ -12,7 +12,6 @@ function SurrogateKeysCache(cacheBackends) {
module.exports = SurrogateKeysCache;
/**
* @param response should respond to `header(key, value)` method
* @param cacheObject should respond to `key() -> String` method
@ -23,11 +22,10 @@ SurrogateKeysCache.prototype.tag = function(response, cacheObject) {
response.get('Surrogate-Key'),
Array.isArray(newKey) ? cacheObject.key().join(' ') : newKey
));
};
function appendSurrogateKey (currentKey, newKey) {
if (!!currentKey) {
if (currentKey) {
newKey = currentKey + ' ' + newKey;
}
return newKey;

View File

@ -83,7 +83,7 @@ module.exports = class AggregationMapConfig extends MapConfig {
}
getAggregatedQuery (index) {
const { sql_raw, sql } = this.getLayer(index).options;
const { sql_raw: sqlRaw, sql } = this.getLayer(index).options;
const {
// The default aggregation has no placement, columns or dimensions;
// this enables the special "full-sample" aggregation.
@ -96,7 +96,7 @@ module.exports = class AggregationMapConfig extends MapConfig {
} = this.getAggregation(index);
return aggregationQuery({
query: sql_raw || sql,
query: sqlRaw || sql,
resolution,
threshold,
placement,
@ -108,7 +108,7 @@ module.exports = class AggregationMapConfig extends MapConfig {
}
isAggregationLayer (index) {
let hasAggregation = this.hasLayerAggregation(index);
const hasAggregation = this.hasLayerAggregation(index);
// for vector-only MapConfig are aggregated unless explicitly disabled
return hasAggregation || (
this.isVectorOnlyMapConfig() && hasAggregation !== AggregationMapConfig.HAS_AGGREGATION_DISABLED
@ -176,7 +176,7 @@ module.exports = class AggregationMapConfig extends MapConfig {
_getLayerAggregationRequiredColumns (index) {
const { columns, dimensions } = this.getAggregation(index);
let finalColumns = ['cartodb_id', '_cdb_feature_count'];
const finalColumns = ['cartodb_id', '_cdb_feature_count'];
let aggregatedColumns = [];
if (columns) {
@ -192,9 +192,9 @@ module.exports = class AggregationMapConfig extends MapConfig {
}
doesLayerReachThreshold (index, featureCount) {
const threshold = this.getAggregation(index) && this.getAggregation(index).threshold ?
this.getAggregation(index).threshold :
AggregationMapConfig.THRESHOLD;
const threshold = this.getAggregation(index) && this.getAggregation(index).threshold
? this.getAggregation(index).threshold
: AggregationMapConfig.THRESHOLD;
return featureCount >= threshold;
}

View File

@ -50,30 +50,30 @@ module.exports.infoForOptions = (options) => {
};
const SUPPORTED_AGGREGATE_FUNCTIONS = {
'count': {
sql: (column_name, params) => `count(${params.aggregated_column || '*'})`
count: {
sql: (columnName, params) => `count(${params.aggregated_column || '*'})`
},
'avg': {
sql: (column_name, params) => `avg(${params.aggregated_column || column_name})`
avg: {
sql: (columnName, params) => `avg(${params.aggregated_column || columnName})`
},
'sum': {
sql: (column_name, params) => `sum(${params.aggregated_column || column_name})`
sum: {
sql: (columnName, params) => `sum(${params.aggregated_column || columnName})`
},
'min': {
sql: (column_name, params) => `min(${params.aggregated_column || column_name})`
min: {
sql: (columnName, params) => `min(${params.aggregated_column || columnName})`
},
'max': {
sql: (column_name, params) => `max(${params.aggregated_column || column_name})`
max: {
sql: (columnName, params) => `max(${params.aggregated_column || columnName})`
},
'mode': {
sql: (column_name, params) => `mode() WITHIN GROUP (ORDER BY ${params.aggregated_column || column_name})`
mode: {
sql: (columnName, params) => `mode() WITHIN GROUP (ORDER BY ${params.aggregated_column || columnName})`
}
};
module.exports.SUPPORTED_AGGREGATE_FUNCTIONS = Object.keys(SUPPORTED_AGGREGATE_FUNCTIONS);
const sep = (list) => {
let expr = list.join(', ');
const expr = list.join(', ');
return expr ? ', ' + expr : expr;
};
@ -85,20 +85,20 @@ const aggregateColumns = ctx => {
}, ctx.columns || {});
};
const aggregateExpression = (column_name, column_parameters) => {
const aggregate_function = column_parameters.aggregate_function || 'count';
const aggregate_definition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregate_function];
if (!aggregate_definition) {
throw new Error("Invalid Aggregate function: '" + aggregate_function + "'");
const aggregateExpression = (columnName, columnParameters) => {
const aggregateFunction = columnParameters.aggregate_function || 'count';
const aggregateDefinition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregateFunction];
if (!aggregateDefinition) {
throw new Error("Invalid Aggregate function: '" + aggregateFunction + "'");
}
return aggregate_definition.sql(column_name, column_parameters);
return aggregateDefinition.sql(columnName, columnParameters);
};
const aggregateColumnDefs = ctx => {
let columns = aggregateColumns(ctx);
return sep(Object.keys(columns).map(column_name => {
const aggregate_expression = aggregateExpression(column_name, columns[column_name]);
return `${aggregate_expression} AS ${column_name}`;
const columns = aggregateColumns(ctx);
return sep(Object.keys(columns).map(columnName => {
const aggregate = aggregateExpression(columnName, columns[columnName]);
return `${aggregate} AS ${columnName}`;
}));
};
@ -135,7 +135,7 @@ const dimensionExpression = definition => {
};
const dimensionNamesAndExpressions = (ctx) => {
let dimensions = aggregateDimensions(ctx);
const dimensions = aggregateDimensions(ctx);
return Object.keys(dimensions).map(dimensionName => {
const dimension = adaptDimensionDefinition(dimensions[dimensionName]);
const expression = dimensionExpression(dimension);
@ -192,7 +192,7 @@ const sqlQ = (value) => {
const FILTERS = {
between: (expr, filter) => {
const lo = filter.greater_than_or_equal_to, hi = filter.less_than_or_equal_to;
const lo = filter.greater_than_or_equal_to; const hi = filter.less_than_or_equal_to;
if (lo != null && hi != null) {
return `(${expr} BETWEEN ${sqlQ(lo)} AND ${sqlQ(hi)})`;
}
@ -218,7 +218,7 @@ const FILTERS = {
}
},
range: (expr, filter) => {
let conds = [];
const conds = [];
if (filter.greater_than_or_equal_to != null) {
conds.push(`(${expr} >= ${sqlQ(filter.greater_than_or_equal_to)})`);
}
@ -238,26 +238,25 @@ const FILTERS = {
};
const filterConditions = ctx => {
let columns = aggregateColumns(ctx);
let dimensions = aggregateDimensions(ctx);
let filters = aggregateFilters(ctx);
return Object.keys(filters).map(filtered_column => {
let filtered_expr;
if (columns[filtered_column]) {
filtered_expr = aggregateExpression(filtered_column, columns[filtered_column]);
const columns = aggregateColumns(ctx);
const dimensions = aggregateDimensions(ctx);
const filters = aggregateFilters(ctx);
return Object.keys(filters).map(filteredColumn => {
let filteredExpr;
if (columns[filteredColumn]) {
filteredExpr = aggregateExpression(filteredColumn, columns[filteredColumn]);
} else if (dimensions[filteredColumn]) {
filteredExpr = dimensions[filteredColumn];
}
else if (dimensions[filtered_column]) {
filtered_expr = dimensions[filtered_column];
if (!filteredExpr) {
throw new Error("Invalid filtered column: '" + filteredColumn + "'");
}
if (!filtered_expr) {
throw new Error("Invalid filtered column: '" + filtered_column + "'");
}
return filterConditionSQL(filtered_expr, filters[filtered_column]);
return filterConditionSQL(filteredExpr, filters[filteredColumn]);
}).join(' AND ');
};
const havingClause = ctx => {
let cond = filterConditions(ctx);
const cond = filterConditions(ctx);
return cond ? `HAVING ${cond}` : '';
};
@ -309,18 +308,16 @@ const gridInfoQuery = ctx => {
`;
};
// Function to generate the resulting point for a cell from the aggregated data
const aggregatedPointWebMercator = (ctx) => {
switch (ctx.placement) {
// For centroid, we return the average of the cell
case 'centroid':
return ', ST_SetSRID(ST_MakePoint(AVG(cdb_x), AVG(cdb_y)), 3857) AS the_geom_webmercator';
// Middle point of the cell
case 'point-grid':
return `, ST_SetSRID(ST_MakePoint(cdb_pos_grid_x, cdb_pos_grid_y), 3857) AS the_geom_webmercator`;
return ', ST_SetSRID(ST_MakePoint(cdb_pos_grid_x, cdb_pos_grid_y), 3857) AS the_geom_webmercator';
// For point-sample we'll get a single point directly from the source
// If it's default aggregation we'll add the extra columns to keep backwards compatibility
@ -335,29 +332,25 @@ const aggregatedPointWebMercator = (ctx) => {
// Function to generate the resulting point for a cell from the a join with the source
const aggregatedPointJoin = (ctx) => {
switch (ctx.placement) {
case 'centroid':
return '';
case 'point-grid':
return '';
// For point-sample we'll get a single point directly from the source
// If it's default aggregation we'll add the extra columns to keep backwards compatibility
case 'point-sample':
return `
NATURAL JOIN
(
SELECT ${ctx.isDefaultAggregation ? `*` : `cartodb_id, the_geom_webmercator`}
SELECT ${ctx.isDefaultAggregation ? '*' : 'cartodb_id, the_geom_webmercator'}
FROM
(
${ctx.sourceQuery}
) __cdb_src_query
) __cdb_query_columns
`;
default:
throw new Error('Invalid aggregation placement "${ctx.placement}"');
throw new Error(`Invalid aggregation placement "${ctx.placement}"`);
}
};
@ -368,7 +361,7 @@ NATURAL JOIN
const aggregatedPosCoordinate = (ctx, coordinate) => {
switch (ctx.placement) {
// For point-grid we return the coordinate of the middle point of the grid
case `point-grid`:
case 'point-grid':
return `(FLOOR(cdb_${coordinate} / __cdb_grid_params.cdb_res) + 0.5) * __cdb_grid_params.cdb_res`;
// For other, we return the cell position (relative to the world)
@ -377,7 +370,6 @@ const aggregatedPosCoordinate = (ctx, coordinate) => {
}
};
const aggregationQueryTemplate = ctx => `
WITH __cdb_grid_params AS
(

View File

@ -80,7 +80,7 @@ function createAggregationColumnNamesValidator(mapconfig) {
return function validateAggregationColumnNames (value, key, index) {
Object.keys(value).forEach((columnName) => {
if (columnName.length <= 0) {
const message = `Invalid column name, should be a non empty string`;
const message = 'Invalid column name, should be a non empty string';
throw createLayerError(message, mapconfig, index);
}
});
@ -90,10 +90,10 @@ function createAggregationColumnNamesValidator(mapconfig) {
function createAggregateFunctionValidator (mapconfig, validAggregatedFunctions) {
return function validateAggregateFunction (value, key, index) {
Object.keys(value).forEach((columnName) => {
const { aggregate_function } = value[columnName];
const { aggregate_function: aggregateFunction } = value[columnName];
if (!validAggregatedFunctions.includes(aggregate_function)) {
const message = `Unsupported aggregation function ${aggregate_function},` +
if (!validAggregatedFunctions.includes(aggregateFunction)) {
const message = `Unsupported aggregation function ${aggregateFunction},` +
` valid ones: ${validAggregatedFunctions.join(', ')}`;
throw createLayerError(message, mapconfig, index);
}
@ -104,10 +104,10 @@ function createAggregateFunctionValidator (mapconfig, validAggregatedFunctions)
function createAggregatedColumnValidator (mapconfig) {
return function validateAggregatedColumn (value, key, index) {
Object.keys(value).forEach((columnName) => {
const { aggregated_column } = value[columnName];
const { aggregated_column: aggregatedColumn } = value[columnName];
if (typeof aggregated_column !== 'string' || aggregated_column <= 0) {
const message = `Invalid aggregated column, should be a non empty string`;
if (typeof aggregatedColumn !== 'string' || aggregatedColumn <= 0) {
const message = 'Invalid aggregated column, should be a non empty string';
throw createLayerError(message, mapconfig, index);
}
});

View File

@ -28,7 +28,7 @@ function timeExpression(t, tz) {
function epochWithDefaults (epoch) {
/* jshint maxcomplexity:9 */ // goddammit linter, I like this as is!!
const format = /^(\d\d\d\d)(?:\-?(\d\d)(?:\-?(\d\d)(?:[T\s]?(\d\d)(?:(\d\d)(?:\:(\d\d))?)?)?)?)?$/;
const format = /^(\d\d\d\d)(?:\-?(\d\d)(?:\-?(\d\d)(?:[T\s]?(\d\d)(?:(\d\d)(?:\:(\d\d))?)?)?)?)?$/; // eslint-disable-line no-useless-escape
const match = (epoch || '').match(format) || [];
const year = match[1] || '0001';
const month = match[2] || '01';
@ -131,19 +131,19 @@ function serialSqlExpr(params) {
}
const isoParts = {
second: `to_char($t, 'YYYY-MM-DD"T"HH24:MI:SS')`,
minute: `to_char($t, 'YYYY-MM-DD"T"HH24:MI')`,
hour: `to_char($t, 'YYYY-MM-DD"T"HH24')`,
day: `to_char($t, 'YYYY-MM-DD')`,
month: `to_char($t, 'YYYY-MM')`,
year: `to_char($t, 'YYYY')`,
week: `to_char($t, 'IYYY-"W"IW')`,
quarter: `to_char($t, 'YYYY-"Q"Q')`,
semester: `to_char($t, 'YYYY"S"') || to_char(CEIL(date_part('month', $t)/6), '9')`,
trimester: `to_char($t, 'YYYY"t"') || to_char(CEIL(date_part('month', $t)/4), '9')`,
decade: `to_char(date_part('decade', $t), '"D"999')`,
century: `to_char($t, '"C"CC')`,
millennium: `to_char(date_part('millennium', $t), '"M"999')`
second: 'to_char($t, \'YYYY-MM-DD"T"HH24:MI:SS\')',
minute: 'to_char($t, \'YYYY-MM-DD"T"HH24:MI\')',
hour: 'to_char($t, \'YYYY-MM-DD"T"HH24\')',
day: 'to_char($t, \'YYYY-MM-DD\')',
month: 'to_char($t, \'YYYY-MM\')',
year: 'to_char($t, \'YYYY\')',
week: 'to_char($t, \'IYYY-"W"IW\')',
quarter: 'to_char($t, \'YYYY-"Q"Q\')',
semester: 'to_char($t, \'YYYY"S"\') || to_char(CEIL(date_part(\'month\', $t)/6), \'9\')',
trimester: 'to_char($t, \'YYYY"t"\') || to_char(CEIL(date_part(\'month\', $t)/4), \'9\')',
decade: 'to_char(date_part(\'decade\', $t), \'"D"999\')',
century: 'to_char($t, \'"C"CC\')',
millennium: 'to_char(date_part(\'millennium\', $t), \'"M"999\')'
};
function isoSqlExpr (params) {
@ -156,16 +156,16 @@ function isoSqlExpr(params) {
}
const cyclicParts = {
dayOfWeek: `date_part('isodow', $t)`, // 1 = monday to 7 = sunday;
dayOfMonth: `date_part('day', $t)`, // 1 to 31
dayOfYear: `date_part('doy', $t)`, // 1 to 366
hourOfDay: `date_part('hour', $t)`, // 0 to 23
monthOfYear: `date_part('month', $t)`, // 1 to 12
quarterOfYear: `date_part('quarter', $t)`, // 1 to 4
semesterOfYear: `FLOOR((date_part('month', $t)-1)/6.0) + 1`, // 1 to 2
trimesterOfYear: `FLOOR((date_part('month', $t)-1)/4.0) + 1`, // 1 to 3
weekOfYear: `date_part('week', $t)`, // 1 to 53
minuteOfHour: `date_part('minute', $t)` // 0 to 59
dayOfWeek: 'date_part(\'isodow\', $t)', // 1 = monday to 7 = sunday;
dayOfMonth: 'date_part(\'day\', $t)', // 1 to 31
dayOfYear: 'date_part(\'doy\', $t)', // 1 to 366
hourOfDay: 'date_part(\'hour\', $t)', // 0 to 23
monthOfYear: 'date_part(\'month\', $t)', // 1 to 12
quarterOfYear: 'date_part(\'quarter\', $t)', // 1 to 4
semesterOfYear: 'FLOOR((date_part(\'month\', $t)-1)/6.0) + 1', // 1 to 2
trimesterOfYear: 'FLOOR((date_part(\'month\', $t)-1)/4.0) + 1', // 1 to 3
weekOfYear: 'date_part(\'week\', $t)', // 1 to 53
minuteOfHour: 'date_part(\'minute\', $t)' // 0 to 59
};
function cyclicSqlExpr (params) {
@ -187,12 +187,12 @@ function validateParameters(params, checker) {
if (missingParams.length) {
errors.push(`Missing parameters: ${missingParams.join(', ')}`);
}
const params_errors = checker(params);
errors.push(...params_errors.errors);
const paramsErrors = checker(params);
errors.push(...paramsErrors.errors);
if (errors.length) {
throw new Error(`Invalid time dimension:\n${errors.join("\n")}`);
throw new Error(`Invalid time dimension:\n${errors.join('\n')}`);
}
return params_errors.params;
return paramsErrors.params;
}
const VALID_CYCLIC_UNITS = Object.keys(cyclicParts);

View File

@ -8,7 +8,6 @@ function CdbRequest() {
module.exports = CdbRequest;
CdbRequest.prototype.userByReq = function (req) {
var host = req.headers.host || '';
if (req.params.user) {

View File

@ -12,8 +12,8 @@ const filteredQueryTpl = ctx => `
AND
${ctx.aggregationColumn} != '-infinity'::float
AND
${ctx.aggregationColumn} != 'NaN'::float` :
''
${ctx.aggregationColumn} != 'NaN'::float`
: ''
}
`;
@ -30,8 +30,8 @@ const summaryQueryTpl = ctx => `
ELSE 0
END
) AS infinities_count,
sum(CASE WHEN ${ctx.aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count` :
''
sum(CASE WHEN ${ctx.aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count`
: ''
}
FROM (${ctx.query}) _cdb_aggregation_nulls
)
@ -44,7 +44,7 @@ const rankedCategoriesQueryTpl = ctx => `
${ctx.aggregationFn} AS value,
row_number() OVER (ORDER BY ${ctx.aggregationFn} desc) as rank
FROM (${filteredQueryTpl(ctx)}) filtered_source
WHERE ${ctx.aggregation === "count" ? `${ctx.column}` : `${ctx.aggregationColumn}`} IS NOT NULL
WHERE ${ctx.aggregation === 'count' ? `${ctx.column}` : `${ctx.aggregationColumn}`} IS NOT NULL
GROUP BY ${ctx.column}
ORDER BY 2 DESC
)
@ -70,7 +70,7 @@ const categoriesSummaryCountQueryTpl = ctx => `
)
`;
const specialNumericValuesColumns = () => `, nans_count, infinities_count`;
const specialNumericValuesColumns = () => ', nans_count, infinities_count';
const rankedAggregationQueryTpl = ctx => `
SELECT
@ -138,7 +138,7 @@ const aggregationDataviewQueryTpl = ctx => `
${rankedCategoriesQueryTpl(ctx)},
${categoriesSummaryMinMaxQueryTpl(ctx)},
${categoriesSummaryCountQueryTpl(ctx)}
${!!ctx.override.ownFilter ? `${aggregationQueryTpl(ctx)}` : `${rankedAggregationQueryTpl(ctx)}`}
${ctx.override.ownFilter ? `${aggregationQueryTpl(ctx)}` : `${rankedAggregationQueryTpl(ctx)}`}
`;
const filterCategoriesQueryTpl = ctx => `
@ -206,11 +206,11 @@ module.exports = class Aggregation extends BaseDataview {
_checkOptions (options) {
if (typeof options.column !== 'string') {
throw new Error(`Aggregation expects 'column' in dataview options`);
throw new Error('Aggregation expects \'column\' in dataview options');
}
if (typeof options.aggregation !== 'string') {
throw new Error(`Aggregation expects 'aggregation' operation in dataview options`);
throw new Error('Aggregation expects \'aggregation\' operation in dataview options');
}
if (!VALID_OPERATIONS[options.aggregation]) {
@ -218,7 +218,7 @@ module.exports = class Aggregation extends BaseDataview {
}
const requiredOptions = VALID_OPERATIONS[options.aggregation];
const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption));
const missingOptions = requiredOptions.filter(requiredOption => !Object.prototype.hasOwnProperty.call(options, requiredOption));
if (missingOptions.length > 0) {
throw new Error(
@ -244,9 +244,9 @@ module.exports = class Aggregation extends BaseDataview {
return null;
}
const limit = Number.isFinite(override.categories) && override.categories > 0 ?
override.categories :
CATEGORIES_LIMIT;
const limit = Number.isFinite(override.categories) && override.categories > 0
? override.categories
: CATEGORIES_LIMIT;
const aggregationSql = aggregationDataviewQueryTpl({
override: override,
@ -303,9 +303,9 @@ module.exports = class Aggregation extends BaseDataview {
search (psql, userQuery, callback) {
const escapedUserQuery = psql.escapeLiteral(`%${userQuery}%`);
const value = this.aggregation !== 'count' && this.aggregationColumn ?
`${this.aggregation}(${this.aggregationColumn})` :
'count(1)';
const value = this.aggregation !== 'count' && this.aggregationColumn
? `${this.aggregation}(${this.aggregationColumn})`
: 'count(1)';
// TODO unfiltered will be wrong as filters are already applied at this point
const query = searchQueryTpl({

View File

@ -16,8 +16,8 @@ const columnTypeQueryTpl = ctx => `SELECT pg_typeof(${ctx.column})::oid FROM (${
function getPGTypeName (pgType) {
return {
float: FLOAT_OIDS.hasOwnProperty(pgType),
date: DATE_OIDS.hasOwnProperty(pgType)
float: Object.prototype.hasOwnProperty.call(FLOAT_OIDS, pgType),
date: Object.prototype.hasOwnProperty.call(DATE_OIDS, pgType)
};
}

View File

@ -8,8 +8,8 @@ const formulaQueryTpl = ctx =>
`SELECT
${ctx.operation}(${utils.handleFloatColumn(ctx)}) AS result,
${utils.countNULLs(ctx)} AS nulls_count
${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ``}
${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ``}
${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ''}
${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ''}
FROM (${ctx.query}) __cdb_formula`;
const VALID_OPERATIONS = {
@ -46,7 +46,7 @@ module.exports = class Formula extends BaseDataview {
_checkOptions (options) {
if (typeof options.operation !== 'string') {
throw new Error(`Formula expects 'operation' in dataview options`);
throw new Error('Formula expects \'operation\' in dataview options');
}
if (!VALID_OPERATIONS[options.operation]) {
@ -54,11 +54,10 @@ module.exports = class Formula extends BaseDataview {
}
if (options.operation !== 'count' && typeof options.column !== 'string') {
throw new Error(`Formula expects 'column' in dataview options`);
throw new Error('Formula expects \'column\' in dataview options');
}
}
sql (psql, override, callback) {
if (!callback) {
callback = override;
@ -92,16 +91,16 @@ module.exports = class Formula extends BaseDataview {
const {
result = 0,
nulls_count = 0,
nans_count,
infinities_count
nans_count: nansCount,
infinities_count: infinitiesCount
} = res.rows[0] || {};
return {
operation: this.operation,
result,
nulls: nulls_count,
nans: nans_count,
infinities: infinities_count
nans: nansCount,
infinities: infinitiesCount
};
}

View File

@ -44,7 +44,8 @@ module.exports = class Histogram {
}
_isDateHistogram (override = {}) {
return (this.options.hasOwnProperty('aggregation') || override.hasOwnProperty('aggregation'));
return (Object.prototype.hasOwnProperty.call(this.options, 'aggregation') ||
Object.prototype.hasOwnProperty.call(override, 'aggregation'));
}
getResult (psql, override, callback) {

View File

@ -62,7 +62,7 @@ module.exports = class BaseHistogram extends BaseDataview {
}
_hasOverridenRange (override) {
return override && override.hasOwnProperty('start') && override.hasOwnProperty('end');
return override && Object.prototype.hasOwnProperty.call(override, 'start') && Object.prototype.hasOwnProperty.call(override, 'end');
}
_getBinStart (override = {}) {

View File

@ -4,7 +4,6 @@ const BaseHistogram = require('./base-histogram');
const debug = require('debug')('windshaft:dataview:date-histogram');
const utils = require('../../../utils/query-utils');
/**
* Gets the name of a timezone with the same offset as the required
* using the pg_timezone_names table. We do this because it's simpler to pass
@ -33,17 +32,16 @@ WITH __wd_tz AS
* our timezone so when calling date_trunc it falls into the correct bin
*/
function dataBucketsQuery (ctx) {
var condition_str = '';
var conditionStr = '';
if (ctx.start !== 0) {
condition_str = `WHERE ${ctx.column} >= to_timestamp(${ctx.start})`;
conditionStr = `WHERE ${ctx.column} >= to_timestamp(${ctx.start})`;
}
if (ctx.end !== 0) {
if (condition_str === '') {
condition_str = `WHERE ${ctx.column} <= to_timestamp(${ctx.end})`;
}
else {
condition_str += ` and ${ctx.column} <= to_timestamp(${ctx.end})`;
if (conditionStr === '') {
conditionStr = `WHERE ${ctx.column} <= to_timestamp(${ctx.end})`;
} else {
conditionStr += ` and ${ctx.column} <= to_timestamp(${ctx.end})`;
}
}
@ -58,7 +56,7 @@ __wd_buckets AS
(
${ctx.query}
) __source, __wd_tz
${condition_str}
${conditionStr}
GROUP BY 1, __wd_tz.name
),`;
}
@ -69,22 +67,22 @@ __wd_buckets AS
* the dataBucketsQuery
*/
function allBucketsArrayQuery (ctx) {
var extra_from = ``;
var series_start = ``;
var series_end = ``;
var extraFrom = '';
var seriesStart = '';
var seriesEnd = '';
if (ctx.start === 0) {
extra_from = `, __wd_buckets GROUP BY __wd_tz.name`;
series_start = `min(__wd_buckets.timestamp)`;
extraFrom = ', __wd_buckets GROUP BY __wd_tz.name';
seriesStart = 'min(__wd_buckets.timestamp)';
} else {
series_start = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.start})))`;
seriesStart = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.start})))`;
}
if (ctx.end === 0) {
extra_from = `, __wd_buckets GROUP BY __wd_tz.name`;
series_end = `max(__wd_buckets.timestamp)`;
extraFrom = ', __wd_buckets GROUP BY __wd_tz.name';
seriesEnd = 'max(__wd_buckets.timestamp)';
} else {
series_end = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.end})))`;
seriesEnd = `date_trunc('${ctx.aggregation}', timezone(__wd_tz.name, to_timestamp(${ctx.end})))`;
}
return `
@ -93,10 +91,10 @@ __wd_all_buckets AS
SELECT ARRAY(
SELECT
generate_series(
${series_start},
${series_end},
${seriesStart},
${seriesEnd},
interval '${ctx.interval}') as bin_start
FROM __wd_tz${extra_from}
FROM __wd_tz${extraFrom}
) as bins
)`;
}
@ -148,18 +146,18 @@ const dateIntervalQueryTpl = ctx => `
const MAX_INTERVAL_VALUE = 100;
const DATE_AGGREGATIONS = {
'auto': true,
'second' : true,
'minute': true,
'hour': true,
'day': true,
'week': true,
'month': true,
'quarter': true,
'year': true,
'decade' : true,
'century' : true,
'millennium' : true
auto: true,
second: true,
minute: true,
hour: true,
day: true,
week: true,
month: true,
quarter: true,
year: true,
decade: true,
century: true,
millennium: true
};
/**
@ -219,8 +217,8 @@ ORDER BY bin ASC;
return null;
}
var interval = this._getAggregation(override) === 'quarter' ?
'3 months' : '1 ' + this._getAggregation(override);
var interval = this._getAggregation(override) === 'quarter'
? '3 months' : '1 ' + this._getAggregation(override);
const histogramSql = this._buildQueryTpl({
override: override,
@ -239,7 +237,7 @@ ORDER BY bin ASC;
}
_isValidAggregation (override) {
return DATE_AGGREGATIONS.hasOwnProperty(this._getAggregation(override));
return Object.prototype.hasOwnProperty.call(DATE_AGGREGATIONS, this._getAggregation(override));
}
_getAutomaticAggregation (psql, callback) {

View File

@ -26,7 +26,7 @@ const irqQueryTpl = ctx => `
max(${ctx.column}) AS __cdb_max_val,
min(${ctx.column}) AS __cdb_min_val,
count(1) AS __cdb_total_rows,
${ctx.irq ? ctx.irq : `0`} AS __cdb_iqr
${ctx.irq ? ctx.irq : '0'} AS __cdb_iqr
FROM
(
SELECT *
@ -51,10 +51,6 @@ Numeric histogram:
}
*/
module.exports = class NumericHistogram extends BaseHistogram {
constructor (query, options, queries) {
super(query, options, queries);
}
_buildQuery (psql, override, callback) {
const histogramSql = this._buildQueryTpl({
column: this._columnType === 'date' ? utils.columnCastTpl({ column: this.column }) : this.column,
@ -72,7 +68,6 @@ module.exports = class NumericHistogram extends BaseHistogram {
return callback(null, histogramSql);
}
/**
* ctx: Object with the following values
* ctx.column -- Column for the histogram
@ -85,35 +80,35 @@ module.exports = class NumericHistogram extends BaseHistogram {
* ctx.maxBins - If !full max bins to calculate [Optional]
*/
_buildQueryTpl (ctx) {
var extra_tables = ``;
var extra_queries = ``;
var extra_groupby = ``;
var extra_filter = ``;
var extraTables = '';
var extraQueries = '';
var extraGroupBy = '';
var extraFilter = '';
if (ctx.start < ctx.end) {
extra_filter = `
extraFilter = `
WHERE __ctx_query.${ctx.column} >= ${ctx.start}
AND __ctx_query.${ctx.column} <= ${ctx.end}
`;
} else {
ctx.end = `__cdb_basics.__cdb_max_val`;
ctx.start = `__cdb_basics.__cdb_min_val`;
extra_groupby = `, __cdb_basics.__cdb_max_val, __cdb_basics.__cdb_min_val`;
extra_tables = `, __cdb_basics`;
extra_queries = `WITH ${irqQueryTpl(ctx)}`;
ctx.end = '__cdb_basics.__cdb_max_val';
ctx.start = '__cdb_basics.__cdb_min_val';
extraGroupBy = ', __cdb_basics.__cdb_max_val, __cdb_basics.__cdb_min_val';
extraTables = ', __cdb_basics';
extraQueries = `WITH ${irqQueryTpl(ctx)}`;
}
if (ctx.bins <= 0) {
ctx.bins = `__cdb_basics.__cdb_bins_number`;
ctx.bins = '__cdb_basics.__cdb_bins_number';
ctx.irq = `percentile_disc(0.75) within group (order by ${ctx.column})
- percentile_disc(0.25) within group (order by ${ctx.column})`;
extra_groupby += `, __cdb_basics.__cdb_bins_number`;
extra_tables = `, __cdb_basics`;
extra_queries = `WITH ${irqQueryTpl(ctx)}`;
extraGroupBy += ', __cdb_basics.__cdb_bins_number';
extraTables = ', __cdb_basics';
extraQueries = `WITH ${irqQueryTpl(ctx)}`;
}
return `
${extra_queries}
${extraQueries}
SELECT
(${ctx.end} - ${ctx.start}) / ${ctx.bins}::float AS bin_width,
${ctx.bins} as bins_number,
@ -132,44 +127,44 @@ SELECT
END AS bin
FROM
(
SELECT * FROM (${ctx.query}) __ctx_query${extra_tables} ${extra_filter}
) __cdb_filtered_source_query${extra_tables}
GROUP BY 10${extra_groupby}
SELECT * FROM (${ctx.query}) __ctx_query${extraTables} ${extraFilter}
) __cdb_filtered_source_query${extraTables}
GROUP BY 10${extraGroupBy}
ORDER BY 10;`;
}
_hasOverridenBins (override) {
return override && override.hasOwnProperty('bins');
return override && Object.prototype.hasOwnProperty.call(override, 'bins');
}
_getSummary (result, override) {
const firstRow = result.rows[0] || {};
var total_nulls = 0;
var total_infinities = 0;
var total_nans = 0;
var total_avg = 0;
var total_count = 0;
var totalNulls = 0;
var totalInfinities = 0;
var totalNans = 0;
var totalAvg = 0;
var totalCount = 0;
result.rows.forEach(function (row) {
total_nulls += row.nulls_count;
total_infinities += row.infinities_count;
total_nans += row.nans_count;
total_avg += row.avg * row.freq;
total_count += row.freq;
totalNulls += row.nulls_count;
totalInfinities += row.infinities_count;
totalNans += row.nans_count;
totalAvg += row.avg * row.freq;
totalCount += row.freq;
});
if (total_count !== 0) {
total_avg /= total_count;
if (totalCount !== 0) {
totalAvg /= totalCount;
}
return {
bin_width: firstRow.bin_width,
bins_count: firstRow.bins_number,
bins_start: this._populateBinStart(firstRow, override),
nulls: total_nulls,
infinities: total_infinities,
nans: total_nans,
avg: total_avg
nulls: totalNulls,
infinities: totalInfinities,
nans: totalNans,
avg: totalAvg
};
}
@ -180,7 +175,7 @@ ORDER BY 10;`;
_populateBinStart (firstRow, override = {}) {
let binStart;
if (override.hasOwnProperty('start')) {
if (Object.prototype.hasOwnProperty.call(override, 'start')) {
binStart = this._getBinStart(override);
} else {
binStart = firstRow.min;
@ -188,5 +183,4 @@ ORDER BY 10;`;
return binStart;
}
};

View File

@ -132,9 +132,9 @@ Aggregation.prototype.sql = function(psql, override, callback) {
}
var aggregationSql;
if (!!override.ownFilter) {
if (override.ownFilter) {
aggregationSql = [
"WITH",
'WITH',
[
filteredQueryTpl({
_isFloatColumn: this._isFloatColumn,
@ -173,7 +173,7 @@ Aggregation.prototype.sql = function(psql, override, callback) {
].join('\n');
} else {
aggregationSql = [
"WITH",
'WITH',
[
filteredQueryTpl({
_isFloatColumn: this._isFloatColumn,
@ -232,7 +232,7 @@ Aggregation.prototype._checkOptions = function (options) {
}
const requiredOptions = VALID_OPERATIONS[options.aggregation];
const missingOptions = requiredOptions.filter(requiredOption => !options.hasOwnProperty(requiredOption));
const missingOptions = requiredOptions.filter(requiredOption => !Object.prototype.hasOwnProperty.call(options, requiredOption));
if (missingOptions.length > 0) {
throw new Error(

View File

@ -53,8 +53,8 @@ BaseOverviewsDataview.prototype.zoomLevelForBbox = function(bbox) {
};
BaseOverviewsDataview.prototype.rewrittenQuery = function (query) {
var zoom_level = this.zoomLevelForBbox(this.options.bbox);
return this.queryRewriter.query(query, this.queryRewriteData, { zoom_level: zoom_level });
var zoomLevel = this.zoomLevelForBbox(this.options.bbox);
return this.queryRewriter.query(query, this.queryRewriteData, { zoom_level: zoomLevel });
};
// Default behaviour

View File

@ -29,7 +29,7 @@ var OverviewsDataviewMetaFactory = {
getFactory: function (queryRewriter, queryRewriteData, options) {
return new OverviewsDataviewFactory(queryRewriter, queryRewriteData, options);
},
}
};
module.exports = OverviewsDataviewMetaFactory;

View File

@ -18,7 +18,7 @@ const VALID_OPERATIONS = {
function dataviewResult (ctx) {
switch (ctx.operation) {
case 'count':
return `sum(_feature_count)`;
return 'sum(_feature_count)';
case 'sum':
return `sum(${utils.handleFloatColumn(ctx)}*_feature_count)`;
case 'avg':
@ -31,8 +31,8 @@ const formulaQueryTpl = ctx =>
`SELECT
${dataviewResult(ctx)} AS result,
${utils.countNULLs(ctx)} AS nulls_count
${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ``}
${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ``}
${ctx.isFloatColumn ? `,${utils.countInfinites(ctx)} AS infinities_count,` : ''}
${ctx.isFloatColumn ? `${utils.countNaNs(ctx)} AS nans_count` : ''}
FROM (${ctx.query}) __cdb_formula`;
function Formula (query, options, queryRewriter, queryRewriteData, params, queries) {

View File

@ -157,7 +157,6 @@ Histogram.prototype.sql = function(psql, override, callback) {
override = {};
}
if (this._columnType === null) {
this.getColumnType(psql, this.column, this.queries.no_filters, function (err, type) {
// assume numeric, will fail later
@ -259,7 +258,7 @@ Histogram.prototype._buildQuery = function (override) {
}
var histogramSql = [
"WITH",
'WITH',
cteSql.join(',\n'),
histogramQueryTpl({
_isFloatColumn: this._columnType === 'float',

View File

@ -7,7 +7,7 @@ var filters = {
function createFilter (filterDefinition) {
var filterType = filterDefinition.type.toLowerCase();
if (!filters.hasOwnProperty(filterType)) {
if (!Object.prototype.hasOwnProperty.call(filters, filterType)) {
throw new Error('Unknown filter type: ' + filterType);
}
return new filters[filterType](filterDefinition.column, filterDefinition.params);
@ -23,7 +23,7 @@ AnalysisFilters.prototype.sql = function(rawSql) {
return Object.keys(filters)
.filter(function (filterName) {
return applyFilters.hasOwnProperty(filterName) ? applyFilters[filterName] : true;
return Object.prototype.hasOwnProperty.call(applyFilters, filterName) ? applyFilters[filterName] : true;
})
.map(function (filterName) {
var filterDefinition = filters[filterName];

View File

@ -9,7 +9,7 @@ var filterQueryTpl = dot.template([
'FROM ({{=it._sql}}) _analysis_category_filter',
'WHERE {{=it._filters}}'
].join('\n'));
var escapeStringTpl = dot.template('$escape_{{=it._i}}${{=it._value}}$escape_{{=it._i}}$');
var escapeStringTpl = dot.template('$escape_{{=it._i}}${{=it._value}}$escape_{{=it._i}}$'); // eslint-disable-line no-template-curly-in-string
var inConditionTpl = dot.template('{{=it._column}} IN ({{=it._values}})');
var notInConditionTpl = dot.template('{{=it._column}} NOT IN ({{=it._values}})');

View File

@ -106,7 +106,6 @@ module.exports.adjustLongitudeRange = adjustLongitudeRange;
module.exports.LATITUDE_MAX_VALUE = LATITUDE_MAX_VALUE;
module.exports.LONGITUDE_MAX_VALUE = LONGITUDE_UPPER_BOUND;
BBox.prototype.sql = function (rawSql) {
var bboxSql = filterQueryTpl({
_sql: rawSql,

View File

@ -27,7 +27,6 @@ module.exports = class AggregationMapConfigAdapter {
return callback(err);
}
if (!this._shouldAdapt(mapConfig, params)) {
return callback(null, requestMapConfig);
}
@ -101,8 +100,7 @@ module.exports = class AggregationMapConfigAdapter {
try {
aggregationSql = mapConfig.getAggregatedQuery(index);
}
catch (error) {
} catch (error) {
return reject(error);
}

View File

@ -45,7 +45,7 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi
var dataview = dataviews[dataviewName];
if (dataview) {
var sourceId = dataview.source.id;
if (!bySourceId.hasOwnProperty(sourceId)) {
if (!Object.prototype.hasOwnProperty.call(bySourceId, sourceId)) {
bySourceId[sourceId] = {};
}
@ -180,8 +180,8 @@ AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfi
};
var SKIP_COLUMNS = {
'the_geom': true,
'the_geom_webmercator': true
the_geom: true,
the_geom_webmercator: true
};
function skipColumns (columnNames) {
@ -233,7 +233,7 @@ function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) {
}
function shouldAdaptLayers (requestMapConfig) {
return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId) ||
return (Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId)) ||
(Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0) ||
requestMapConfig.dataviews;
}
@ -279,7 +279,7 @@ function getLayerDataviews(layer, dataviews) {
function getDataviewsColumns (dataviews) {
return Object.keys(dataviews.reduce(function (columnsDict, dataview) {
getDataviewColumns(dataview).forEach(function (columnName) {
if (!!columnName) {
if (columnName) {
columnsDict[columnName] = true;
}
});
@ -291,7 +291,7 @@ function getDataviewColumns(dataview) {
var columns = [];
var options = dataview.options;
['column', 'aggregationColumn'].forEach(function (opt) {
if (options.hasOwnProperty(opt) && !!options[opt]) {
if (Object.prototype.hasOwnProperty.call(options, opt) && !!options[opt]) {
columns.push(options[opt]);
}
});
@ -316,7 +316,7 @@ function getDataviewsErrors(dataviews) {
Object.keys(dataviews).forEach(function (dataviewName) {
var dataview = dataviews[dataviewName];
if (!dataview.hasOwnProperty('source') || !dataview.source.id) {
if (!Object.prototype.hasOwnProperty.call(dataview, 'source') || !dataview.source.id) {
errors.push(new Error('Dataview "' + dataviewName + '" is missing `source.id` attribute'));
}
@ -333,7 +333,7 @@ function getMissingDataviewsSourceIds(dataviews, sourceId2Node) {
Object.keys(dataviews).forEach(function (dataviewName) {
var dataview = dataviews[dataviewName];
var dataviewSourceId = getDataviewSourceId(dataview);
if (!sourceId2Node.hasOwnProperty(dataviewSourceId)) {
if (!Object.prototype.hasOwnProperty.call(sourceId2Node, dataviewSourceId)) {
missingDataviewsSourceIds.push(new AnalysisError('Node with `source.id="' + dataviewSourceId + '"`' +
' not found in analyses for dataview "' + dataviewName + '"'));
}

View File

@ -5,7 +5,6 @@ function DataviewsWidgetsMapConfigAdapter() {
module.exports = DataviewsWidgetsMapConfigAdapter;
DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) {
if (!shouldAdapt(requestMapConfig)) {
return callback(null, requestMapConfig);
@ -64,7 +63,7 @@ DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, request
layersFilters.forEach(function (layerFilters) {
Object.keys(layerFilters).forEach(function (filterName) {
if (!filters.dataviews.hasOwnProperty(filterName)) {
if (!Object.prototype.hasOwnProperty.call(filters.dataviews, filterName)) {
filters.dataviews[filterName] = layerFilters[filterName];
}
});

View File

@ -24,7 +24,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
function adaptLayer (layer, done) {
if (isNamedTypeLayer(layer)) {
if (!layer.options.name) {
return done(new Error('Missing Named Map `name` in layer options'));
}
@ -63,7 +62,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
return done(unauthorizedError);
}
});
} else {
return done(null, {
datasource: false,
@ -83,11 +81,10 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
return callback(new Error('Missing layers array from layergroup config'));
}
var layers = [],
currentLayerIndex = 0;
var layers = [];
var currentLayerIndex = 0;
layersResults.forEach(function (layersResult) {
layersResult.layers.forEach(function (layer) {
layers.push(layer);
if (layersResult.datasource) {
@ -102,7 +99,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
}
currentLayerIndex++;
});
});
requestMapConfig.layers = layers;
@ -111,7 +107,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
return callback(null, requestMapConfig);
}
var dbAuth = {};
if (_.some(layers, isNamedTypeLayer)) {
@ -128,7 +123,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC
context.datasource = datasourceBuilder.build();
return callback(null, requestMapConfig);
}
};
function isNamedTypeLayer (layer) {

View File

@ -115,12 +115,12 @@ function getUnfilteredQuery (analysesResults, layer) {
if (node) {
var filters = node.getFilters();
var filters_disabler = Object.keys(filters).reduce(function (disabler, filter_id) {
disabler[filter_id] = false;
var filtersDisabler = Object.keys(filters).reduce(function (disabler, filterId) {
disabler[filterId] = false;
return disabler;
}, {});
return node.getQuery(filters_disabler);
return node.getQuery(filtersDisabler);
}
}
}

View File

@ -5,7 +5,6 @@ function SqlWrapMapConfigAdapter() {
module.exports = SqlWrapMapConfigAdapter;
SqlWrapMapConfigAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) {
if (requestMapConfig && Array.isArray(requestMapConfig.layers)) {
requestMapConfig.layers = requestMapConfig.layers.map(function (layer) {

View File

@ -61,5 +61,4 @@ class VectorMapConfigAdapter {
}
}
module.exports = VectorMapConfigAdapter;

View File

@ -68,9 +68,9 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider {
if (this.config) {
try {
templateParams = Object.prototype.toString.call(this.config) === '[object String]' ?
JSON.parse(this.config) :
this.config;
templateParams = Object.prototype.toString.call(this.config) === '[object String]'
? JSON.parse(this.config)
: this.config;
} catch (e) {
const err = new Error('malformed config parameter, should be a valid JSON');
return callback(err);
@ -135,7 +135,7 @@ module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider {
},
batch: {
username: this.user,
apiKey: apiKey
apiKey
}
};

View File

@ -80,7 +80,7 @@ ResourceLocator.prototype.urlForTemplate = function (tpl, username, cdnDomain, r
if (templated) {
return {
urlTemplate: tpl({
cdn_url: (cdnDomain.hasOwnProperty('urlTemplate') ? cdnDomain.urlTemplate : cdnDomain),
cdn_url: (Object.prototype.hasOwnProperty.call(cdnDomain, 'urlTemplate') ? cdnDomain.urlTemplate : cdnDomain),
user: username,
port: this.environment.port,
resource: resource.getPath()
@ -156,10 +156,6 @@ class Resource {
}
class TileResource extends Resource {
constructor (resourcePath) {
super(resourcePath);
}
getDomain (domain, subdomains) {
if (!subdomains) {
return domain;
@ -179,10 +175,6 @@ class TileResource extends Resource {
}
class TemplateResource extends Resource {
constructor (resourcePath) {
super(resourcePath);
}
getDomain (domain, subdomains) {
return {
urlTemplate: domain,
@ -214,7 +206,7 @@ function getCdnUrls(serverMetadata, username, resource) {
}
return {
http: httpUrls,
https: httpsUrls,
https: httpsUrls
};
}
return null;
@ -236,7 +228,7 @@ function getCdnDomain(serverMetadata, resource) {
}
return {
http: httpDomain,
https: httpsDomain,
https: httpsDomain
};
}
return null;

View File

@ -8,7 +8,6 @@ function HealthCheck(disableFile) {
module.exports = HealthCheck;
HealthCheck.prototype.check = function (callback) {
fs.readFile(this.disableFile, function handleDisabledFile (err, data) {
var disabledError = null;

View File

@ -2,9 +2,8 @@
var HealthCheck = require('./monitoring/health-check');
var WELCOME_MSG = "This is the CartoDB Maps API, " +
"see the documentation at http://docs.cartodb.com/cartodb-platform/maps-api.html";
var WELCOME_MSG = 'This is the CartoDB Maps API, ' +
'see the documentation at http://docs.cartodb.com/cartodb-platform/maps-api.html';
function ServerInfoController (versions) {
this.healthConfig = global.environment.health || {};
@ -29,7 +28,7 @@ ServerInfoController.prototype.version = function(req, res) {
};
ServerInfoController.prototype.health = function (req, res) {
if (!!this.healthConfig.enabled) {
if (this.healthConfig.enabled) {
var startTime = Date.now();
this.healthCheck.check(function (err) {
var ok = !err;
@ -42,7 +41,6 @@ ServerInfoController.prototype.health = function(req, res) {
response.err = err.message;
}
res.status(ok ? 200 : 503).send(response);
});
} else {
res.status(200).send({ enabled: false, ok: true });

View File

@ -70,13 +70,13 @@ module.exports = {
api: [{
paths: [
'/api/v1',
'/user/:user/api/v1',
'/user/:user/api/v1'
],
// Base url for the Detached Maps API
// "/api/v1/map" is the new API,
map: [{
paths: [
'/map',
'/map'
]
}],
// Base url for the Templated Maps API

View File

@ -14,7 +14,7 @@ const ServerInfoController = require('./server-info-controller');
const StatsClient = require('./stats/client');
module.exports = function createServer (serverOptions) {
if (!serverOptions.hasOwnProperty('routes')) {
if (!Object.prototype.hasOwnProperty.call(serverOptions, 'routes')) {
throw new Error('Must initialise server with "routes" as base paths configuration');
}

View File

@ -18,29 +18,27 @@ module.exports = {
* @returns {StatsD|Object}
*/
getInstance: function (config) {
if (!this.instance) {
var instance;
if (config) {
instance = new StatsD(config);
instance.last_error = { msg: '', count: 0 };
instance.socket.on('error', function (err) {
var last_err = instance.last_error;
var last_msg = last_err.msg;
var this_msg = '' + err;
if (this_msg !== last_msg) {
debug("statsd client socket error: " + err);
var lastErr = instance.last_error;
var lastMsg = lastErr.msg;
var thisMsg = '' + err;
if (thisMsg !== lastMsg) {
debug('statsd client socket error: ' + err);
instance.last_error.count = 1;
instance.last_error.msg = this_msg;
instance.last_error.msg = thisMsg;
} else {
++last_err.count;
if (!last_err.interval) {
++lastErr.count;
if (!lastErr.interval) {
instance.last_error.interval = setInterval(function () {
var count = instance.last_error.count;
if (count > 1) {
debug("last statsd client socket error repeated " + count + " times");
debug('last statsd client socket error repeated ' + count + ' times');
instance.last_error.count = 1;
clearInterval(instance.last_error.interval);
instance.last_error.interval = null;

View File

@ -9,7 +9,7 @@ function ProfilerProxy(opts) {
this.profile = !!opts.profile;
this.profiler = null;
if (!!opts.profile) {
if (opts.profile) {
this.profiler = new Profiler({ statsd_client: opts.statsd_client });
}
}
@ -45,11 +45,11 @@ ProfilerProxy.prototype.sendStats = function() {
};
ProfilerProxy.prototype.toString = function () {
return this.profile ? this.profiler.toString() : "";
return this.profile ? this.profiler.toString() : '';
};
ProfilerProxy.prototype.toJSONString = function () {
return this.profile ? this.profiler.toJSONString() : "{}";
return this.profile ? this.profiler.toJSONString() : '{}';
};
module.exports = ProfilerProxy;

View File

@ -25,7 +25,7 @@ function wrapDates(originalQuery, fields) {
* @param {object} field
*/
function _isDateType (field) {
return DATE_OIDS.hasOwnProperty(field.dataTypeID);
return Object.prototype.hasOwnProperty.call(DATE_OIDS, field.dataTypeID);
}
/**

View File

@ -4,7 +4,7 @@ module.exports = function jsonReplacerFactory () {
// Fix: https://github.com/CartoDB/Windshaft-cartodb/issues/705
// See: http://expressjs.com/en/4x/api.html#app.set
return function jsonReplacer (key, value) {
if (value !== value) {
if (value !== value) { // eslint-disable-line no-self-compare
return 'NaN';
}

View File

@ -188,5 +188,4 @@ module.exports = class LayergroupMetadata {
});
}
}
};

View File

@ -11,20 +11,19 @@ var FILTER_MIN_ROWS = 65536;
// Maximum filtered fraction to not apply overviews
var FILTER_MAX_FRACTION = 0.2;
function apply_filters_to_query(query, filters, bbox_filter) {
function applyFiltersToQuery (query, filters, bboxFilter) {
if (filters && !_.isEmpty(filters)) {
var analysisFilter = new AnalysisFilter(filters);
query = analysisFilter.sql(query);
}
if ( bbox_filter ) {
var bboxFilter = new BBoxFilter(bbox_filter.options, bbox_filter.params);
query = bboxFilter.sql(query);
if (bboxFilter) {
var filter = new BBoxFilter(bboxFilter.options, bboxFilter.params);
query = filter.sql(query);
}
return query;
}
function OverviewsQueryRewriter (options) {
this.options = options;
}
@ -37,72 +36,72 @@ module.exports = OverviewsQueryRewriter;
// Build UNION expression to replace table, using overviews metadata
// overviews metadata: { 1: 'table_ov1', ... }
// assume table and overview names include schema if necessary and are quoted as needed
function overviews_view_for_table(table, overviews_metadata, indent) {
var condition, i, len, ov_table, overview_layers, selects, z_hi, z_lo;
var parsed_table = TableNameParser.parse(table);
function overviewsViewForTable (table, overviewsMetadata, indent) {
var condition, i, len, ovTable, overviewLayers, selects, zHi, zLo;
var parsedTable = TableNameParser.parse(table);
var sorted_overviews = []; // [[1, 'table_ov1'], ...]
var sortedOverviews = []; // [[1, 'table_ov1'], ...]
indent = indent || ' ';
for (var z in overviews_metadata) {
if (overviews_metadata.hasOwnProperty(z) && z !== 'schema') {
sorted_overviews.push([z, overviews_metadata[z].table]);
for (var z in overviewsMetadata) {
if (Object.prototype.hasOwnProperty.call(overviewsMetadata, z) && z !== 'schema') {
sortedOverviews.push([z, overviewsMetadata[z].table]);
}
}
sorted_overviews.sort(function(a, b){ return a[0]-b[0]; });
sortedOverviews.sort(function (a, b) { return a[0] - b[0]; });
overview_layers = [];
z_lo = null;
for (i = 0, len = sorted_overviews.length; i < len; i++) {
z_hi = parseInt(sorted_overviews[i][0]);
ov_table = sorted_overviews[i][1];
overview_layers.push([overview_z_condition(z_lo, z_hi), ov_table]);
z_lo = z_hi;
overviewLayers = [];
zLo = null;
for (i = 0, len = sortedOverviews.length; i < len; i++) {
zHi = parseInt(sortedOverviews[i][0]);
ovTable = sortedOverviews[i][1];
overviewLayers.push([overviewZCondition(zLo, zHi), ovTable]);
zLo = zHi;
}
overview_layers.push(["_vovw_z > " + z_lo, table]);
overviewLayers.push(['_vovw_z > ' + zLo, table]);
selects = overview_layers.map(function(condition_table) {
condition = condition_table[0];
ov_table = TableNameParser.parse(condition_table[1]);
ov_table.schema = ov_table.schema || parsed_table.schema;
var ov_identifier = TableNameParser.table_identifier(ov_table);
return indent + "SELECT * FROM " + ov_identifier + ", _vovw_scale WHERE " + condition;
selects = overviewLayers.map(function (conditionTable) {
condition = conditionTable[0];
ovTable = TableNameParser.parse(conditionTable[1]);
ovTable.schema = ovTable.schema || parsedTable.schema;
var ovIdentifier = TableNameParser.table_identifier(ovTable);
return indent + 'SELECT * FROM ' + ovIdentifier + ', _vovw_scale WHERE ' + condition;
});
return selects.join("\n"+indent+"UNION ALL\n");
return selects.join('\n' + indent + 'UNION ALL\n');
}
function overview_z_condition(z_lo, z_hi) {
if (z_lo !== null) {
if (z_lo === z_hi - 1) {
return "_vovw_z = " + z_hi;
function overviewZCondition (zLo, zHi) {
if (zLo !== null) {
if (zLo === zHi - 1) {
return '_vovw_z = ' + zHi;
} else {
return "_vovw_z > " + z_lo + " AND _vovw_z <= " + z_hi;
return '_vovw_z > ' + zLo + ' AND _vovw_z <= ' + zHi;
}
} else {
if (z_hi === 0) {
return "_vovw_z = " + z_hi;
if (zHi === 0) {
return '_vovw_z = ' + zHi;
} else {
return "_vovw_z <= " + z_hi;
return '_vovw_z <= ' + zHi;
}
}
}
// name to be used for the view of the table using overviews
function overviews_view_name(table) {
var parsed_table = TableNameParser.parse(table);
parsed_table.table = '_vovw_' + parsed_table.table;
parsed_table.schema = null;
return TableNameParser.table_identifier(parsed_table);
function overviewsViewName (table) {
var parsedTable = TableNameParser.parse(table);
parsedTable.table = '_vovw_' + parsedTable.table;
parsedTable.schema = null;
return TableNameParser.table_identifier(parsedTable);
}
// replace a table name in a query by anoter name
function replace_table_in_query(sql, old_table_name, replacement) {
var old_table = TableNameParser.parse(old_table_name);
var old_table_ident = TableNameParser.table_identifier(old_table);
function replaceTableInQuery (sql, oldTableName, replacement) {
var oldTable = TableNameParser.parse(oldTableName);
var oldTableIdent = TableNameParser.table_identifier(oldTable);
// regular expression prefix (beginning) to match a table name
function pattern_prefix(schema, identifier) {
function patternPrefix (schema, identifier) {
if (schema) {
// to match a table name including schema prefix
// name should not be part of another name, so we require
@ -119,12 +118,12 @@ function replace_table_in_query(sql, old_table_name, replacement) {
// since the pattern matches the first character of the table
// it must be put back in the replacement text
replacement = '$01' + replacement;
return '([^\.a-z0-9_]|^)';
return '([^\.a-z0-9_]|^)'; // eslint-disable-line no-useless-escape
}
}
// regular expression suffix (ending) to match a table name
function pattern_suffix(identifier) {
function patternSuffix (identifier) {
// name shouldn't be the prefix of a longer name
if (identifier[identifier.length - 1] !== '"') {
return '\\b';
@ -134,24 +133,23 @@ function replace_table_in_query(sql, old_table_name, replacement) {
}
// regular expression to match a table name
var regexp = pattern_prefix(old_table.schema, old_table_ident) +
old_table_ident +
pattern_suffix(old_table_ident);
var regexp = patternPrefix(oldTable.schema, oldTableIdent) +
oldTableIdent +
patternSuffix(oldTableIdent);
// replace all occurrences of the table pattern
return sql.replace(new RegExp(regexp, 'g'), replacement);
}
function replace_table_in_query_with_schema(query, table, schema, replacement) {
function replaceTableInQueryWithSchema (query, table, schema, replacement) {
if (replacement) {
query = replace_table_in_query(query, table, replacement);
var parsed_table = TableNameParser.parse(table);
if (!parsed_table.schema && schema) {
query = replaceTableInQuery(query, table, replacement);
var parsedTable = TableNameParser.parse(table);
if (!parsedTable.schema && schema) {
// replace also the qualified table name, if the table wasn't qualified
parsed_table.schema = schema;
table = TableNameParser.table_identifier(parsed_table);
query = replace_table_in_query(query, table, replacement);
parsedTable.schema = schema;
table = TableNameParser.table_identifier(parsedTable);
query = replaceTableInQuery(query, table, replacement);
}
}
return query;
@ -159,20 +157,20 @@ function replace_table_in_query_with_schema(query, table, schema, replacement) {
// Build query to use overviews for a variant zoom level (given by a expression to
// be evaluated by the database server)
function overviews_query_with_zoom_expression(query, overviews, zoom_level_expression) {
var replaced_query = query;
var sql = "WITH\n _vovw_scale AS ( SELECT " + zoom_level_expression + " AS _vovw_z )";
function overviewsQueryWithZoomExpression (query, overviews, zoomLevelExpression) {
var replacedQuery = query;
var sql = 'WITH\n _vovw_scale AS ( SELECT ' + zoomLevelExpression + ' AS _vovw_z )';
var replacement;
_.each(Object.keys(overviews), function (table) {
var table_overviews = overviews[table];
var table_view = overviews_view_name(table);
var schema = table_overviews.schema;
replacement = "(\n" + overviews_view_for_table(table, table_overviews) + "\n ) AS " + table_view;
replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement);
var tableOverviews = overviews[table];
var tableView = overviewsViewName(table);
var schema = tableOverviews.schema;
replacement = '(\n' + overviewsViewForTable(table, tableOverviews) + '\n ) AS ' + tableView;
replacedQuery = replaceTableInQueryWithSchema(replacedQuery, table, schema, replacement);
});
if ( replaced_query !== query ) {
sql += "\n";
sql += replaced_query;
if (replacedQuery !== query) {
sql += '\n';
sql += replacedQuery;
} else {
sql = query;
}
@ -180,27 +178,27 @@ function overviews_query_with_zoom_expression(query, overviews, zoom_level_expre
}
// Build query to use overviews for a specific zoom level value
function overviews_query_with_definite_zoom(query, overviews, zoom_level) {
var replaced_query = query;
function overviewsQueryWithDefiniteZoom (query, overviews, zoomLevel) {
var replacedQuery = query;
var replacement;
_.each(Object.keys(overviews), function (table) {
var table_overviews = overviews[table];
var schema = table_overviews.schema;
replacement = overview_table_for_zoom_level(table_overviews, zoom_level);
replaced_query = replace_table_in_query_with_schema(replaced_query, table, schema, replacement);
var tableOverviews = overviews[table];
var schema = tableOverviews.schema;
replacement = overviewTableForZoomLevel(tableOverviews, zoomLevel);
replacedQuery = replaceTableInQueryWithSchema(replacedQuery, table, schema, replacement);
});
return replaced_query;
return replacedQuery;
}
// Find a suitable overview table for a specific zoom_level
function overview_table_for_zoom_level(table_overviews, zoom_level) {
var overview_table;
if ( table_overviews ) {
overview_table = table_overviews[zoom_level];
if ( !overview_table ) {
_.every(Object.keys(table_overviews).sort(function(x,y){ return x-y; }), function(overview_zoom) {
if ( +overview_zoom > +zoom_level ) {
overview_table = table_overviews[overview_zoom];
// Find a suitable overview table for a specific zoomLevel
function overviewTableForZoomLevel (tableOverviews, zoomLevel) {
var overviewTable;
if (tableOverviews) {
overviewTable = tableOverviews[zoomLevel];
if (!overviewTable) {
_.every(Object.keys(tableOverviews).sort(function (x, y) { return x - y; }), function (overviewZoom) {
if (+overviewZoom > +zoomLevel) {
overviewTable = tableOverviews[overviewZoom];
return false;
} else {
return true;
@ -208,10 +206,10 @@ function overview_table_for_zoom_level(table_overviews, zoom_level) {
});
}
}
if ( overview_table ) {
overview_table = overview_table.table;
if (overviewTable) {
overviewTable = overviewTable.table;
}
return overview_table;
return overviewTable;
}
// Transform an SQL query so that it uses overviews.
@ -228,88 +226,87 @@ function overview_table_for_zoom_level(table_overviews, zoom_level) {
// {
// overviews: // overview tables metadata
// { 'table-name': {1: { table: 'overview-table-1' }, ... }, ... },
// zoom_level: ..., // optional zoom level
// zoomLevel: ..., // optional zoom level
// filters: ..., // filters definition
// unfiltered_query: ..., // query without the filters
// bbox_filter: ... // bounding-box filter
// unfilteredQuery: ..., // query without the filters
// bboxFilter: ... // bounding-box filter
// }
OverviewsQueryRewriter.prototype.query = function (query, data, options) {
options = options || {};
data = data || {};
var overviews = data.overviews;
var unfiltered_query = data.unfiltered_query;
var unfilteredQuery = data.unfiltered_query;
var filters = data.filters;
var bbox_filter = data.bbox_filter;
var bboxFilter = data.bbox_filter;
if ( !unfiltered_query ) {
unfiltered_query = query;
if (!unfilteredQuery) {
unfilteredQuery = query;
}
if ( !should_use_overviews(unfiltered_query, data) ) {
if (!shouldUseOverviews(unfilteredQuery, data)) {
return query;
}
var rewritten_query;
var rewrittenQuery;
var zoom_level_expression = this.options.zoom_level;
var zoom_level = zoom_level_for_query(unfiltered_query, zoom_level_expression, options);
var zoomLevelExpression = this.options.zoom_level;
var zoomLevel = zoomLevelForQuery(unfilteredQuery, zoomLevelExpression, options);
rewritten_query = overviews_query(unfiltered_query, overviews, zoom_level, zoom_level_expression);
rewrittenQuery = overviewsQuery(unfilteredQuery, overviews, zoomLevel, zoomLevelExpression);
if ( rewritten_query === unfiltered_query ) {
if (rewrittenQuery === unfilteredQuery) {
// could not or didn't need to alter the query
rewritten_query = query;
rewrittenQuery = query;
} else {
rewritten_query = apply_filters_to_query(rewritten_query, filters, bbox_filter);
rewrittenQuery = applyFiltersToQuery(rewrittenQuery, filters, bboxFilter);
}
return rewritten_query;
return rewrittenQuery;
};
function zoom_level_for_query(query, zoom_level_expression, options) {
var zoom_level = null;
function zoomLevelForQuery (query, zoomLevelExpression, options) {
var zoomLevel = null;
if (_.has(options, 'zoom_level')) {
zoom_level = options.zoom_level || '0';
zoomLevel = options.zoom_level || '0';
}
if ( zoom_level === null && !zoom_level_expression ) {
zoom_level = '0';
if (zoomLevel === null && !zoomLevelExpression) {
zoomLevel = '0';
}
return zoom_level;
return zoomLevel;
}
function overviews_query(query, overviews, zoom_level, zoom_level_expression) {
if ( zoom_level || zoom_level === '0' || zoom_level === 0 ) {
return overviews_query_with_definite_zoom(query, overviews, zoom_level);
function overviewsQuery (query, overviews, zoomLevel, zoomLevelExpression) {
if (zoomLevel || zoomLevel === '0' || zoomLevel === 0) {
return overviewsQueryWithDefiniteZoom(query, overviews, zoomLevel);
} else {
return overviews_query_with_zoom_expression(query, overviews, zoom_level_expression);
return overviewsQueryWithZoomExpression(query, overviews, zoomLevelExpression);
}
}
function should_use_overviews(query, data) {
function shouldUseOverviews (query, data) {
data = data || {};
var use_overviews = data.overviews && is_supported_query(query);
if ( use_overviews && data.filters && data.filter_stats ) {
var filtered_rows = data.filter_stats.filtered_rows;
var unfiltered_rows = data.filter_stats.unfiltered_rows;
if ( unfiltered_rows && (filtered_rows || filtered_rows === 0) ) {
use_overviews = filtered_rows >= FILTER_MIN_ROWS ||
(filtered_rows/unfiltered_rows) > FILTER_MAX_FRACTION;
var useOverviews = data.overviews && isSupportedQuery(query);
if (useOverviews && data.filters && data.filter_stats) {
var filteredRows = data.filter_stats.filtered_rows;
var unfilteredRows = data.filter_stats.unfiltered_rows;
if (unfilteredRows && (filteredRows || filteredRows === 0)) {
useOverviews = filteredRows >= FILTER_MIN_ROWS ||
(filteredRows / unfilteredRows) > FILTER_MAX_FRACTION;
}
}
return use_overviews;
return useOverviews;
}
function is_supported_query(sql) {
var basic_query =
/\s*SELECT\s+[\*a-z0-9_,\s]+?\s+FROM\s+((\"[^"]+\"|[a-z0-9_]+)\.)?(\"[^"]+\"|[a-z0-9_]+)\s*;?\s*/i;
var unwrapped_query = new RegExp("^"+basic_query.source+"$", 'i');
function isSupportedQuery (sql) {
var basicQuery = /\s*SELECT\s+[\*a-z0-9_,\s]+?\s+FROM\s+((\"[^"]+\"|[a-z0-9_]+)\.)?(\"[^"]+\"|[a-z0-9_]+)\s*;?\s*/i; // eslint-disable-line no-useless-escape
var unwrappedQuery = new RegExp('^' + basicQuery.source + '$', 'i');
// queries for named maps are wrapped like this:
var wrapped_query = new RegExp(
"^\\s*SELECT\\s+\\*\\s+FROM\\s+\\(" +
basic_query.source +
"\\)\\s+AS\\s+wrapped_query\\s+WHERE\\s+\\d+=1\\s*$",
var wrappedQuery = new RegExp(
'^\\s*SELECT\\s+\\*\\s+FROM\\s+\\(' +
basicQuery.source +
'\\)\\s+AS\\s+wrapped_query\\s+WHERE\\s+\\d+=1\\s*$',
'i'
);
return !!(sql.match(unwrapped_query) || sql.match(wrapped_query));
return !!(sql.match(unwrappedQuery) || sql.match(wrappedQuery));
}

View File

@ -43,8 +43,8 @@ module.exports.columnCastTpl = function columnCastTpl(ctx) {
/** 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)`
return `${!ctx.isFloatColumn ? `${ctx.column}`
: `nullif(nullif(nullif(${ctx.column}, 'infinity'::float), '-infinity'::float), 'NaN'::float)`
}`;
};
@ -55,15 +55,15 @@ module.exports.countNULLs = function countNULLs(ctx) {
/** Count only infinity (positive and negative) appearances */
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)`
return `${!ctx.isFloatColumn ? '0'
: `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) {
return `${!ctx.isFloatColumn ? '0' :
`sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)`
return `${!ctx.isFloatColumn ? '0'
: `sum(CASE WHEN (${ctx.column} = 'NaN'::float) THEN 1 ELSE 0 END)`
}`;
};

View File

@ -1,86 +1,84 @@
'use strict';
// Quote an PostgreSQL identifier if ncecessary
function quote_identifier_if_needed(txt) {
function quoteIdentifierIfNeeded (txt) {
if (txt && !txt.match(/^[a-z_][a-z_0-9]*$/)) {
return '"' + txt.replace(/\"/g, '""') + '"';
return '"' + txt.replace(/"/g, '""') + '"';
} else {
return txt;
}
}
// Parse PostgreSQL table name (possibly quoted and with optional schema).+
// Returns { schema: 'schema_name', table: 'table_name' }
function parse_table_name(table) {
function split_as_quoted_parts(table_name) {
// Returns { schema: 'schema_name', table: 'tableName' }
function parseTableName (table) {
function splitAsQuotedParts (tableName) {
// parse table into 'parts' that may be quoted, each part
// in the parts array being an object { part: 'text', quoted: false/true }
var parts = [];
var splitted = table_name.split(/\"/);
var splitted = tableName.split(/"/);
for (var i = 0; i < splitted.length; i++) {
if (splitted[i] === '') {
if (parts.length > 0 && i < splitted.length - 1) {
i++;
parts[parts.length - 1].part += '"' + splitted[i];
}
}
else {
var is_quoted = (i > 0 && splitted[i-1] === '') ||
} else {
var isQuoted = (i > 0 && splitted[i - 1] === '') ||
(i < splitted.length - 1 && splitted[i + 1] === '');
parts.push({ part: splitted[i], quoted: is_quoted });
parts.push({ part: splitted[i], quoted: isQuoted });
}
}
return parts;
}
var parts = split_as_quoted_parts(table);
var parts = splitAsQuotedParts(table);
function split_single_part(part) {
var schema_part = null;
var table_part = null;
function splitSinglePart (part) {
var schemaPart = null;
var tablePart = null;
if (part.quoted) {
table_part = part.part;
tablePart = part.part;
} else {
var parts = part.part.split('.');
if (parts.length === 1) {
schema_part = null;
table_part = parts[0];
schemaPart = null;
tablePart = parts[0];
} else if (parts.length === 2) {
schema_part = parts[0];
table_part = parts[1];
schemaPart = parts[0];
tablePart = parts[1];
} // else invalid table name
}
return {
schema: schema_part,
table: table_part
schema: schemaPart,
table: tablePart
};
}
function split_two_parts(part1, part2) {
var schema_part = null;
var table_part = null;
function splitTwoParts (part1, part2) {
var schemaPart = null;
var tablePart = null;
if (part1.quoted && !part2.quoted) {
if (part2.part[0] === '.') {
schema_part = part1.part;
table_part = part2.part.slice(1);
schemaPart = part1.part;
tablePart = part2.part.slice(1);
} // else invalid table name (missing dot)
} else if (!part1.quoted && part2.quoted) {
if (part1.part[part1.part.length - 1] === '.') {
schema_part = part1.part.slice(0, -1);
table_part = part2.part;
schemaPart = part1.part.slice(0, -1);
tablePart = part2.part;
} // else invalid table name (missing dot)
} // else invalid table name (missing dot)
return {
schema: schema_part,
table: table_part
schema: schemaPart,
table: tablePart
};
}
if (parts.length === 1) {
return split_single_part(parts[0]);
return splitSinglePart(parts[0]);
} else if (parts.length === 2) {
return split_two_parts(parts[0], parts[1]);
return splitTwoParts(parts[0], parts[1]);
} else if (parts.length === 3 && parts[1].part === '.') {
return {
schema: parts[0].part,
@ -89,12 +87,12 @@ function parse_table_name(table) {
} // else invalid table name
}
function table_identifier(parsed_name) {
if ( parsed_name && parsed_name.table ) {
if ( parsed_name.schema ) {
return quote_identifier_if_needed(parsed_name.schema) + '.' + quote_identifier_if_needed(parsed_name.table);
function tableIdentifier (parsedName) {
if (parsedName && parsedName.table) {
if (parsedName.schema) {
return quoteIdentifierIfNeeded(parsedName.schema) + '.' + quoteIdentifierIfNeeded(parsedName.table);
} else {
return quote_identifier_if_needed(parsed_name.table);
return quoteIdentifierIfNeeded(parsedName.table);
}
} else {
return null;
@ -102,7 +100,7 @@ function table_identifier(parsed_name) {
}
module.exports = {
parse: parse_table_name,
quote: quote_identifier_if_needed,
table_identifier: table_identifier
parse: parseTableName,
quote: quoteIdentifierIfNeeded,
table_identifier: tableIdentifier
};

1383
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -53,8 +53,13 @@
"yargs": "11.1.0"
},
"devDependencies": {
"eslint": "^6.5.1",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"istanbul": "0.4.5",
"jshint": "2.9.7",
"mocha": "5.2.0",
"moment": "2.22.1",
"nock": "9.2.6",
@ -63,7 +68,8 @@
"strftime": "0.10.0"
},
"scripts": {
"lint": "jshint lib test app.js",
"lint:fix": "eslint --fix app.js \"lib/**/*.js\" \"test/**/*.js\"",
"lint": "eslint app.js \"lib/**/*.js\" \"test/**/*.js\"",
"preinstall": "make pre-install",
"test": "make test-all",
"update-internal-deps": "rm -rf node_modules && npm install",

View File

@ -6,7 +6,7 @@ if (process.argv.length !== 3) {
var LZMA = require('lzma').LZMA;
var lzmaWorker = new LZMA();
var lzmaInput = decodeURIComponent(process.argv[2]);
var lzmaBuffer = new Buffer(lzmaInput, 'base64')
var lzmaBuffer = Buffer.from(lzmaInput, 'base64')
.toString('binary')
.split('')
.map(function(c) {

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,6 @@ require('../../support/test-helper');
var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');
describe('analyses controller', function () {
const mapConfig = {
version: '1.5.0',
@ -52,7 +51,7 @@ describe('analyses controller', function () {
});
it('should support jsonp responses', function (done) {
this.testClient.getAnalysesCatalog({ jsonp: 'jsonp_test' }, (err, result) => {
this.testClient.getAnalysesCatalog({ jsonp: 'jsonpTest' }, (err, result) => {
if (err) {
return done(err);
}
@ -60,14 +59,13 @@ describe('analyses controller', function () {
assert.ok(result);
let didRunJsonCallback = false;
// jshint ignore:start
function jsonp_test(body) {
/* eslint-disable no-unused-vars, no-eval */
function jsonpTest (body) {
assert.ok(Array.isArray(body.catalog));
didRunJsonCallback = true;
}
eval(result);
// jshint ignore:end
/* eslint-enable */
assert.ok(didRunJsonCallback);
@ -84,7 +82,7 @@ describe('analyses controller', function () {
return done(err);
}
assert.deepEqual(result.errors[0], 'Unauthorized');
assert.deepStrictEqual(result.errors[0], 'Unauthorized');
this.testClient.apiKey = apiKey;
done();
});
@ -106,11 +104,10 @@ describe('analyses controller', function () {
result.catalog
.filter(analysis => analysis.node_id === '0a215e1f3405381cf0ea6b3b0deb6fdcfdc2fcaa')
.forEach(analysis => assert.equal(analysis.type, 'buffer'));
.forEach(analysis => assert.strictEqual(analysis.type, 'buffer'));
this.testClient.drain(done);
});
});
});
});

View File

@ -6,7 +6,6 @@ const assert = require('../../support/assert');
const TestClient = require('../../support/test-client');
describe('analysis-filters-params', () => {
const CARTOCSS = `#layer {
marker-fill-opacity: 1;
marker-line-color: white;
@ -23,13 +22,13 @@ describe('analysis-filters-params', () => {
version: '1.6.0',
layers: [
{
"type": "cartodb",
"options": {
"source": {
"id": "a1"
type: 'cartodb',
options: {
source: {
id: 'a1'
},
"cartocss": CARTOCSS,
"cartocss_version": "2.3.0"
cartocss: CARTOCSS,
cartocss_version: '2.3.0'
}
}
],
@ -55,10 +54,10 @@ describe('analysis-filters-params', () => {
},
analyses: [
{
"id": "a1",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'a1',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]
@ -77,7 +76,6 @@ describe('analysis-filters-params', () => {
}
};
it('should get a filtered histogram dataview with all filters', function (done) {
const testClient = new TestClient(mapConfig, 1234);
const testParams = Object.assign({}, params, {
@ -87,8 +85,8 @@ describe('analysis-filters-params', () => {
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 6);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_count, 6);
testClient.drain(done);
});
@ -103,8 +101,8 @@ describe('analysis-filters-params', () => {
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 24);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_count, 24);
testClient.drain(done);
});
@ -119,8 +117,8 @@ describe('analysis-filters-params', () => {
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_count, 48);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_count, 48);
testClient.drain(done);
});
@ -144,7 +142,8 @@ describe('analysis-filters-params', () => {
});
testClient.getDataview('pop_max_histogram', testParams, (err, dataview) => {
assert.deepEqual(dataview, expectedError);
assert.ifError(err);
assert.deepStrictEqual(dataview, expectedError);
testClient.drain(done);
});

View File

@ -6,7 +6,6 @@ const assert = require('../../support/assert');
const TestClient = require('../../support/test-client');
describe('analysis-layers-dataviews', () => {
const CARTOCSS = `#layer {
marker-fill-opacity: 1;
marker-line-color: white;
@ -23,13 +22,13 @@ describe('analysis-layers-dataviews', () => {
version: '1.6.0',
layers: [
{
"type": "cartodb",
"options": {
"source": {
"id": "a1"
type: 'cartodb',
options: {
source: {
id: 'a1'
},
"cartocss": CARTOCSS,
"cartocss_version": "2.3.0"
cartocss: CARTOCSS,
cartocss_version: '2.3.0'
}
}
],
@ -46,10 +45,10 @@ describe('analysis-layers-dataviews', () => {
},
analyses: [
{
"id": "a1",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'a1',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]
@ -61,7 +60,7 @@ describe('analysis-layers-dataviews', () => {
const params = {
filters: {
analyses: {
'a1': [
a1: [
{
type: 'range',
column: 'pop_max',
@ -77,8 +76,8 @@ describe('analysis-layers-dataviews', () => {
testClient.getDataview('pop_max_histogram', params, (err, dataview) => {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 2008000);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_start, 2008000);
testClient.drain(done);
});

View File

@ -7,34 +7,32 @@ var TestClient = require('../../support/test-client');
var dot = require('dot');
describe('analysis-layers-dataviews', function () {
var multitypeStyleTemplate = dot.template([
"#points['mapnik::geometry_type'=1] {",
" marker-fill-opacity: {{=it._opacity}};",
" marker-line-color: #FFF;",
" marker-line-width: 0.5;",
" marker-line-opacity: {{=it._opacity}};",
" marker-placement: point;",
" marker-type: ellipse;",
" marker-width: 8;",
" marker-fill: {{=it._color}};",
" marker-allow-overlap: true;",
"}",
' marker-fill-opacity: {{=it._opacity}};',
' marker-line-color: #FFF;',
' marker-line-width: 0.5;',
' marker-line-opacity: {{=it._opacity}};',
' marker-placement: point;',
' marker-type: ellipse;',
' marker-width: 8;',
' marker-fill: {{=it._color}};',
' marker-allow-overlap: true;',
'}',
"#lines['mapnik::geometry_type'=2] {",
" line-color: {{=it._color}};",
" line-width: 2;",
" line-opacity: {{=it._opacity}};",
"}",
' line-color: {{=it._color}};',
' line-width: 2;',
' line-opacity: {{=it._opacity}};',
'}',
"#polygons['mapnik::geometry_type'=3] {",
" polygon-fill: {{=it._color}};",
" polygon-opacity: {{=it._opacity}};",
" line-color: #FFF;",
" line-width: 0.5;",
" line-opacity: {{=it._opacity}};",
"}"
' polygon-fill: {{=it._color}};',
' polygon-opacity: {{=it._opacity}};',
' line-color: #FFF;',
' line-width: 0.5;',
' line-opacity: {{=it._opacity}};',
'}'
].join('\n'));
function cartocss (color, opacity) {
return multitypeStyleTemplate({
_color: color || '#F11810',
@ -56,13 +54,13 @@ describe('analysis-layers-dataviews', function() {
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
type: 'cartodb',
options: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
}
],
@ -79,10 +77,10 @@ describe('analysis-layers-dataviews', function() {
},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]
@ -94,8 +92,8 @@ describe('analysis-layers-dataviews', function() {
testClient.getDataview('pop_max_histogram', function (err, dataview) {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 0);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_start, 0);
testClient.drain(done);
});
@ -118,8 +116,8 @@ describe('analysis-layers-dataviews', function() {
testClient.getDataview('pop_max_histogram', params, function (err, dataview) {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 2008000);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_start, 2008000);
testClient.drain(done);
});
@ -142,8 +140,8 @@ describe('analysis-layers-dataviews', function() {
testClient.getDataview('pop_max_histogram', params, function (err, dataview) {
assert.ok(!err, err);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 0);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_start, 0);
testClient.drain(done);
});

View File

@ -7,36 +7,34 @@ var TestClient = require('../../support/test-client');
var dot = require('dot');
describe('analysis-layers', function () {
var IMAGE_TOLERANCE_PER_MIL = 20;
var multitypeStyleTemplate = dot.template([
"#points['mapnik::geometry_type'=1] {",
" marker-fill-opacity: {{=it._opacity}};",
" marker-line-color: #FFF;",
" marker-line-width: 0.5;",
" marker-line-opacity: {{=it._opacity}};",
" marker-placement: point;",
" marker-type: ellipse;",
" marker-width: 8;",
" marker-fill: {{=it._color}};",
" marker-allow-overlap: true;",
"}",
' marker-fill-opacity: {{=it._opacity}};',
' marker-line-color: #FFF;',
' marker-line-width: 0.5;',
' marker-line-opacity: {{=it._opacity}};',
' marker-placement: point;',
' marker-type: ellipse;',
' marker-width: 8;',
' marker-fill: {{=it._color}};',
' marker-allow-overlap: true;',
'}',
"#lines['mapnik::geometry_type'=2] {",
" line-color: {{=it._color}};",
" line-width: 2;",
" line-opacity: {{=it._opacity}};",
"}",
' line-color: {{=it._color}};',
' line-width: 2;',
' line-opacity: {{=it._opacity}};',
'}',
"#polygons['mapnik::geometry_type'=3] {",
" polygon-fill: {{=it._color}};",
" polygon-opacity: {{=it._opacity}};",
" line-color: #FFF;",
" line-width: 0.5;",
" line-opacity: {{=it._opacity}};",
"}"
' polygon-fill: {{=it._color}};',
' polygon-opacity: {{=it._opacity}};',
' line-color: #FFF;',
' line-width: 0.5;',
' line-opacity: {{=it._opacity}};',
'}'
].join('\n'));
function cartocss (color, opacity) {
return multitypeStyleTemplate({
_color: color || '#F11810',
@ -64,23 +62,23 @@ describe('analysis-layers', function() {
mapConfig: mapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
type: 'cartodb',
options: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]
@ -94,30 +92,30 @@ describe('analysis-layers', function() {
mapConfig: mapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 50000
radius: 50000
}
}
]
@ -127,7 +125,6 @@ describe('analysis-layers', function() {
useCases.forEach(function (useCase) {
it('should implement use case: "' + useCase.desc + '"', function (done) {
var testClient = new TestClient(useCase.mapConfig, 1234);
var tile = useCase.tile || TILE_ANALYSIS_TABLES;
@ -157,7 +154,7 @@ describe('analysis-layers', function() {
testClient.getLayergroup(function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.metadata.layers.length, 1);
assert.strictEqual(layergroupResult.metadata.layers.length, 1);
testClient.drain(done);
});
@ -176,13 +173,11 @@ describe('analysis-layers', function() {
}
};
testClient.getLayergroup({ response: PERMISSION_DENIED_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.deepEqual(
assert.deepStrictEqual(
layergroupResult.errors,
["Analysis requires authentication with API key: permission denied."]
['Analysis requires authentication with API key: permission denied.']
);
testClient.drain(done);
@ -203,15 +198,15 @@ describe('analysis-layers', function() {
'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult)
);
var analyses = layergroupResult.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']);
assert.deepStrictEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']);
nodesIds.forEach(function (nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'query'), 'Missing "status" attribute in node');
});
testClient.drain(done);
@ -225,29 +220,29 @@ describe('analysis-layers', function() {
mapConfig: mapConfig(
[
{
"type": "cartodb",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
type: 'cartodb',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
},
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
type: 'cartodb',
options: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
type: 'cartodb',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
}
],
@ -273,10 +268,10 @@ describe('analysis-layers', function() {
},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]
@ -293,16 +288,16 @@ describe('analysis-layers', function() {
'Missing "analyses" array metadata from: ' + JSON.stringify(layergroupResult)
);
var analyses = layergroupResult.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745']);
assert.deepStrictEqual(nodesIds, ['2570e105-7b37-40d2-bdf4-1af889598745']);
nodesIds.forEach(function (nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(node.hasOwnProperty('query'), 'Missing "status" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'query'), 'Missing "status" attribute in node');
});
testClient.drain(done);
@ -318,11 +313,11 @@ describe('analysis-layers', function() {
testClient.getNodeStatus('HEAD', function (err, response, nodeStatus) {
assert.ok(!err, err);
assert.equal(nodeStatus.status, 'ready');
assert.strictEqual(nodeStatus.status, 'ready');
var headers = response.headers;
assert.equal(headers['cache-control'], 'public,max-age=5');
assert.strictEqual(headers['cache-control'], 'public,max-age=5');
var lastModified = new Date(headers['last-modified']);
var tenSecondsInMs = 1e5;
@ -336,24 +331,24 @@ describe('analysis-layers', function() {
var testClient = new TestClient(mapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745"
type: 'cartodb',
options: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745'
},
"sql_wrap": "SELECT * FROM (<%= sql %>) __wrapped WHERE adm0cap = 1",
"cartocss": DEFAULT_MULTITYPE_STYLE,
"cartocss_version": "2.3.0"
sql_wrap: 'SELECT * FROM (<%= sql %>) __wrapped WHERE adm0cap = 1',
cartocss: DEFAULT_MULTITYPE_STYLE,
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
]

View File

@ -8,8 +8,6 @@ var dot = require('dot');
var debug = require('debug')('windshaft:cartodb:test');
describe('analysis-layers use cases', function () {
var multitypeStyleTemplate = dot.template(
`#points['mapnik::geometry_type'=1] {
marker-fill-opacity: {{=it._opacity}};
@ -36,7 +34,6 @@ describe('analysis-layers use cases', function () {
}`
);
function cartocss (color, opacity) {
return multitypeStyleTemplate({
_color: color || '#F11810',
@ -267,11 +264,10 @@ describe('analysis-layers use cases', function () {
];
useCases.forEach(function (useCase) {
if (!!useCase.skip) {
if (useCase.skip) {
return debug(JSON.stringify(useCase.mapConfig, null, 4));
}
it(`should implement use case: '${useCase.desc}'`, function (done) {
var testClient = new TestClient(useCase.mapConfig, 1234);
var tile = useCase.tile || TILE_ANALYSIS_TABLES;
@ -281,7 +277,7 @@ describe('analysis-layers use cases', function () {
// image.save('/tmp/tests/' + imageIdx + '---' + useCase.desc.replace(/\s/g, '-') + '.png');
assert.equal(image.width(), 256);
assert.strictEqual(image.width(), 256);
testClient.drain(done);
});

View File

@ -33,30 +33,30 @@ describe('analysis-layers error cases', function() {
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "INVALID-SOURCE-ID"
type: 'cartodb',
options: {
source: {
id: 'INVALID-SOURCE-ID'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 50000
radius: 50000
}
}
]
@ -67,8 +67,8 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(layergroupResult.errors[0], 'Missing analysis node.id="INVALID-SOURCE-ID" for layer=0');
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(layergroupResult.errors[0], 'Missing analysis node.id="INVALID-SOURCE-ID" for layer=0');
testClient.drain(done);
});
@ -78,20 +78,20 @@ describe('analysis-layers error cases', function() {
var mapConfig = createMapConfig(
[
{
"type": "http",
"options": {
"urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png",
"subdomains": "abcd"
type: 'http',
options: {
urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png',
subdomains: 'abcd'
}
},
{
"type": "cartodb",
"options": {
"source": {
"id": "ID-FOR-NONEXISTENT-ANALYSIS"
type: 'cartodb',
options: {
source: {
id: 'ID-FOR-NONEXISTENT-ANALYSIS'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
]
@ -102,8 +102,8 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'Missing analysis node.id="ID-FOR-NONEXISTENT-ANALYSIS" for layer=1'
);
@ -116,18 +116,18 @@ describe('analysis-layers error cases', function() {
var mapConfig = createMapConfig(
[
{
"type": "http",
"options": {
"urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png",
"subdomains": "abcd"
type: 'http',
options: {
urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png',
subdomains: 'abcd'
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from populated_places_simple_reduced",
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
type: 'cartodb',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
],
@ -149,8 +149,8 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(layergroupResult.errors[0], 'Node with `source.id="ID-FOR-NONEXISTENT-ANALYSIS"`' +
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(layergroupResult.errors[0], 'Node with `source.id="ID-FOR-NONEXISTENT-ANALYSIS"`' +
' not found in analyses for dataview "pop_max_histogram"');
testClient.drain(done);
@ -161,30 +161,30 @@ describe('analysis-layers error cases', function() {
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "HEAD",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: 'HEAD',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 50000
radius: 50000
}
}
]
@ -195,50 +195,49 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: AUTH_ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'Analysis requires authentication with API key: permission denied.'
);
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
assert.equal(
assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis');
assert.strictEqual(
layergroupResult.errors_with_context[0].message,
'Analysis requires authentication with API key: permission denied.'
);
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
testClient.drain(done);
});
});
it('camshaft: should return error: Missing required param "radius"; with context', function (done) {
var mapConfig = createMapConfig(
[
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
],
{},
[
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "HEAD2",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: 'HEAD2',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
}
}
@ -251,16 +250,16 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'Missing required param "radius"'
);
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
assert.equal(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"');
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis');
assert.strictEqual(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
testClient.drain(done);
});
@ -268,30 +267,30 @@ describe('analysis-layers error cases', function() {
it('should return missing param error of outer node indicating the node_id and context', function (done) {
var mapConfig = createMapConfig([{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}], {}, [{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "HEAD2",
"type": "buffer",
"params": {
"source": {
"id": "HEAD3",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: 'HEAD2',
type: 'buffer',
params: {
source: {
id: 'HEAD3',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 10
radius: 10
}
}
}
@ -303,17 +302,17 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'Missing required param "radius"'
);
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
assert.equal(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"');
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis');
assert.strictEqual(layergroupResult.errors_with_context[0].message, 'Missing required param "radius"');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD');
testClient.drain(done);
});
@ -321,33 +320,33 @@ describe('analysis-layers error cases', function() {
it('should return invalid param type error of inner node indicating the node_id and context', function (done) {
var mapConfig = createMapConfig([{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}], {}, [{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "HEAD2",
"type": "buffer",
"params": {
"source": {
"id": "HEAD3",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: 'HEAD2',
type: 'buffer',
params: {
source: {
id: 'HEAD3',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 'invalid_radius'
radius: 'invalid_radius'
}
},
"radius": 10
radius: 10
}
}]);
@ -356,20 +355,20 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'Invalid type for param "radius", expects "number" type, got `"invalid_radius"`'
);
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
assert.equal(
assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis');
assert.strictEqual(
layergroupResult.errors_with_context[0].message,
'Invalid type for param "radius", expects "number" type, got `"invalid_radius"`'
);
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD2');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD2');
testClient.drain(done);
});
@ -377,41 +376,41 @@ describe('analysis-layers error cases', function() {
it('should return "function does not exist" indicating the node_id and context', function (done) {
var mapConfig = createMapConfig([{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#polygons { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#polygons { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}], {}, [{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "HEAD2",
"type": "buffer",
"params": {
"source": {
"id": "HEAD3",
"type": 'deprecated-sql-function',
"params": {
"id": "HEAD4",
"function_name": 'DEP_EXT_does_not_exist_fn',
"primary_source": {
"type": 'source',
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: 'HEAD2',
type: 'buffer',
params: {
source: {
id: 'HEAD3',
type: 'deprecated-sql-function',
params: {
id: 'HEAD4',
function_name: 'DEP_EXT_does_not_exist_fn',
primary_source: {
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"function_args": ['wadus']
function_args: ['wadus']
}
},
"radius": 10
radius: 10
}
},
"radius": 10
radius: 10
}
}]);
@ -420,25 +419,22 @@ describe('analysis-layers error cases', function() {
testClient.getLayergroup({ response: ERROR_RESPONSE }, function (err, layergroupResult) {
assert.ok(!err, err);
assert.equal(layergroupResult.errors.length, 1);
assert.equal(
assert.strictEqual(layergroupResult.errors.length, 1);
assert.strictEqual(
layergroupResult.errors[0],
'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist'
);
assert.equal(layergroupResult.errors_with_context[0].type, 'analysis');
assert.equal(
assert.strictEqual(layergroupResult.errors_with_context[0].type, 'analysis');
assert.strictEqual(
layergroupResult.errors_with_context[0].message,
'function dep_ext_does_not_exist_fn(unknown, unknown, unknown, text[], unknown) does not exist'
);
assert.equal(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.equal(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.equal(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD3');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.id, 'HEAD');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.type, 'buffer');
assert.strictEqual(layergroupResult.errors_with_context[0].analysis.node_id, 'HEAD3');
testClient.drain(done);
});
});
});

View File

@ -17,7 +17,6 @@ describe('named-maps analysis', function() {
server = new CartodbWindshaft(serverOptions);
});
var IMAGE_TOLERANCE_PER_MIL = 20;
var username = 'localhost';
@ -30,13 +29,13 @@ describe('named-maps analysis', function() {
version: '1.5.0',
layers: [
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
type: 'cartodb',
options: {
source: {
id: 'HEAD'
},
"cartocss": '#buffer { polygon-fill: red; }',
"cartocss_version": "2.3.0"
cartocss: '#buffer { polygon-fill: red; }',
cartocss_version: '2.3.0'
}
}
],
@ -53,17 +52,17 @@ describe('named-maps analysis', function() {
},
analyses: [
{
"id": "HEAD",
"type": "buffer",
"params": {
"source": {
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
"type": "source",
"params": {
"query": "select * from populated_places_simple_reduced"
id: 'HEAD',
type: 'buffer',
params: {
source: {
id: '2570e105-7b37-40d2-bdf4-1af889598745',
type: 'source',
params: {
query: 'select * from populated_places_simple_reduced'
}
},
"radius": 50000
radius: 50000
}
}
]
@ -86,7 +85,7 @@ describe('named-maps analysis', function() {
status: 200
},
function (res, err) {
assert.deepEqual(JSON.parse(res.body), { template_id: widgetsTemplateName });
assert.deepStrictEqual(JSON.parse(res.body), { template_id: widgetsTemplateName });
return done(err);
}
);
@ -137,7 +136,7 @@ describe('named-maps analysis', function() {
assert.ifError(err);
layergroup = JSON.parse(res.body);
assert.ok(layergroup.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from: " + res.body);
assert.ok(Object.prototype.hasOwnProperty.call(layergroup, 'layergroupid'), "Missing 'layergroupid' from: " + res.body);
layergroupid = layergroup.layergroupid;
assert.ok(
@ -145,15 +144,15 @@ describe('named-maps analysis', function() {
'Missing "analyses" array metadata from: ' + res.body
);
var analyses = layergroup.metadata.analyses;
assert.equal(analyses.length, 1, 'Invalid number of analyses in metadata');
assert.strictEqual(analyses.length, 1, 'Invalid number of analyses in metadata');
var nodes = analyses[0].nodes;
var nodesIds = Object.keys(nodes);
assert.deepEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']);
assert.deepStrictEqual(nodesIds, ['HEAD', '2570e105-7b37-40d2-bdf4-1af889598745']);
nodesIds.forEach(function (nodeId) {
var node = nodes[nodeId];
assert.ok(node.hasOwnProperty('url'), 'Missing "url" attribute in node');
assert.ok(node.hasOwnProperty('status'), 'Missing "status" attribute in node');
assert.ok(!node.hasOwnProperty('query'), 'Unexpected "query" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'url'), 'Missing "url" attribute in node');
assert.ok(Object.prototype.hasOwnProperty.call(node, 'status'), 'Missing "status" attribute in node');
assert.ok(!Object.prototype.hasOwnProperty.call(node, 'query'), 'Unexpected "query" attribute in node');
});
keysToDelete['map_cfg|' + LayergroupToken.parse(layergroup.layergroupid).token] = 0;
@ -162,7 +161,6 @@ describe('named-maps analysis', function() {
return done();
}
);
});
afterEach(function (done) {
@ -196,7 +194,6 @@ describe('named-maps analysis', function() {
assert.ok(!err, err);
done();
});
}
);
});
@ -223,8 +220,8 @@ describe('named-maps analysis', function() {
}
var dataview = JSON.parse(res.body);
assert.equal(dataview.type, 'histogram');
assert.equal(dataview.bins_start, 0);
assert.strictEqual(dataview.type, 'histogram');
assert.strictEqual(dataview.bins_start, 0);
done();
}
@ -258,7 +255,6 @@ describe('named-maps analysis', function() {
assert.ok(!err, err);
done();
});
}
);
});
@ -303,22 +299,20 @@ describe('named-maps analysis', function() {
},
function (res, err) {
assert.ifError(err);
assert.deepEqual(
assert.deepStrictEqual(
JSON.parse(res.body),
{
errors:['Unsupported image format \"gif\"'],
errors: ['Unsupported image format "gif"'],
errors_with_context: [{
type: 'unknown',
message: 'Unsupported image format \"gif\"'
message: 'Unsupported image format "gif"'
}]
}
);
done();
}
);
});
});
describe('auto-instantiation', function () {
@ -333,5 +327,4 @@ describe('named-maps analysis', function() {
});
});
});
});

View File

@ -8,81 +8,81 @@ var TestClient = require('../../support/test-client');
describe('analysis-layers regressions', function () {
it('should return a complete list of nodes from analysis', function (done) {
var mapConfig = {
"version": "1.5.0",
"layers": [
version: '1.5.0',
layers: [
{
"type": "cartodb",
"options": {
"cartocss": TestClient.CARTOCSS.POINTS,
"cartocss_version": "2.1.1",
"interactivity": [],
"source": {
"id": "a4"
type: 'cartodb',
options: {
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.1.1',
interactivity: [],
source: {
id: 'a4'
}
}
},
{
"type": "cartodb",
"options": {
"cartocss": TestClient.CARTOCSS.POINTS,
"cartocss_version": "2.1.0",
"interactivity": [],
"source": {
"id": "b1"
type: 'cartodb',
options: {
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.1.0',
interactivity: [],
source: {
id: 'b1'
}
}
}
],
"dataviews": {
"74493a30-4679-4b72-a60c-b6f808b57c98": {
"type": "histogram",
"source": {
"id": "b0"
dataviews: {
'74493a30-4679-4b72-a60c-b6f808b57c98': {
type: 'histogram',
source: {
id: 'b0'
},
"options": {
"column": "customer_value",
"bins": 10
options: {
column: 'customer_value',
bins: 10
}
}
},
"analyses": [
analyses: [
{
"id": "a4",
"type": "point-in-polygon",
"params": {
"polygons_source": {
"id": "a3",
"type": "buffer",
"params": {
"source": {
"id": "a2",
"type": "centroid",
"params": {
"source": {
"id": "b1",
"type": "kmeans",
"params": {
"source": {
"id": "b0",
"type": "source",
"params": {
"query": "SELECT * FROM populated_places_simple_reduced"
id: 'a4',
type: 'point-in-polygon',
params: {
polygons_source: {
id: 'a3',
type: 'buffer',
params: {
source: {
id: 'a2',
type: 'centroid',
params: {
source: {
id: 'b1',
type: 'kmeans',
params: {
source: {
id: 'b0',
type: 'source',
params: {
query: 'SELECT * FROM populated_places_simple_reduced'
}
},
"clusters": 5
clusters: 5
}
},
"category_column": "cluster_no"
category_column: 'cluster_no'
}
},
"radius": 200000
radius: 200000
}
},
"points_source": {
"id": "customer_home_locations",
"type": "source",
"params": {
"query": "SELECT * FROM populated_places_simple_reduced"
points_source: {
id: 'customer_home_locations',
type: 'source',
params: {
query: 'SELECT * FROM populated_places_simple_reduced'
}
}
}
@ -99,19 +99,18 @@ describe('analysis-layers regressions', function() {
assert.ok(layergroupResult.metadata);
var analyses = layergroupResult.metadata.analyses;
assert.ok(analyses);
assert.equal(analyses.length, 1);
assert.strictEqual(analyses.length, 1);
var expectedIds = ['customer_home_locations', 'b0', 'b1', 'a2', 'a3', 'a4'];
expectedIds.forEach(function (expectedId) {
assert.ok(
analyses[0].nodes.hasOwnProperty(expectedId),
Object.prototype.hasOwnProperty.call(analyses[0].nodes, expectedId),
'Missing "' + expectedId + '" from node list.'
);
});
assert.equal(Object.keys(analyses[0].nodes).length, expectedIds.length, Object.keys(analyses[0].nodes));
assert.strictEqual(Object.keys(analyses[0].nodes).length, expectedIds.length, Object.keys(analyses[0].nodes));
testClient.drain(done);
});
});
});

View File

@ -39,8 +39,8 @@ function createRequest(layergroup, userHost, apiKey) {
}
var layergroupUrl = '/api/v1/map';
var pointSqlMaster = "select * from test_table_private_1";
var pointSqlPublic = "select * from test_table";
var pointSqlMaster = 'select * from test_table_private_1';
var pointSqlPublic = 'select * from test_table';
var keysToDelete;
describe('Basic authorization use cases', function () {
@ -58,7 +58,7 @@ describe('Basic authorization use cases', function () {
testHelper.deleteRedisKeys(keysToDelete, done);
});
it("succeed with master", function (done) {
it('succeed with master', function (done) {
var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }');
assert.response(server,
@ -71,7 +71,7 @@ describe('Basic authorization use cases', function () {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
@ -81,8 +81,7 @@ describe('Basic authorization use cases', function () {
);
});
it("succeed with default - sending default_public", function (done) {
it('succeed with default - sending default_public', function (done) {
var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }');
assert.response(server,
@ -95,7 +94,7 @@ describe('Basic authorization use cases', function () {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
@ -105,7 +104,7 @@ describe('Basic authorization use cases', function () {
);
});
it("fail with non-existent api key", function (done) {
it('fail with non-existent api key', function (done) {
var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }');
assert.response(server,
@ -116,15 +115,15 @@ describe('Basic authorization use cases', function () {
function (res, err) {
assert.ifError(err);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('errors'));
assert.equal(parsed.errors.length, 1);
assert.ok(Object.prototype.hasOwnProperty.call(parsed, 'errors'));
assert.strictEqual(parsed.errors.length, 1);
assert.ok(parsed.errors[0].match(/Unauthorized/));
done();
}
);
});
it("fail with default", function (done) {
it('fail with default', function (done) {
var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }');
assert.response(server,
@ -141,7 +140,7 @@ describe('Basic authorization use cases', function () {
});
describe('No api key provided - fallback to default_public', function () {
it("succeed with default - public dataset", function (done) {
it('succeed with default - public dataset', function (done) {
var layergroup = singleLayergroupConfig(pointSqlPublic, '#layer { marker-fill:red; }');
assert.response(server,
@ -154,7 +153,7 @@ describe('Basic authorization use cases', function () {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
assert.strictEqual(res.headers['x-layergroup-id'], parsed.layergroupid);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsed.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
@ -164,7 +163,7 @@ describe('Basic authorization use cases', function () {
);
});
it("fail with default - private dataset", function (done) {
it('fail with default - private dataset', function (done) {
var layergroup = singleLayergroupConfig(pointSqlMaster, '#layer { marker-fill:red; }');
assert.response(server,

View File

@ -39,7 +39,6 @@ describe('authorization', function() {
});
});
it('should fail getting a named map tile with default apikey token', function (done) {
const apikeyTokenCreate = 'regular1';
const apikeyTokenGet = 'default_public';
@ -69,11 +68,10 @@ describe('authorization', function() {
};
testClientGet.getTile(0, 0, 0, params, function (err, res, body) {
assert.ifError(err);
assert.ok(body.hasOwnProperty('errors'));
assert.equal(body.errors.length, 1);
assert.ok(Object.prototype.hasOwnProperty.call(body, 'errors'));
assert.strictEqual(body.errors.length, 1);
assert.ok(body.errors[0].match(/permission denied/), body.errors[0]);
testClientGet.drain(done);
@ -100,8 +98,8 @@ describe('authorization', function() {
testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) {
assert.ifError(err);
assert.ok(layergroupResult.hasOwnProperty('errors'));
assert.equal(layergroupResult.errors.length, 1);
assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors'));
assert.strictEqual(layergroupResult.errors.length, 1);
assert.ok(layergroupResult.errors[0].match(/permission denied/), layergroupResult.errors[0]);
testClient.drain(done);
@ -152,7 +150,7 @@ describe('authorization', function() {
testClient.getTile(0, 0, 0, function (err, res, tile) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.strictEqual(res.statusCode, 200);
assert.ok(tile instanceof mapnik.Image);
testClient.drain(done);
@ -177,8 +175,8 @@ describe('authorization', function() {
testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) { // TODO 401
assert.ifError(err);
assert.ok(layergroupResult.hasOwnProperty('errors'));
assert.equal(layergroupResult.errors.length, 1);
assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors'));
assert.strictEqual(layergroupResult.errors.length, 1);
assert.ok(layergroupResult.errors[0].match(/permission denied/), layergroupResult.errors[0]);
testClient.drain(done);
@ -204,8 +202,8 @@ describe('authorization', function() {
testClient.getLayergroup({ response: { status: 403 } }, function (err, layergroupResult) {
assert.ifError(err);
assert.ok(layergroupResult.hasOwnProperty('errors'));
assert.equal(layergroupResult.errors.length, 1);
assert.ok(Object.prototype.hasOwnProperty.call(layergroupResult, 'errors'));
assert.strictEqual(layergroupResult.errors.length, 1);
assert.ok(layergroupResult.errors[0].match(/Forbidden/), layergroupResult.errors[0]);
testClient.drain(done);
@ -305,8 +303,8 @@ describe('authorization', function() {
],
analyses: [
{
id: "HEAD1",
type: "buffer",
id: 'HEAD1',
type: 'buffer',
params: {
source: {
id: 'HEAD2',
@ -333,7 +331,6 @@ describe('authorization', function() {
describe('Named maps', function () {
describe('LIST Named maps', function () {
it('should fail while listing named maps with a regular apikey token', function (done) {
const apikeyToken = 'regular1';
@ -342,9 +339,9 @@ describe('authorization', function() {
testClient.getNamedMapList({ response: { status: 403 } }, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(body.errors.length, 1);
assert.strictEqual(body.errors.length, 1);
assert.ok(body.errors[0].match(/Forbidden/), body.errors[0]);
testClient.drain(done);
@ -359,9 +356,9 @@ describe('authorization', function() {
testClient.getNamedMapList({ response: { status: 403 } }, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(body.errors.length, 1);
assert.strictEqual(body.errors.length, 1);
assert.ok(body.errors[0].match(/Forbidden/), body.errors[0]);
testClient.drain(done);
@ -376,9 +373,9 @@ describe('authorization', function() {
testClient.getNamedMapList({ response: { status: 401 } }, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.strictEqual(res.statusCode, 401);
assert.equal(body.errors.length, 1);
assert.strictEqual(body.errors.length, 1);
assert.ok(body.errors[0].match(/Unauthorized/), body.errors[0]);
testClient.drain(done);
@ -393,7 +390,7 @@ describe('authorization', function() {
testClient.getNamedMapList({}, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.strictEqual(res.statusCode, 200);
assert.ok(Array.isArray(body.template_ids));
testClient.drain(done);
@ -418,7 +415,7 @@ describe('authorization', function() {
options: {
sql: 'select * from test_table_localhost_regular1',
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0',
cartocss_version: '2.3.0'
}
}]
}
@ -432,7 +429,7 @@ describe('authorization', function() {
testClient.getTile(0, 0, 0, function (err, res, tile) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.strictEqual(res.statusCode, 200);
assert.ok(tile instanceof mapnik.Image);
testClient.drain(done);
@ -447,9 +444,9 @@ describe('authorization', function() {
testClient.createTemplate({ response: { status: 403 } }, function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClient.drain(done);
@ -464,9 +461,9 @@ describe('authorization', function() {
testClient.createTemplate({ response: { status: 403 } }, function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClient.drain(done);
@ -481,9 +478,9 @@ describe('authorization', function() {
testClient.createTemplate({ response: { status: 401 } }, function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.strictEqual(res.statusCode, 401);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]);
testClient.drain(done);
@ -508,7 +505,7 @@ describe('authorization', function() {
options: {
sql: 'select * from test_table_localhost_regular1',
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0',
cartocss_version: '2.3.0'
}
}]
}
@ -534,7 +531,7 @@ describe('authorization', function() {
function (err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 204);
assert.strictEqual(res.statusCode, 204);
testClientDelete.drain(done);
}
@ -562,9 +559,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientDelete.drain(done);
@ -593,9 +590,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientDelete.drain(done);
@ -624,9 +621,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.strictEqual(res.statusCode, 401);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]);
testClientDelete.drain(done);
@ -653,7 +650,7 @@ describe('authorization', function() {
options: {
sql: 'select * from test_table_localhost_regular1',
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0',
cartocss_version: '2.3.0'
}
}]
}
@ -679,7 +676,7 @@ describe('authorization', function() {
function (err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.strictEqual(res.statusCode, 200);
testClientDelete.drain(done);
}
@ -707,9 +704,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientGet.drain(done);
@ -738,9 +735,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientGet.drain(done);
@ -769,9 +766,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.strictEqual(res.statusCode, 401);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]);
testClientGet.drain(done);
@ -798,7 +795,7 @@ describe('authorization', function() {
options: {
sql: 'select * from test_table_localhost_regular1',
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0',
cartocss_version: '2.3.0'
}
}]
}
@ -825,7 +822,7 @@ describe('authorization', function() {
function (err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.strictEqual(res.statusCode, 200);
testClientDelete.drain(done);
}
@ -854,9 +851,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientDelete.drain(done);
@ -886,9 +883,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 403);
assert.strictEqual(res.statusCode, 403);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Forbidden/), response.errors[0]);
testClientDelete.drain(done);
@ -918,9 +915,9 @@ describe('authorization', function() {
function (err, res, response) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.strictEqual(res.statusCode, 401);
assert.equal(response.errors.length, 1);
assert.strictEqual(response.errors.length, 1);
assert.ok(response.errors[0].match(/Unauthorized/), response.errors[0]);
testClientDelete.drain(done);
@ -928,7 +925,6 @@ describe('authorization', function() {
);
});
});
});
});
});

Some files were not shown because too many files have changed in this diff Show More