snowflake-sdk
Version:
Node.js driver for Snowflake
1,120 lines (968 loc) • 33.8 kB
JavaScript
/*
* Copyright (c) 2015-2024 Snowflake Computing Inc. All rights reserved.
*/
const os = require('os');
const url = require('url');
const Util = require('../util');
const Errors = require('../errors');
const path = require('path');
const ErrorCodes = Errors.codes;
const NativeTypes = require('./result/data_types').NativeTypes;
const GlobalConfig = require('../global_config');
const AuthenticationTypes = require('../authentication/authentication_types');
const levenshtein = require('fastest-levenshtein');
const RowMode = require('./../constants/row_mode');
const DataTypes = require('./result/data_types');
const Logger = require('../logger');
const WAIT_FOR_BROWSER_ACTION_TIMEOUT = 120000;
const DEFAULT_PARAMS =
[
'account',
'application',
'region',
'host',
'accessUrl',
'username',
'password',
'authenticator',
'proxyHost',
'proxyPort',
'serviceName',
'privateKey',
'privateKeyPath',
'privateKeyPass',
'token',
'warehouse',
'database',
'schema',
'role',
'rowMode',
'streamResult',
'fetchAsString',
'clientSessionKeepAlive',
'clientSessionKeepAliveHeartbeatFrequency',
'jsTreatIntegerAsBigInt',
'sessionToken',
'masterToken',
'sessionTokenExpirationTime',
'masterTokenExpirationTime',
'agentClass',
'validateDefaultParameters',
'arrayBindingThreshold',
'gcsUseDownscopedCredential',
'forceStageBindError',
'includeRetryReason',
'disableQueryContextCache',
'retryTimeout',
'clientRequestMFAToken',
'clientStoreTemporaryCredential',
'disableConsoleLogin',
'forceGCPUseDownscopedCredential',
'representNullAsStringNull',
'disableSamlURLCheck',
'credentialCacheDir',
'passcodeInPassword',
'passcode',
];
function consolidateHostAndAccount(options) {
let dotPos = -1;
let realAccount = undefined;
let realRegion = undefined;
const protocol = options.protocol || 'https';
const port = Util.exists(options.port) ? Util.format(':%s', options.port) : '';
if (Util.exists(options.region)) {
Errors.checkArgumentValid(Util.isCorrectSubdomain(options.region), ErrorCodes.ERR_CONN_CREATE_INVALID_REGION_REGEX);
realRegion = options.region;
}
if (Util.exists(options.account)) {
Errors.checkArgumentValid(Util.isString(options.account), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCOUNT);
Errors.checkArgumentValid(Util.isCorrectSubdomain(options.account), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCOUNT_REGEX);
dotPos = options.account.indexOf('.');
realAccount = options.account;
if (dotPos > 0) {
realRegion = realAccount.substring(dotPos + 1);
realAccount = realAccount.substring(0, dotPos);
}
}
if (Util.exists(options.accessUrl)) { //accessUrl is set in configuration
try {
const parsedUrl = url.parse(options.accessUrl);
Errors.checkArgumentValid(Util.exists(parsedUrl.hostname), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCESS_URL);
if (!Util.exists(options.host)) {
options.host = parsedUrl.hostname;
}
const dotPos = parsedUrl.hostname.indexOf('.');
if (dotPos > 0 && !Util.exists(options.account)) {
realAccount = parsedUrl.hostname.substring(0, dotPos);
}
} catch (e) {
Errors.checkArgumentValid(
false, ErrorCodes.ERR_CONN_CREATE_MISSING_ACCOUNT);
}
} else if (Util.exists(options.host)) { //host is set in configuration
options.accessUrl = Util.format('%s://%s%s', protocol, options.host, port);
const dotPos = options.host.indexOf('.');
if (dotPos > 0 && !Util.exists(options.account)) {
realAccount = options.host.substring(0, dotPos);
} else {
realAccount = options.account;
}
} else if (Util.exists(options.account)) { //only account() is set in configuration
if (options.region === 'us-west-2') {
options.region = '';
}
options.host = Util.constructHostname(realRegion, realAccount);
options.accessUrl = Util.format('%s://%s%s', protocol, options.host, port);
}
if (Util.exists(realAccount) && options.accessUrl.includes('global.snowflakecomputing')) {
const dashPos = realAccount.indexOf('-');
if (dashPos > 0) {
// global URL
realAccount = realAccount.substring(0, dashPos);
}
}
options.account = realAccount;
options.region = realRegion;
// check for missing accessURL
Errors.checkArgumentExists(Util.exists(options.account), ErrorCodes.ERR_CONN_CREATE_MISSING_ACCOUNT);
// check for missing account
Errors.checkArgumentExists(Util.exists(options.accessUrl), ErrorCodes.ERR_CONN_CREATE_MISSING_ACCESS_URL);
}
/**
* A Connection configuration object that should be available to all stateful
* objects in the driver.
*
* @param {Object} options
* @param {Boolean} [validateCredentials]
* @param {Boolean} [qaMode]
* @param {Object} [clientInfo]
*
* @constructor
*/
function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) {
// if no value is specified for the validate credentials flag, default to true
if (!Util.exists(validateCredentials)) {
validateCredentials = true;
}
// check for missing options
Errors.checkArgumentExists(Util.exists(options),
ErrorCodes.ERR_CONN_CREATE_MISSING_OPTIONS);
// check for invalid options
Errors.checkArgumentValid(Util.isObject(options),
ErrorCodes.ERR_CONN_CREATE_INVALID_OPTIONS);
// only validate credentials if necessary
if (validateCredentials) {
// username is not required for oauth and external browser authenticators
if (!Util.exists(options.authenticator) ||
(options.authenticator.toUpperCase() !== AuthenticationTypes.OAUTH_AUTHENTICATOR &&
options.authenticator.toUpperCase() !== AuthenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) {
// check for missing username
Errors.checkArgumentExists(Util.exists(options.username),
ErrorCodes.ERR_CONN_CREATE_MISSING_USERNAME);
}
if (Util.exists(options.username)) {
// check for invalid username
Errors.checkArgumentValid(Util.isString(options.username),
ErrorCodes.ERR_CONN_CREATE_INVALID_USERNAME);
}
// password is only required for default authenticator
if (!Util.exists(options.authenticator) ||
options.authenticator === AuthenticationTypes.DEFAULT_AUTHENTICATOR) {
// check for missing password
Errors.checkArgumentExists(Util.exists(options.password),
ErrorCodes.ERR_CONN_CREATE_MISSING_PASSWORD);
// check for invalid password
Errors.checkArgumentValid(Util.isString(options.password),
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSWORD);
}
consolidateHostAndAccount(options);
}
// check for missing accessUrl
Errors.checkArgumentExists(Util.exists(options.accessUrl),
ErrorCodes.ERR_CONN_CREATE_MISSING_ACCESS_URL);
// check for invalid accessUrl
Errors.checkArgumentValid(Util.isString(options.accessUrl),
ErrorCodes.ERR_CONN_CREATE_INVALID_ACCESS_URL);
const proxyHost = options.proxyHost;
const proxyPort = options.proxyPort;
const proxyUser = options.proxyUser;
const proxyPassword = options.proxyPassword;
const proxyProtocol = options.proxyProtocol || 'http';
const noProxy = options.noProxy;
// if we're running in node and some proxy information is specified
let proxy;
if (Util.isNode() && (Util.exists(proxyHost) || Util.exists(proxyPort))) {
// check for missing proxyHost
Errors.checkArgumentExists(Util.exists(proxyHost),
ErrorCodes.ERR_CONN_CREATE_MISSING_PROXY_HOST);
// check for invalid proxyHost
Errors.checkArgumentValid(Util.isString(proxyHost),
ErrorCodes.ERR_CONN_CREATE_INVALID_PROXY_HOST);
// check for missing proxyPort
Errors.checkArgumentExists(Util.exists(proxyPort),
ErrorCodes.ERR_CONN_CREATE_MISSING_PROXY_PORT);
// check for invalid proxyPort
Errors.checkArgumentValid(Util.isNumber(proxyPort),
ErrorCodes.ERR_CONN_CREATE_INVALID_PROXY_PORT);
if (Util.exists(noProxy)) {
// check for invalid noProxy
Errors.checkArgumentValid(Util.isString(noProxy),
ErrorCodes.ERR_CONN_CREATE_INVALID_NO_PROXY);
}
if (Util.exists(proxyUser) || Util.exists(proxyPassword)) {
// check for missing proxyUser
Errors.checkArgumentExists(Util.exists(proxyUser),
ErrorCodes.ERR_CONN_CREATE_MISSING_PROXY_USER);
// check for invalid proxyUser
Errors.checkArgumentValid(Util.isString(proxyUser),
ErrorCodes.ERR_CONN_CREATE_INVALID_PROXY_USER);
// check for missing proxyPassword
Errors.checkArgumentExists(Util.exists(proxyPassword),
ErrorCodes.ERR_CONN_CREATE_MISSING_PROXY_PASS);
// check for invalid proxyPassword
Errors.checkArgumentValid(Util.isString(proxyPassword),
ErrorCodes.ERR_CONN_CREATE_INVALID_PROXY_PASS);
proxy =
{
host: proxyHost,
port: proxyPort,
user: proxyUser,
password: proxyPassword,
protocol: proxyProtocol,
noProxy: noProxy
};
} else {
proxy =
{
host: proxyHost,
port: proxyPort,
protocol: proxyProtocol,
noProxy: noProxy
};
}
}
const serviceName = options.serviceName;
let authenticator = options.authenticator;
// if no value is specified for authenticator, default to Snowflake
if (!Util.exists(authenticator)) {
authenticator = AuthenticationTypes.DEFAULT_AUTHENTICATOR;
} else {
authenticator = authenticator.toUpperCase();
}
let browserActionTimeout = options.browserActionTimeout;
if (Util.exists(options.browserActionTimeout)) {
Errors.checkArgumentValid(Util.number.isPositiveInteger(browserActionTimeout),
ErrorCodes.ERR_CONN_CREATE_INVALID_BROWSER_TIMEOUT);
} else {
browserActionTimeout = WAIT_FOR_BROWSER_ACTION_TIMEOUT;
}
const privateKey = options.privateKey;
if (Util.exists(options.privateKey)) {
Errors.checkArgumentValid((Util.isString(privateKey) && Util.isPrivateKey(privateKey)),
ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY);
}
const privateKeyPath = options.privateKeyPath;
if (Util.exists(options.privateKeyPath)) {
Errors.checkArgumentValid(Util.isString(privateKeyPath),
ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY_PATH);
}
const privateKeyPass = options.privateKeyPass;
if (Util.exists(options.privateKeyPass)) {
Errors.checkArgumentValid(Util.isString(privateKeyPass),
ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY_PASS);
}
const token = options.token;
if (Util.exists(token)) {
Errors.checkArgumentValid(Util.isString(token),
ErrorCodes.ERR_CONN_CREATE_INVALID_OAUTH_TOKEN);
}
const warehouse = options.warehouse;
const database = options.database;
const schema = options.schema;
const role = options.role;
// check for invalid warehouse
if (Util.exists(warehouse)) {
Errors.checkArgumentValid(Util.isString(warehouse),
ErrorCodes.ERR_CONN_CREATE_INVALID_WAREHOUSE);
}
// check for invalid database
if (Util.exists(database)) {
Errors.checkArgumentValid(Util.isString(database),
ErrorCodes.ERR_CONN_CREATE_INVALID_DATABASE);
}
// check for invalid schema
if (Util.exists(schema)) {
Errors.checkArgumentValid(Util.isString(schema),
ErrorCodes.ERR_CONN_CREATE_INVALID_SCHEMA);
}
// check for invalid role
if (Util.exists(role)) {
Errors.checkArgumentValid(Util.isString(role),
ErrorCodes.ERR_CONN_CREATE_INVALID_ROLE);
}
// check for invalid streamResult
const streamResult = options.streamResult;
if (Util.exists(streamResult)) {
Errors.checkArgumentValid(Util.isBoolean(streamResult),
ErrorCodes.ERR_CONN_CREATE_INVALID_STREAM_RESULT);
}
// check for invalid fetchAsString
const fetchAsString = options.fetchAsString;
if (Util.exists(fetchAsString)) {
// check that the value is an array
Errors.checkArgumentValid(Util.isArray(fetchAsString),
ErrorCodes.ERR_CONN_CREATE_INVALID_FETCH_AS_STRING);
// check that all the array elements are valid
const invalidValueIndex = NativeTypes.findInvalidValue(fetchAsString);
Errors.checkArgumentValid(invalidValueIndex === -1,
ErrorCodes.ERR_CONN_CREATE_INVALID_FETCH_AS_STRING_VALUES,
JSON.stringify(fetchAsString[invalidValueIndex]));
}
// Row mode is optional, can be undefined
const rowMode = options.rowMode;
if (Util.exists(rowMode)) {
RowMode.checkRowModeValid(rowMode);
}
// check for invalid clientSessionKeepAlive
const clientSessionKeepAlive = options.clientSessionKeepAlive;
if (Util.exists(clientSessionKeepAlive)) {
Errors.checkArgumentValid(Util.isBoolean(clientSessionKeepAlive),
ErrorCodes.ERR_CONN_CREATE_INVALID_KEEP_ALIVE);
}
// check for invalid clientSessionKeepAliveHeartbeatFrequency
let clientSessionKeepAliveHeartbeatFrequency = options.clientSessionKeepAliveHeartbeatFrequency;
if (Util.exists(clientSessionKeepAliveHeartbeatFrequency)) {
Errors.checkArgumentValid(Util.isNumber(clientSessionKeepAliveHeartbeatFrequency),
ErrorCodes.ERR_CONN_CREATE_INVALID_KEEP_ALIVE_HEARTBEAT_FREQ);
clientSessionKeepAliveHeartbeatFrequency =
Util.validateClientSessionKeepAliveHeartbeatFrequency(clientSessionKeepAliveHeartbeatFrequency, 14400);
}
const jsTreatIntegerAsBigInt = options.jsTreatIntegerAsBigInt;
if (Util.exists(jsTreatIntegerAsBigInt)) {
Errors.checkArgumentValid(Util.isBoolean(jsTreatIntegerAsBigInt),
ErrorCodes.ERR_CONN_CREATE_INVALID_TREAT_INTEGER_AS_BIGINT);
}
const gcsUseDownscopedCredential = options.gcsUseDownscopedCredential;
if (Util.exists(gcsUseDownscopedCredential)) {
Errors.checkArgumentValid(Util.isBoolean(gcsUseDownscopedCredential),
ErrorCodes.ERR_CONN_CREATE_INVALID_GCS_USE_DOWNSCOPED_CREDENTIAL);
}
const clientConfigFile = options.clientConfigFile;
if (Util.exists(clientConfigFile)) {
Errors.checkArgumentValid(Util.isString(clientConfigFile), ErrorCodes.ERR_CONN_CREATE_INVALID_CLIENT_CONFIG_FILE);
}
// remember if we're in qa mode
this._qaMode = qaMode;
// if a client-info argument is specified, validate it
const clientType = 'JavaScript';
let clientName;
let clientVersion;
let clientEnvironment;
if (Util.exists(clientInfo)) {
Errors.assertInternal(Util.isObject(clientInfo));
Errors.assertInternal(Util.isString(clientInfo.version));
Errors.assertInternal(Util.isObject(clientInfo.environment));
clientName = clientInfo.name;
clientVersion = clientInfo.version;
clientEnvironment = clientInfo.environment;
clientEnvironment.OS = os.platform();
clientEnvironment.OS_VERSION = os.release();
clientEnvironment.OCSP_MODE = GlobalConfig.getOcspMode();
}
const clientApplication = options.application;
if (Util.exists(clientApplication)) {
Errors.checkArgumentValid(Util.isString(clientApplication),
ErrorCodes.ERR_CONN_CREATE_INVALID_APPLICATION);
const APPLICATION_PATTERN = new RegExp(String.raw`^[A-Za-z]([A-Za-z0-9.\-_]){1,50}$`,
'gi');
Errors.checkArgumentValid(APPLICATION_PATTERN.test(clientApplication),
ErrorCodes.ERR_CONN_CREATE_INVALID_APPLICATION);
}
let validateDefaultParameters = false;
if (Util.exists(options.validateDefaultParameters)) {
// check for invalid validateDefaultParameters
Errors.checkArgumentValid(Util.isBoolean(options.validateDefaultParameters),
ErrorCodes.ERR_CONN_CREATE_INVALID_VALIDATE_DEFAULT_PARAMETERS);
validateDefaultParameters = options.validateDefaultParameters;
}
let bindThreshold = null;
if (Util.exists(options.arrayBindingThreshold)) {
// check for invalid arrayBindingThreshold
Errors.checkArgumentValid(Util.isNumber(options.arrayBindingThreshold),
ErrorCodes.ERR_CONN_CREATE_INVALID_ARRAY_BINDING_THRESHOLD);
bindThreshold = options.arrayBindingThreshold;
}
let forceStageBindError = null;
if (Util.exists(options.forceStageBindError)) {
// check for invalid forceStageBindError
Errors.checkArgumentValid(Util.isNumber(options.forceStageBindError),
ErrorCodes.ERR_CONN_CREATE_INVALID_FORCE_STAGE_BIND_ERROR);
forceStageBindError = options.forceStageBindError;
}
let disableQueryContextCache = false;
if (Util.exists(options.disableQueryContextCache)) {
Errors.checkArgumentValid(Util.isBoolean(options.disableQueryContextCache),
ErrorCodes.ERR_CONN_CREATE_INVALID_DISABLED_QUERY_CONTEXT_CACHE);
disableQueryContextCache = options.disableQueryContextCache;
}
let retryTimeout = 300;
if (Util.exists(options.retryTimeout)) {
Errors.checkArgumentValid(Util.isNumber(options.retryTimeout),
ErrorCodes.ERR_CONN_CREATE_INVALID_MAX_RETRY_TIMEOUT);
retryTimeout = options.retryTimeout !== 0 ? Math.max(retryTimeout, options.retryTimeout) : 0;
}
let includeRetryReason = true;
if (Util.exists(options.includeRetryReason)) {
Errors.checkArgumentValid(Util.isBoolean(options.includeRetryReason),
ErrorCodes.ERR_CONN_CREATE_INVALID_INCLUDE_RETRY_REASON);
includeRetryReason = options.includeRetryReason;
}
let clientRequestMFAToken = false;
if (Util.exists(options.clientRequestMFAToken)) {
Errors.checkArgumentValid(Util.isBoolean(options.clientRequestMFAToken),
ErrorCodes.ERR_CONN_CREATE_INVALID_CLIENT_REQUEST_MFA_TOKEN);
clientRequestMFAToken = options.clientRequestMFAToken;
}
let disableConsoleLogin = true;
if (Util.exists(options.disableConsoleLogin)) {
Errors.checkArgumentValid(Util.isBoolean(options.disableConsoleLogin),
ErrorCodes.ERR_CONN_CREATE_INVALID_DISABLE_CONSOLE_LOGIN);
disableConsoleLogin = options.disableConsoleLogin;
}
if (Util.exists(options.forceGCPUseDownscopedCredential)) {
Errors.checkArgumentValid(Util.isBoolean(options.forceGCPUseDownscopedCredential),
ErrorCodes.ERR_CONN_CREATE_INVALID_FORCE_GCP_USE_DOWNSCOPED_CREDENTIAL);
process.env.SNOWFLAKE_FORCE_GCP_USE_DOWNSCOPED_CREDENTIAL = options.forceGCPUseDownscopedCredential;
} else {
process.env.SNOWFLAKE_FORCE_GCP_USE_DOWNSCOPED_CREDENTIAL = false;
}
if (Util.exists(options.representNullAsStringNull)) {
Errors.checkArgumentValid(Util.isBoolean(options.representNullAsStringNull),
ErrorCodes.ERR_CONN_CREATE_INVALID_REPRESENT_NULL_AS_STRING_NULL);
DataTypes.setIsRepresentNullAsStringNull(options.representNullAsStringNull);
}
let disableSamlURLCheck = false;
if (Util.exists(options.disableSamlURLCheck)) {
Errors.checkArgumentValid(Util.isBoolean(options.disableSamlURLCheck),
ErrorCodes.ERR_CONN_CREATE_INVALID_DISABLE_SAML_URL_CHECK);
disableSamlURLCheck = options.disableSamlURLCheck;
}
let clientStoreTemporaryCredential = false;
if (Util.exists(options.clientStoreTemporaryCredential)) {
Errors.checkArgumentValid(Util.isBoolean(options.clientStoreTemporaryCredential),
ErrorCodes.ERR_CONN_CREATE_INVALID_CLIENT_STORE_TEMPORARY_CREDENTIAL);
clientStoreTemporaryCredential = options.clientStoreTemporaryCredential;
}
let credentialCacheDir = null;
if (Util.exists(options.credentialCacheDir)) {
const absolutePath = path.resolve(options.credentialCacheDir);
Errors.checkArgumentValid(Util.validatePath(absolutePath),
ErrorCodes.ERR_CONN_CREATE_INVALID_CREDENTIAL_CACHE_DIR);
credentialCacheDir = absolutePath;
}
let passcodeInPassword = false;
if (Util.exists(options.passcodeInPassword)) {
Errors.checkArgumentValid(Util.isBoolean(options.passcodeInPassword),
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSCODE_IN_PASSWORD);
passcodeInPassword = options.passcodeInPassword;
}
let passcode = null;
if (Util.exists(options.passcode)) {
Errors.checkArgumentValid(Util.isString(options.passcode),
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSCODE);
passcode = options.passcode;
}
if (validateDefaultParameters) {
for (const [key] of Object.entries(options)) {
if (!DEFAULT_PARAMS.includes(key)) {
const result = levenshtein.closest(key, DEFAULT_PARAMS);
Logger.getInstance().error(`'${key}' is an unknown connection parameter. Did you mean '${result}'?`);
}
}
}
/**
* Returns an object that contains information about the proxy hostname, port,
* etc. for when http requests are made.
*
* @returns {Object}
*/
this.getProxy = function () {
return proxy;
};
/**
* Returns the warehouse to automatically use once a connection has been
* established.
*
* @returns {String}
*/
this.getWarehouse = function () {
return warehouse;
};
/**
* Returns the database to automatically use once a connection has been
* established.
*
* @returns {String}
*/
this.getDatabase = function () {
return database;
};
/**
* Returns the schema to automatically use once a connection has been
* established.
*
* @returns {String}
*/
this.getSchema = function () {
return schema;
};
/**
* Returns the role to automatically use once a connection has been
* established.
*
* @returns {String}
*/
this.getRole = function () {
return role;
};
/**
* Returns the service name.
*
* @returns {String}
*/
this.getServiceName = function () {
return serviceName;
};
/**
* Returns the authenticator to use for establishing a connection.
*
* @returns {String}
*/
this.getAuthenticator = function () {
return authenticator;
};
/**
* Returns the timeout in millis used for authentication by external browser.
*
* @returns {String}
*/
this.getBrowserActionTimeout = function () {
return browserActionTimeout;
};
/**
* Returns the private key string.
*
* @returns {String}
*/
this.getPrivateKey = function () {
return privateKey;
};
/**
* Returns the private key file location.
*
* @returns {String}
*/
this.getPrivateKeyPath = function () {
return privateKeyPath;
};
/**
* Returns the private key passphrase.
*
* @returns {String}
*/
this.getPrivateKeyPass = function () {
return privateKeyPass;
};
/**
* Returns the OAuth token.
*
* @returns {String}
*/
this.getToken = function () {
return token;
};
/**
* Returns the streamResult flag.
*
* @returns {boolean}
*/
this.getStreamResult = function () {
return streamResult;
};
/**
* Returns the fetchAsString array.
*
* @returns {String[]}
*/
this.getFetchAsString = function () {
return fetchAsString;
};
/**
* Returns the rowMode string value ('array', 'object' or 'object_with_renamed_duplicated_columns'). Could be null or undefined.
*
* @returns {String}
*/
this.getRowMode = function () {
return rowMode;
};
/**
* Returns the client type.
*
* @returns {String}
*/
this.getClientType = function () {
return clientType;
};
/**
* Returns the client name.
*
* @returns {String}
*/
this.getClientName = function () {
return clientName;
};
/**
* Returns the client version.
*
* @returns {String}
*/
this.getClientVersion = function () {
return clientVersion;
};
/**
* Returns the client application.
*
* @returns {String}
*/
this.getClientApplication = function () {
return clientApplication;
};
/**
* Returns a JSON object containing version information for all the various
* components of the runtime, e.g. node, v8, openssl, etc.
*
* @returns {Object}
*/
this.getClientEnvironment = function () {
return clientEnvironment;
};
/**
* Returns the client session keep alive setting.
*
* @returns {String}
*/
this.getClientSessionKeepAlive = function () {
return clientSessionKeepAlive;
};
/**
* Returns the client session keep alive heartbeat frequency setting.
*
* @returns {String}
*/
this.getClientSessionKeepAliveHeartbeatFrequency = function () {
return clientSessionKeepAliveHeartbeatFrequency;
};
/**
* Returns the client treat integer as setting
*
* @returns {String}
*/
this.getJsTreatIntegerAsBigInt = function () {
return jsTreatIntegerAsBigInt;
};
/**
* Returns the setting for the GCS_USE_DOWNSCOPED_CREDENTIAL session parameter
*
* @returns {String}
*/
this.getGcsUseDownscopedCredential = function () {
return gcsUseDownscopedCredential;
};
/**
* Returns the bind threshold
*
* @returns {string}
*/
this.getbindThreshold = function () {
return bindThreshold;
};
/**
* Returns the force stage bind error
*
* @returns {string}
*/
this.getForceStageBindError = function () {
return forceStageBindError;
};
/**
* Returns whether the Retry reason is included or not in the retry url
*
* @returns {Boolean}
*/
this.getIncludeRetryReason = function () {
return includeRetryReason;
};
/**
* Returns whether the Query Context Cache is enabled or not by the configuration
*
* @returns {Boolean}
*/
this.getDisableQueryContextCache = function () {
return disableQueryContextCache;
};
/**
* Returns the client config file
*
* @returns {String}
*/
this.getClientConfigFile = function () {
return clientConfigFile;
};
/**
* Returns the max login timeout
*
* @returns {Number}
*/
this.getRetryTimeout = function () {
return retryTimeout;
};
this.getDisableConsoleLogin = function () {
return disableConsoleLogin;
};
/**
* Returns whether the SAML URL check is enabled or not.
*
* @returns {Boolean}
*/
this.getDisableSamlURLCheck = function () {
return disableSamlURLCheck;
};
this.getCredentialCacheDir = function () {
return credentialCacheDir;
};
this.getClientRequestMFAToken = function () {
return clientRequestMFAToken;
};
/**
* Returns whether the auth token saves on the local machine or not.
*
* @returns {Boolean}
*/
this.getClientStoreTemporaryCredential = function () {
return clientStoreTemporaryCredential;
};
this.getPasscodeInPassword = function () {
return passcodeInPassword;
};
this.getPasscode = function () {
return passcode;
};
// save config options
this.username = options.username;
this.password = options.password;
this.accessUrl = options.accessUrl;
this.region = options.region;
this.account = options.account;
this.host = options.host;
this.sessionToken = options.sessionToken;
this.masterToken = options.masterToken;
this.masterTokenExpirationTime = options.masterTokenExpirationTime;
this.sessionTokenExpirationTime = options.sessionTokenExpirationTime;
this.clientConfigFile = options.clientConfigFile;
// create the parameters array
const parameters = createParameters();
// create a map in which the keys are the parameter names and the values are
// the corresponding parameters
const mapParameters = {};
let index, length, parameter;
for (index = 0, length = parameters.length; index < length; index++) {
parameter = parameters[index];
mapParameters[parameter.name] = parameter;
// initialize the value to the default
parameter.value = parameter.defaultValue;
}
// for each property in the options object that matches a known parameter name
let propertyName, propertyValue;
for (propertyName in options) {
if (Object.prototype.hasOwnProperty.call(options, propertyName) &&
Object.prototype.hasOwnProperty.call(mapParameters, propertyName)) {
// if the parameter matching the property is external and the specified
// value is valid for the parameter, update the parameter value
propertyValue = options[propertyName];
parameter = mapParameters[propertyName];
if (parameter.external && parameter.validate(propertyValue)) {
parameter.value = propertyValue;
}
}
}
// save the parameters map
this._mapParameters = mapParameters;
// custom agent class, test only
this.agentClass = options.agentClass;
}
/**
* Determines if qa-mode is on.
*
* @returns {Boolean}
*/
ConnectionConfig.prototype.isQaMode = function () {
return this._qaMode;
};
/**
* Clears all credential-related information.
*/
ConnectionConfig.prototype.clearCredentials = function () {
// clear the password
this.password = null;
// TODO: clear passcode and other credential-related information as well
};
const PARAM_TIMEOUT = 'timeout';
const PARAM_RESULT_PREFETCH = 'resultPrefetch';
const PARAM_RESULT_STREAM_INTERRUPTS = 'resultStreamInterrupts';
const PARAM_RESULT_CHUNK_CACHE_SIZE = 'resultChunkCacheSize';
const PARAM_RESULT_PROCESSING_BATCH_SIZE = 'resultProcessingBatchSize';
const PARAM_RESULT_PROCESSING_BATCH_DURATION = 'resultProcessingBatchDuration';
const PARAM_ROW_STREAM_HIGH_WATER_MARK = 'rowStreamHighWaterMark';
const PARAM_RETRY_LARGE_RESULT_SET_MAX_NUM_RETRIES = 'largeResultSetRetryMaxNumRetries';
const PARAM_RETRY_LARGE_RESULT_SET_MAX_SLEEP_TIME = 'largeResultSetRetryMaxSleepTime';
const PARAM_RETRY_SF_MAX_LOGIN_RETRIES = 'sfRetryMaxLoginRetries';
const PARAM_RETRY_SF_MAX_NUM_RETRIES = 'sfRetryMaxNumRetries';
const PARAM_RETRY_SF_STARTING_SLEEP_TIME = 'sfRetryStartingSleepTime';
const PARAM_RETRY_SF_MAX_SLEEP_TIME = 'sfRetryMaxSleepTime';
/**
* Creates the list of known parameters. If a parameter is marked as external,
* its value can be overridden by adding the appropriate name-value mapping to
* the ConnectionConfig options.
*
* @returns {Object[]}
*/
function createParameters() {
const isNonNegativeInteger = Util.number.isNonNegativeInteger.bind(Util.number);
const isPositiveInteger = Util.number.isPositiveInteger.bind(Util.number);
const isNonNegativeNumber = Util.number.isNonNegative.bind(Util.number);
return [
{
name: PARAM_TIMEOUT,
defaultValue: 90 * 1000,
external: true,
validate: isPositiveInteger
},
{
name: PARAM_RESULT_PREFETCH,
defaultValue: 2,
external: true,
validate: isPositiveInteger
},
{
name: PARAM_RESULT_STREAM_INTERRUPTS,
defaultValue: 3,
validate: isPositiveInteger
},
// for now we set chunk cache size to 1, which is same as
// disabling the chunk cache. Otherwise, cache will explode
// memory when fetching large result set
{
name: PARAM_RESULT_CHUNK_CACHE_SIZE,
defaultValue: 1,
validate: isPositiveInteger
},
{
name: PARAM_RESULT_PROCESSING_BATCH_SIZE,
defaultValue: 1000,
validate: isPositiveInteger
},
{
name: PARAM_RESULT_PROCESSING_BATCH_DURATION,
defaultValue: 100,
validate: isPositiveInteger
},
{
name: PARAM_ROW_STREAM_HIGH_WATER_MARK,
defaultValue: 10,
validate: isPositiveInteger
},
{
name: PARAM_RETRY_LARGE_RESULT_SET_MAX_NUM_RETRIES,
defaultValue: 10,
validate: isNonNegativeInteger
},
{
name: PARAM_RETRY_LARGE_RESULT_SET_MAX_SLEEP_TIME,
defaultValue: 16,
validate: isNonNegativeInteger
},
{
name: PARAM_RETRY_SF_MAX_LOGIN_RETRIES,
defaultValue: 7,
external: true,
validate: isNonNegativeInteger
},
{
name: PARAM_RETRY_SF_MAX_NUM_RETRIES,
defaultValue: 1000,
validate: isNonNegativeInteger
},
{
name: PARAM_RETRY_SF_STARTING_SLEEP_TIME,
defaultValue: 1,
validate: isNonNegativeNumber
},
{
name: PARAM_RETRY_SF_MAX_SLEEP_TIME,
defaultValue: 16,
validate: isNonNegativeNumber
}
];
}
ConnectionConfig.prototype.getTimeout = function () {
return this._getParameterValue(PARAM_TIMEOUT);
};
ConnectionConfig.prototype.getResultPrefetch = function () {
return this._getParameterValue(PARAM_RESULT_PREFETCH);
};
ConnectionConfig.prototype.getResultStreamInterrupts = function () {
return this._getParameterValue(PARAM_RESULT_STREAM_INTERRUPTS);
};
ConnectionConfig.prototype.getResultChunkCacheSize = function () {
return this._getParameterValue(PARAM_RESULT_CHUNK_CACHE_SIZE);
};
ConnectionConfig.prototype.getResultProcessingBatchSize = function () {
return this._getParameterValue(PARAM_RESULT_PROCESSING_BATCH_SIZE);
};
ConnectionConfig.prototype.getResultProcessingBatchDuration = function () {
return this._getParameterValue(PARAM_RESULT_PROCESSING_BATCH_DURATION);
};
ConnectionConfig.prototype.getRowStreamHighWaterMark = function () {
return this._getParameterValue(PARAM_ROW_STREAM_HIGH_WATER_MARK);
};
ConnectionConfig.prototype.getRetryLargeResultSetMaxNumRetries = function () {
return this._getParameterValue(PARAM_RETRY_LARGE_RESULT_SET_MAX_NUM_RETRIES);
};
ConnectionConfig.prototype.getRetryLargeResultSetMaxSleepTime = function () {
return this._getParameterValue(PARAM_RETRY_LARGE_RESULT_SET_MAX_SLEEP_TIME);
};
ConnectionConfig.prototype.getRetrySfMaxNumRetries = function () {
return this._getParameterValue(PARAM_RETRY_SF_MAX_NUM_RETRIES);
};
ConnectionConfig.prototype.getRetrySfMaxLoginRetries = function () {
return this._getParameterValue(PARAM_RETRY_SF_MAX_LOGIN_RETRIES);
};
ConnectionConfig.prototype.getRetrySfStartingSleepTime = function () {
return this._getParameterValue(PARAM_RETRY_SF_STARTING_SLEEP_TIME);
};
ConnectionConfig.prototype.getRetrySfMaxSleepTime = function () {
return this._getParameterValue(PARAM_RETRY_SF_MAX_SLEEP_TIME);
};
/**
* Returns the value of a given connection config parameter.
*
* @param parameterName
*
* @returns {Object}
* @private
*/
ConnectionConfig.prototype._getParameterValue = function (parameterName) {
const parameter = this._mapParameters[parameterName];
return parameter ? parameter.value : undefined;
};
module.exports = ConnectionConfig;