"use strict";
const utils = require("./utils");
const types = require("./types");
const promiseUtils = require("./promise-utils");
/**
* Creates a new instance of {@link ExecutionProfile}.
* @classdesc
* Represents a set configurations to be used in a statement execution to be used for a single {@link Client} instance.
*
* An {@link ExecutionProfile} instance should not be shared across different {@link Client} instances.
* @param {String} name Name of the execution profile.
*
* Use `'default'` to specify that the new instance should be the default {@link ExecutionProfile} if no
* profile is specified in the execution.
* @param {Object} [options] Profile options, when any of the options is not specified the {@link Client} will the use
* the ones defined in the default profile.
* @param {Number} [options.consistency] The consistency level to use for this profile.
* @param {LoadBalancingPolicy} [options.loadBalancing] The load-balancing policy to use for this profile.
* @param {Number} [options.readTimeout] The client per-host request timeout to use for this profile.
* @param {RetryPolicy} [options.retry] The retry policy to use for this profile.
* @param {Number} [options.serialConsistency] The serial consistency level to use for this profile.
* @param {LoadBalancingPolicy} [options.loadBalancing] The load-balancing policy to use for this profile.
* @param {Number} [options.readTimeout] The client per-host request timeout to use for this profile.
* @param {RetryPolicy} [options.retry] The retry policy to use for this profile.
* @param {Number} [options.serialConsistency] The serial consistency level to use for this profile.
* @example
* const { Client, ExecutionProfile } = require('cassandra-driver');
* const client = new Client({
* contactPoints: ['host1', 'host2'],
* profiles: [
* new ExecutionProfile('metrics-oltp', {
* consistency: consistency.localQuorum,
* retry: myRetryPolicy
* })
* ]
* });
*
* client.execute(query, params, { executionProfile: 'metrics-oltp' }, callback);
* @constructor
*/
function ExecutionProfile(name, options) {
if (typeof name !== "string") {
throw new TypeError("Execution profile name must be a string");
}
options = options || utils.emptyObject;
/**
* Name of the execution profile.
* @type {String}
*/
this.name = name;
/**
* Consistency level.
* @type {Number}
*/
this.consistency = options.consistency;
/**
* Load-balancing policy
* @type {LoadBalancingPolicy}
*/
this.loadBalancing = options.loadBalancing;
/**
* Client read timeout.
* @type {Number}
*/
this.readTimeout = options.readTimeout;
/**
* Retry policy.
* @type {RetryPolicy}
*/
this.retry = options.retry;
/**
* Serial consistency level.
* @type {Number}
*/
this.serialConsistency = options.serialConsistency;
/**
* Legacy field
* @type {undefined}
*/
this.graphOptions = undefined;
}
/**
* Contains the logic to handle the different execution profiles of a {@link Client}.
* @ignore
*/
class ProfileManager {
/**
* @param {ClientOptions} options
*/
constructor(options) {
this._profiles = options.profiles || [];
this._defaultConfiguredRetryPolicy = undefined;
this._setDefault(options);
// A array of unique load balancing policies
this._loadBalancingPolicies = [];
// A dictionary of name keys and profile values
this._profilesMap = {};
// A dictionary of name keys and custom payload dictionaries as values
this._customPayloadCache = {};
this._profiles.forEach(function (p) {
this._profilesMap[p.name] = p;
// Set required properties
p.loadBalancing =
p.loadBalancing || this._defaultProfile.loadBalancing;
// Using array indexOf is not very efficient (O(n)) but the amount of profiles should be limited
// and a handful of load-balancing policies (no hashcode for load-Balancing policies)
if (this._loadBalancingPolicies.indexOf(p.loadBalancing) === -1) {
this._loadBalancingPolicies.push(p.loadBalancing);
}
return p;
}, this);
}
/**
* @param {Client} client
* @param {HostMap} hosts
*/
async init(client, hosts) {
for (const lbp of this._loadBalancingPolicies) {
await promiseUtils.fromCallback((callback) =>
lbp.init(client, hosts, callback),
);
}
}
/**
* Uses the load-balancing policies to get the relative distance to the host and return the closest one.
* @param {Host} host
*/
getDistance(host) {
let distance = types.distance.ignored;
// this is performance critical: we can't use any other language features than for-loop :(
for (let i = 0; i < this._loadBalancingPolicies.length; i++) {
const d = this._loadBalancingPolicies[i].getDistance(host);
if (d < distance) {
distance = d;
if (distance === types.distance.local) {
break;
}
}
}
host.setDistance(distance);
return distance;
}
/**
* @param {String|ExecutionProfile} name
* @returns {ExecutionProfile|undefined} It returns the execution profile by name or the default profile when name is
* undefined. It returns undefined when the profile does not exist.
*/
getProfile(name) {
if (name instanceof ExecutionProfile) {
return name;
}
return this._profilesMap[name || "default"];
}
/** @returns {ExecutionProfile} */
getDefault() {
return this._defaultProfile;
}
/** @returns {LoadBalancingPolicy} */
getDefaultLoadBalancing() {
return this._defaultProfile.loadBalancing;
}
/**
* @private
* @param {ClientOptions} options
*/
_setDefault(options) {
this._defaultProfile = this._profiles.filter(function (p) {
return p.name === "default";
})[0];
if (!this._defaultProfile) {
this._profiles.push(
(this._defaultProfile = new ExecutionProfile("default")),
);
}
// Store the default configured retry policy
this._defaultConfiguredRetryPolicy = this._defaultProfile.retry;
// Set the required properties
this._defaultProfile.loadBalancing =
this._defaultProfile.loadBalancing ||
options.policies.loadBalancing;
this._defaultProfile.retry =
this._defaultProfile.retry || options.policies.retry;
}
/**
* Gets all the execution profiles currently defined.
* @returns {Array.<ExecutionProfile>}
*/
getAll() {
return this._profiles;
}
getDefaultConfiguredRetryPolicy() {
return this._defaultConfiguredRetryPolicy;
}
}
module.exports = {
ProfileManager,
ExecutionProfile,
};