oracle-nosqldb
Version:
Node.js driver for Oracle NoSQL Database
438 lines (430 loc) • 22.9 kB
JavaScript
/*-
* Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl/
*/
;
/**
* Defines types used for NoSQL driver configuration.
*/
/**
* Configuration object passed to construct {@link NoSQLClient} instance.
* <p>
* This configuration can be passed to {@link NoSQLClient}
* directly as JavaScript object or stored in a file as JSON or JavaScript
* object (in which case the file path is passed to the NoSQLClient
* constructor). Note that most of the properties are optional and
* applicable default values will be used in their absense.
* <p>
* Note that methods of {@link NoSQLClient} that perform operations on NoSQL
* database take <em>opt</em> parameter as one of the arguments. In addition
* to options specific to particular operation, the <em>opt</em> parameter
* may have some of the same properties present in {@link Config} and
* will override thier values for particular operation. Not all options can
* be overriden in the <em>opt</em> parameter. {@link NoSQLClient} method
* descriptions provide list of options that can override the property values
* in {@link Config} for particular method. Remaining properties can only be
* specified in {@link Config} and thus are set for the lifetime of
* {@link NoSQLClient} instance. Note that all parameters present in
* {@link Config}, with the exception of user-defined class instances, will
* be copied upon creation of {@link NoSQLClient} instance, so their
* modification will have no effect after {@link NoSQLClient} instance is
* created.
* <p>
* Note that all timeouts, durations, and other numeric options here and
* elsewhere are restricted to being non-negative 32 bit integers, unless
* specified otherwise (the exception to this is when dates are represented as
* absolute value of milliseconds).
* <p>
* Note that since currently JavaScript and Node.js do not have a way to work
* with arbitrary precision decimal numbers, the driver supports integration
* with 3rd party number libraries to use for database type <em>Number</em>.
* This allows you to use a 3rd party of your choice (e.g. decimal.js,
* bignumber.js, etc.) to represent arbitrary precision numbers. See
* {@link DBNumberConfig} for details.
*
* @tutorial connect-cloud
* @tutorial connect-on-prem
* @tutorial tables
*
* @example //Config object stored as JSON in a file ~/myapp/ndcs_config.json
* //(1s are used for sensitive info)
* {
* "serviceType": "CLOUD"
* "endpoint": "nosql.us-phoenix-1.oci.oraclecloud.com",
* "timeout": 20000,
* "auth":
* {
* "iam":
* {
* "configFile": "~/myapp/.oci/config",
* "profileName": "John"
* }
* }
* }
*
* //In application code:
* const client = new NoSQLClient('~/myapp/ndcs_config.json');
*
* @example //Same config directly passed as JavaScript object to
* //{@link NoSQLClient#constructor}
* const client = new NoSQLClient({
* serviceType: ServiceType.CLOUD,
* endpoint: 'nosql.us-phoenix-1.oci.oraclecloud.com',
* timeout: 20000,
* auth: {
* iam: {
* configFile: '~/myapp/.oci/config',
* profileName: 'John'
* }
* }
* });
*
* @example //Overriding properties in Config for given API call:
*
* //Will use timeout of 8000 instead of 20000 specified at client's creation
* client.getTableInfo('Table1', { timeout: 8000 }, (err, res) => {
* //.....
* });
*
* @global
* @typedef {object} Config
* @property {(ServiceType|string)} [serviceType] Type of service the driver
* will be using. May be specified as either {@link ServiceType} enumeration
* or string. Currently supported values are CLOUD, CLOUDSIM and KVSTORE.
* Although this property is optional, it is recommended to specify it to
* avoid ambiguity. If not specified, in most cases the driver will deduce
* the service type from other information in {@link Config}. See
* {@link ServiceType} for details
* @property {(string|URL)} [endpoint] Endpoint to use to connect to
* the service. See the online documentation for the complete set of
* available regions. For example,
* <em>ndcs.uscom-east-1.oraclecloud.com</em> or <em>localhost:8080</em>.
* Endpoint specifies the host to connect to but may optionally specify port
* and/or protocol. Protocol is usually not needed and is inferred from the
* host and port information: if no port is specified, port 443 and
* protocol HTTPS are assumed, if port 443 is specified, HTTPS is assumed,
* if port is specified and it is not 443, HTTP is assumed. If protocol is
* specified, it must be either HTTP or HTTPS. For example,
* <em>https://nosql.us-phoenix-1.oci.oraclecloud.com</em> or
* <em>http://localhost:8080</em>. In this case, in addition to string, the
* endpoint may also be specified as Node.js URL instance. If protocol is
* specified but not port, 443 is assumed for HTTPS and 8080 for HTTP (which
* is the default port for CloudSim). You may specify <em>endpoint</em> or
* <em>region</em> but not both.
* @property {Region|string} [region] Cloud service only. Specify a region
* to use to connect to the Oracle NoSQL Database Cloud Service.
* This property may be specified instead of {@link Config}#endoint.
* The service endpoint will be inferred from the region. May be
* specified either as {@link Region} enumeration constant, e.g.
* {@link Region.AP_MUMBAI_1} or as a string (so it can be specified in
* config file), which must be either one of {@link Region} enumeration
* constant names, e.g. <em>AP_MUMBAI_1</em>, <em>US_ASHBURN_1</em>, etc or
* one of region identifiers, e.g. <em>ap-mumbai-1</em>,
* <em>us-ashburn-1</em>, etc. You must specify either {@link Config}#region
* or {@link Config}#endpoint but not both. The only exception to this is if
* you set the region identifier in an OCI configuration file together with
* your credentials, in which case you need not specify either
* {@link Config}#region or {@link Config}#endpoint. This implies that you
* store your credentials and region identifier in the OCI configuration file
* and provide configuration in {@link IAMConfig} to access this file or use
* the defaults. See {@link IAMConfig} for more information. Note that
* setting {@link Config}#region or {@link Config}#endpoint takes precedence
* over region identifier in an OCI configuration file
* @property {number} [timeout=5000] Timeout in for non-DDL operations in
* milliseconds. Note that for operations that are automatically retried,
* the timeout is cumulative over all retries and not just a timeout for
* a single retry. This means that all retries and waiting periods between
* retries are counted towards the timeout
* @property {number} [ddlTimeout=10000] Timeout for DDL operations, that is
* operations executed by {@link NoSQLClient#tableDDL},
* {@link NoSQLClient#setTableLimits} or {@link NoSQLClient#adminDDL}
* methods, in milliseconds. Used as a default <em>opt.timeout</em> for
* these methods. Note that if <em>opt.complete</em> is true for any of
* these methods, separate default timeouts are used for issuing the
* DDL operation and waiting for its completion, with values of
* {@link Config}#ddlTimeout for the former and
* {@link Config}#tablePollTimeout or {@link Config}#adminPollTimeout for the
* latter (if not set, these poll timeouts default to <em>Infinity</em>).
* @property {number} [securityInfoTimeout=10000] Timeout for all operations
* while waiting for security information to be available in the system, in
* milliseconds. It is different from regular operation timeout and is used
* while automatically retrying operations that failed with error code
* {@link ErrorCode.SECURITY_INFO_UNAVAILABLE})
* @property {number} [tablePollTimeout=Infinity] Timeout when polling for
* table state using {@link NoSQLClient#forCompletion} while waiting for
* completion of {@link NoSQLClient#tableDDL} operation, in milliseconds.
* Can be overriden by <em>opt.timeout</em> for these methods. Default is
* <em>Infinity</em> meaning no timeout. This is to allow for potentially
* long running table DDL operations
* @property {number} [tablePollDelay=1000] Delay between successive poll
* attempts when polling for table state using
* {@link NoSQLClient#forCompletion} while waiting for completion
* of {@link NoSQLClient#tableDDL} operation, in milliseconds. Can be
* overriden by <em>opt.delay</em> for these methods
* @property {number} [adminPollTimeout=Infinity] Timeout when waiting for
* completion of {@link NoSQLClient#adminDDL} operation, as used by
* {@link NoSQLClient#forCompletion}, in milliseconds. Can be overriden by
* <em>opt.timeout</em> for these methods. Default is <em>Infinity</em>
* meaning no timeout. This is to allow for potentially long running admin
* DDL operations
* @property {number} [adminPollDelay=1000] Delay between successive poll
* attempts when waiting for completion of {@link NoSQLClient#adminDDL}
* operation, as used by {@link NoSQLClient#forCompletion}, in milliseconds.
* Can be overriden by <em>opt.delay</em> for these methods
* @property {Consistency} [consistency=Consistency.EVENTUAL]
* Consistency used for read operations
* @property {Durability} [durability] On-premises only. Durability used for
* write operations. If not set, the default server-side durability settings
* are used
* @property {number} [maxMemoryMB=1024] Maximum amount of memory in
* megabytes that may be used by the driver-side portion of execution of
* queries for operations such as duplicate elimination (which may be
* required if using an index on an array or a map) and sorting. Such
* operations may require significant amount of memory as they need to cache
* full result set or a large subset of it locally. If memory consumption
* exceeds this value, error will result. The default is 1 GB
* @property {string} [compartment] Cloud service only. Compartment id (OCID)
* or compartment name to use for operations with this {@link NoSQLClient}
* instance. If the name is used it can be either the name of a top-level
* compartment or a path to a nested compartment, e.g.
* <em>compartmentA.compartmentB.compartmentC</em>. The path should not
* include the root compartment name (tenant). If this property is not
* specified either here or for an individual operation the
* tenant OCID is used as the compartment id for the operation, which is the
* id of the root compartment for the tenancy. See
* [Setting Up Your Tenancy]{@link https://docs.cloud.oracle.com/iaas/Content/GSG/Concepts/settinguptenancy.htm}
* for more information
* @property {RetryConfig|null} [retry] Configuration for operation retries
* as specified by {@link RetryConfig} object. If not specified, default
* retry configuration is used, see {@link RetryConfig}. May be set to null
* to disable operation retries alltogether
* @property {object} [httpOpt] Http or https options object for the driver
* in the same format as passed to constructor of Node.js
* <em>HTTP.Agent</em> or <em>HTTPS.Agent</em>. If not specified, default
* global<em>HTTP.Agent</em> or <em>HTTPS.Agent</em> will be used instead
* @property {AuthConfig} [auth] Authorization configuration, see
* {@link AuthConfig}
* @property {DBNumberConfig} [dbNumber] Configuration to use 3rd party
* number/decimal library for values of datatype <em>Number</em>. If not
* specified, the driver will use Javascript <em>number</em> type to
* represent values of type Number. See {@link DBNumberConfig}
* @property {boolean} [longAsBigInt] If set to <em>true</em>, Database Type
* <em>Long</em> is represented as JavaScript type <em>bigint</em>. This
* allows to represent 64-bit integers without loss of precsision, even when
* they are outside of range from <em>Number.MIN_SAFE_INTEGER</em> to
* <em>Number.MAX_SAFE_INTEGER</em> (that is, their magnitude exceeds 53 bits
* in size). If this option is set, the values of datatype <em>Long</em>
* returned by the service by operations such as {@link NoSQLClient#get} as
* well as query results will be of type <em>bigint</em>. For values of
* datatype <em>Long</em> passed to the service by operations such as
* {@link NoSQLClient#put} you may use either <em>bigint</em> or
* <em>number</em>. If not specified, defaults to <em>false</em>, meaning
* that the values of datatype <em>Long</em> are returned as <em>number</em>.
* In this case, loss of precision is possible for values outside the safe
* integer range as indicated above.
* @property {boolean|function|string} [rateLimiter] For
* Cloud Service or Cloud Simulator only. Enables rate limiting based on
* table limits. You may use default rate limiter provided by the driver or
* supply a custom rate limiter. Set this value to <em>true</em> to use
* default rate limiter. To use custom rate limiter, set this
* value to the constructor function of your custom {@link RateLimiter}
* class. Alternatively, provide a module name which exports the
* constructor function. If not specified or set to <em>false</em>,
* <em>undefined</em> or <em>null</em>, rate limiting is disabled.
* See {@link RateLimiter}
* @property {number} [rateLimiterPercent] For Cloud Service or Cloud
* Simulator only. When rate limiting is enabled (see
* {@link Config}#rateLimiter), specifies percentage of table limits this
* {@link NoSQLClient} instance will use. This is useful when running
* multiple clients and allotting each client only a portion of the table
* limits. Must be > 0 and <= 100. If not specified, defaults to 100, which
* means to use full table limits. See {@link RateLimiter}
*/
/**
* Configuration for operation retries, which is set as {@link Config}#retry.
* <p>
* When an operation fails with {@link NoSQLError} or its subclass, the driver
* has an option to retry the operation automatically, transparently to the
* application. The operation may be retried multiple times until the
* operation timeout is reached. The driver may only retry the operations
* that failed with retryable {@link ErrorCode} (see
* {@link NoSQLError#errorCode}). Whether the operation is retried and how
* depends on the what {@link RetryHandler} is used. Retry handler is an
* object that provides two properties/methods: {@link RetryHandler}#doRetry
* that determines whether the operation should be retried at given time and
* {@link RetryHandler}#delay that determines how long to wait between
* successive retries.
* <p>
* {@link RetryConfig} object may contain {@link RetryHandler} and applicable
* parameters customize that retry handler. Unless application sets its
* own {@link RetryHandler}, the driver will use default retry handler which
* is suitable for most applications. Default {@link RetryHandler} works as
* follows:
* <p>
* Whether the operation is retried depends on:
* <ul>
* <li>Whether the error is retryable as mentioned above. This is the case for
* any {@link RetryHandler}. Default {@link RetryHandler} has special
* handling for {@link ErrorCode.INVALID_AUTHORIZATION}, see the description
* of that error code for details.
* </li>
* <li>Type of the operation. In general, only data operations are retried,
* not DDL or metadata operations (such as {@link NoSQLClient#listTables} or
* {@link NoSQLClient#getIndexes}). However, if DDL operation caused
* {@link ErrorCode.OPERATION_LIMIT_EXCEEDED}.
* the operation will be retried with large delay as described below.</li>
* <li>Whether the limit on the number of retries has been reached as
* configured by {@link RetryConfig}#maxRetries property.</li>
* </ul>
* For retry delay, an exponential backoff algorithm is used. The delay
* starts with {@link RetryConfig}#baseDelay and then doubles on successive
* retries. In addition a random value between 0 and
* {@link RetryConfig}#baseDelay is added to this result.
* <p>
* Exceptions to this are:
* <ul>
* <li>If DDL operation resulted in {@link ErrorCode.OPERATION_LIMIT_EXCEEDED}
* because of more stringent system limits for control operations, a much
* larger delay is needed to retry the operation. In this case the
* exponential backoff algorithm will start with a large delay of
* {@link RetryConfig}#controlOpBaseDelay. You may customize this value
* depending on what limits the system has for DDL operations. You may
* disable automatic retries for this error by setting
* {@link RetryConfig}#controlOpBaseDelay to null.</li>
* <li>Network errors (see {@link ErrorCode.NETWORK_ERROR}) and errors caused
* by unavailability of security information (see
* {@link ErrorCode.SECURITY_INFO_UNAVAILABLE}) are always retried regardless
* of the number of retries reached without regard to
* {@link RetryConfig}#maxRetries. As for other errors, the retries are
* stopped when operation timeout is reached that results in
* {@link NoSQLTimeoutError}.</li>
* <li>When the retry is caused by unavailability of security information as
* determined by {@link ErrorCode.SECURITY_INFO_UNAVAILABLE} the algorithm
* starts with constant delay of {@link RetryConfig}#secInfoBaseDelay for a
* maximum number of retries {@link RetryConfig}#secInfoNumBackoff and then
* switches to exponential backoff algorithm described above also starting
* with {@link RetryConfig}#secInfoBaseDelay. You can set
* {@link RetryConfig}#secInfoNumBackoff to 0 to start exponential backoff
* algorithm immediately.</li>
* </ul>
* <p>
* You may customize the default retry handler by overriding the values of any
* properties mentioned above.
*
* @see {@link RetryHandler}
* @example //Customizing default retry handler
* let config = {
* endpoint: '.....',
* .....
* retry: {
* numRetries: 3,
* baseDelay: 3000,
* //Default values to be used for security info errors
* }
* };
*
* @example //Disable retries alltogether, application will retry manually
* let config = {
* endpoint: '.....',
* .....
* retry: null
* };
*
* @global
* @typedef {object} RetryConfig
* @property {RetryHandler|null} [handler] Retry handler used. Set this
* property if you want to use custom retry handler. You may set this to
* null to disable retries alltogether
* @property {number} [maxRetries=10] Maximum number of retries, including
* initial API invocation, for default retry handler
* @property {number} [baseDelay=200] Base delay between retries for
* exponential backoff algorithm in default retry handler, in milliseconds
* @property {number} [controlOpBaseDelay=60000] Base retry delay for
* {@link ErrorCode.OPERATION_LIMIT_EXCEEDED} used by default retry handler
* exponential backoff algorithm. Note that automatic retries for this error
* only take effect if the timeout used for the operation that caused the
* error (see {@link Config}#timeout and {@link Config}#ddlTimeout) is greater
* than the value of <em>controlOpBaseDelay</em>. Otherwise the operation
* won't be retried and {@link ErrorCode.OPERATION_LIMIT_EXCEEDED} will be
* returned to the application. You may also set this property to null
* to disable automatic retries for this error (if it is prefferred that
* application does manual retries for this error)
* @property {number} [secInfoBaseDelay=100] Base delay when waiting for
* availability of security information as in error code
* {@link ErrorCode.SECURITY_INFO_UNAVAILABLE} for default retry handler, in
* milliseconds
* @property {number} [secInfoNumBackoff=10] Maximum number of retries with
* constant delay when waiting for availability of security information, as in
* error code {@link ErrorCode.SECURITY_INFO_UNAVAILABLE}
* for default retry handler
*/
/**
* Retry handler set as {@link RetryConfig}#handler. Use this to set custom
* retry handler. This type should provide two properties which can
* be functions or constants (see below): {@link RetryHandler}#doRetry and
* {@link RetryHandler}#delay. It may be a plain object or an instance of a
* class.
*
* @example //Using custom retry handler
* let config = {
* endpoint: '.....',
* .....
* retry: {
* handler: {
* doRetry: (op, numRetries, err) => {
* //for the sake of example
* return numRetries < 5;
* }
* delay: (op, numRetries) => {
* //for the sake of example
* return (numRetries + 1) * 1000;
* }
* }
* }
* };
*
* @global
* @typedef {object} RetryHandler
* @property {boolean|doRetry} doRetry Determines whether an
* operation should be retried. Can be either boolean, which applies to all
* operations, or a function that determines whether given operation should be
* retried based on operation, number of retries so far and the error
* occured. See {@link doRetry}
* @property {number|delay} delay Determines delay between
* successive retries in milliseconds. Can be either number, which indicates
* constant delay in milliseconds, or a function that determines delay based
* on operation, number of retries so far and the error occurred. See
* {@link delay}
*/
/**
* Function definition for {@link RetryHandler}#doRetry.
* @global
* @callback doRetry
* @param {Operation} operation Operation object describing the failed
* operation
* @param {number} numRetries How many retries happened so far for this
* operation. This includes the original API invokation, so numRetries
* will be 1 after the first error
* @param {NoSQLError} err Error that occurred as {@link NoSQLError} or its
* subclass
* @return {boolean} true if the operation should be retried. If false,
* no more retries will be done for this operation
*/
/**
* Function definition for {@link RetryHandler}#delay. This function
* will be called only if {@link RetryHandler}#doRetry returned
* <em>true</em>.
* @global
* @callback delay
* @param {Operation} operation Operation object describing the failed
* operation
* @param {number} numRetries How many retries happened so far for this
* operation. This includes original API invokation, so numRetries
* will be 1 after the first error
* @param {NoSQLError} err Error that occurred as {@link NoSQLError} or its
* subclass
* @return {number} Number of milliseconds to before the next retry of this
* operation
*/