// *****************************************************************************
// Copyright 2013-2023 Aerospike, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// *****************************************************************************
'use strict'
const as = require('bindings')('aerospike.node')
const AerospikeError = require('./error')
const EventLoop = require('./event_loop')
/**
* @module aerospike
*
* @description The Aerospike module is the main entry point for the Aerospike
* Node.js Client API. It provides methods for creating new client instances
* that connect to a specific Aerospike server cluster.
*/
// ========================================================================
// Sub-Modules
// ========================================================================
/**
* The {@link module:aerospike/filter|filter} module provides functions to
* create secondary index (SI) filter predicates for use in query operations via the
* {@link Client#query} command.
*
* @summary {@link module:aerospike/filter|aerospike/filter} module
*/
exports.filter = require('./filter')
/**
* The {@link module:aerospike/exp|exp} module provides functions to
* create expressions for use in key operations via the {@link
* Client#operate} command.
* @summary {@link module:aerospike/exp|aerospike/exp} module
*/
const exp = exports.exp = require('./exp')
exp.type = as.exp.type
/**
* @summary POSIX regex compilation flags.
*
* @enum {number}
*
*/
exports.regex = {
/** Use basic regular expression syntax. */
BASIC: 0,
/** Use extended regular expression syntax. */
EXTENDED: 1,
/** Ignore case when matching. */
ICASE: 2,
/** Anchors do not match at newline characters in the string. */
NEWLINE: 4
}
/**
* The info protocol provides access to configuration and statistics for the
* Aerospike server. The {@link module:aerospike/info|info} module provides
* utility functions for parsing the info data returned by the Aerospike
* server.
*
* @summary {@link module:aerospike/info|aerospike/info} module
*/
exports.info = require('./info')
/**
* The admin module contains classes associated with RBAC (Role Based Access Control) security
* methods defined in {@link Client}
*
* @summary {@link module:aerospike/admin|aerospike/admin} module
*/
exports.admin = require('./admin')
/**
* The {@link module:aerospike/lists|lists} module defines operations on the Lists
* complex data type.
*
* @summary {@link module:aerospike/lists|aerospike/lists} module
*/
exports.lists = require('./lists')
/**
* The {@link module:aerospike/hll|hll} module defines operations on the
* HyperLogLog data type.
*
* @summary {@link module:aerospike/hll|aerospike/hll} module
*
* @since v3.16.0
*/
exports.hll = require('./hll')
/**
* The {@link module:aerospike/maps|maps} module defines operations on the Maps
* complex data type.
*
* @summary {@link module:aerospike/maps|aerospike/maps} module
* @static
*/
const maps = exports.maps = require('./maps')
// copy maps related enums into maps module
Object.keys(as.maps).forEach(key => {
maps[key] = as.maps[key]
})
/**
* The {@link module:aerospike/cdt|cdt} module provides the {@link CdtContext}
* class for operations on nested lists and maps.
*
* @summary {@link module:aerospike/cdt|aerospike/cdt} module
*/
exports.cdt = {
Context: require('./cdt_context')
}
/**
* The {@link module:aerospike/bitwise|bitwise} module defines operations on
* the bytes data type.
*
* @summary {@link module:aerospike/bitwise|aerospike/bitwise} module
*/
exports.bitwise = require('./bitwise')
/**
* The {@link module:aerospike/operations|operations} module provides functions
* to create operations for the {@link Client#operate} command.
*
* @summary {@link module:aerospike/operations|aerospike/operations} module
*/
exports.operations = require('./operations')
/**
* The {@link module:aerospike/exp/operations|ExpOperation} module provides functions
* to create operations using <a href="https://aerospike.com/docs/guide/expressions">⇑Aerospike Expressions</a>
* for the {@link Client#operate} command.
*
*
* @summary {@link module:aerospike/exp/operations|aerospike/exp/operations} module
*/
exp.operations = require('./exp_operations')
/**
* The {@link module:aerospike/policy|policy} module defines policies and
* policy values that define the behavior of database operations.
*
* @summary {@link module:aerospike/policy|aerospike/policy} module
* @static
*/
exports.policy = require('./policy')
// short-cuts to the policy classes defined under the policy module
exports.BasePolicy = require('./policy').BasePolicy
exports.ApplyPolicy = require('./policy').ApplyPolicy
exports.BatchPolicy = require('./policy').BatchPolicy
exports.OperatePolicy = require('./policy').OperatePolicy
exports.QueryPolicy = require('./policy').QueryPolicy
exports.ReadPolicy = require('./policy').ReadPolicy
exports.RemovePolicy = require('./policy').RemovePolicy
exports.ScanPolicy = require('./policy').ScanPolicy
exports.WritePolicy = require('./policy').WritePolicy
exports.BatchApplyPolicy = require('./policy').BatchApplyPolicy
exports.BatchReadPolicy = require('./policy').BatchReadPolicy
exports.BatchRemovePolicy = require('./policy').BatchRemovePolicy
exports.BatchWritePolicy = require('./policy').BatchWritePolicy
exports.CommandQueuePolicy = require('./policy').CommandQueuePolicy
exports.InfoPolicy = require('./policy').InfoPolicy
exports.ListPolicy = require('./policy').ListPolicy
exports.MapPolicy = require('./policy').MapPolicy
exports.AdminPolicy = require('./policy').AdminPolicy
/**
* The {@link module:aerospike/status|status} module contains a list of the
* status codes returned by the Aerospike server.
*
* @summary {@link module:aerospike/status|aerospike/status} module
*/
exports.status = require('./status')
/**
* The {@link module:aerospike/features|features} module contains a list of the
* feature strings used by the Aerospike server.
*
* @summary {@link module:aerospike/features|aerospike/features} module
*/
exports.features = require('./features')
// ========================================================================
// Classes
// ========================================================================
/**
* In case of any errors during the database operation the client will return an
* {@link AerospikeError} instance (either through the provided callback or
* when the returned Promise gets resolved).
*
* @summary {@link AerospikeError} class
*/
exports.AerospikeError = AerospikeError
/**
* The main interface of the Aerospike client. Commands such as put, get or query
* can be sent to an Aerospike database cluster using the Client class.
*
* @summary {@link Client} class
*/
exports.Client = require('./client')
/**
* The Config class contains the settings for an Aerospike client instance,
* including the list of seed hosts, default policies, and other settings.
*
* @summary {@link Config} class
*/
exports.Config = require('./config')
/**
* All the decimal values with valid fractions (e.g. 123.45) will be stored as
* double data type in Aerospike. To store decimal values with 0 fraction as
* double, the value needs to be wrapped in a {@link Double} class instance.
*
* @summary {@link Double} class
*/
exports.Double = require('./double')
/**
* Representation of a GeoJSON value. Since GeoJSON values are JSON objects
* they need to be wrapped in the {@link GeoJSON} class so that the client can
* distinguish them from other types of objects.
*
* @summary {@link GeoJSON} class
*/
exports.GeoJSON = require('./geojson')
/**
* A key uniquely identifies a record in the Aerospike database within a given
* namespace.
*
* @summary {@link Key} class
*/
exports.Key = require('./key')
/**
* A record with the Aerospike database consists of one or more record "bins"
* (name-value pairs) and meta-data, incl. time-to-live and generation; a
* record is uniquely identified by it's key within a given namespace.
*
* @summary {@link Record} class
*/
exports.Record = require('./record')
/**
* In the Aerospike database, each record (similar to a row in a relational database) stores
* data using one or more bins (like columns in a relational database).
*
* @summary {@link Bin} class
*/
exports.Bin = require('./bin')
// ========================================================================
// Enumerations
// ========================================================================
/**
* @summary Enumeration of auth modes
*
* @description Authentication mode when user/password is defined.
*
* Note: The Node.js client's TLS support is currently limited to Linux, and
* therefore secure, external authentication (e.g. LDAP) is only supported on
* Linux as well. External authentication can be used on macOS or Windows but
* it will _not_ be secure!
*
* @enum {number}
*
* @property {number} INTERNAL - Use internal authentication only. Hashed
* password is stored on the server. Do not send clear password. This is the
* default.
* @property {number} EXTERNAL - Use external authentication (like LDAP).
* Specific external authentication is configured on server. If TLS is enabled,
* send clear password on node login via TLS. Throws exception, if TLS is not
* enabled.
* @property {number} EXTERNAL_INSECURE - Use external authentication (like
* LDAP). Specific external authentication is configured on server. Send
* clear password on node login whether or not TLS is enabled. This mode
* should only be used for testing purposes because it is not secure
* authentication.
* @property {number} AUTH_PKI - Use PKI authentication.
* Authentication and authorization is based on a certificate. No user name or
* password needs to be configured. Requires mTLS and a client certificate.
*
* @example <caption>Using external authentication mode, e.g. to use LDAP authentication</caption>
*
* const Aerospike = require('aerospike')
*
* const config = {
* user: process.env.ADMIN_USER,
* password: process.env.ADMIN_PASSWORD,
* authMode: Aerospike.auth.EXTERNAL
* }
*
*
* @example <caption>Using PKI authentication mode</caption>
*
* const Aerospike = require('aerospike')
*
* const config = {
* hosts: [
* { addr: 'bob-cluster-a', port: process.env.PORT}
* ],
* tls: {
* cafile: process.env.CAFILE,
* keyfile: process.env.KEYFILE,
* certfile: process.env.CERT,
* }
* authMode: Aerospike.auth.AUTH_PKI,
* }
*
*
* Aerospike.connect(config).then(async (client) => {
* const info = await client.infoAny().then(Aerospike.info.parse)
* console.info(info)
* client.close()
* })
*/
exports.auth = as.auth
/**
* @summary Enumeration of UDF types.
*
* @enum {number}
*
* @property {number} LUA - Lua (only supported UDF type at the moment)
*/
exports.language = as.language
/**
* @summary Enumeration of log levels
*
* @enum {number}
*
* @property {number} OFF - Turn off logging
* @property {number} ERROR - Log messages at ERROR level
* @property {number} WARN - Log messages at WARN level or below
* @property {number} INFO - Log messages at INFO level or below
* @property {number} DEBUG - Log messages at DEBUG level or below
* @property {number} TRACE - Log messages at TRACE level or below
*
* @see {@link Config#log} to set the log level for a specific client instance
* @see {@link module:aerospike.setDefaultLogging} to set the global default
* log settings, incl. logging of the Aerospike C client library.
*
* @example <caption>Setting log level for new client</caption>
*
* const Aerospike = require('aerospike')
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* log: { level: Aerospike.log.DEBUG },
* // Timeouts disabled, latency dependent on server location. Configure as needed.
* policies: {
* read : new Aerospike.ReadPolicy({socketTimeout : 0, totalTimeout : 0}),
* write : new Aerospike.WritePolicy({socketTimeout : 0, totalTimeout : 0})
* }
* }
* Aerospike.connect(config, (error, client) => {
* if (error) throw error
* var key = new Aerospike.Key('test', 'demo', 'k1')
* client.put(key, {example: 31}, (error) => {
* if (error) throw error
* client.get(key, (error, record) => {
* console.info(record)
* client.close()
* })
* })
* })
*/
exports.log = as.log
/**
* @summary Enumertion of special TTL (time-to-live) values.
*
* @description Instead of specifying a TTL in seconds, you can set the TTL
* to one of these special values when creating or updating a record.
*
* @enum {number}
*
* @property {number} NAMESPACE_DEFAULT - Use the default TTL value for the
* namespace of the record.
* @property {number} NEVER_EXIRE - Never expire the record.
* @property {number} DONT_UPDATE - Update the record without changing the
* record's TTL value. Requires server 3.10.1 or later.
*
* @example <caption>Use ttl.DONT_UPDATE to change the value of a record
* bin without changing the records expiry time</caption>
*
* const Aerospike = require('aerospike')
* const Key = Aerospike.Key
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* // Timeouts disabled, latency dependent on server location. Configure as needed.
* policies: {
* read : new Aerospike.ReadPolicy({socketTimeout : 0, totalTimeout : 0}),
* write : new Aerospike.WritePolicy({socketTimeout : 0, totalTimeout : 0})
* }
* }
* Aerospike.connect(config, (error, client) => {
* if (error) throw error
* let key = new Key('test', 'demo', 'key1')
* let bins = { 'int': 1 }
* let meta = { ttl: 86400 }
*
* client.put(key, bins, meta, (error) => {
* if (error) throw error
*
* bins = { 'int': 2 }
* meta = { ttl: Aerospike.ttl.DONT_UPDATE }
* client.put(key, bins, meta, (error) => {
* if (error) throw error
*
* client.get(key, (error, record) => {
* if (error) throw error
*
* console.log(record.bins.int) // => 2
* console.log(record.ttl) // => 86400
* client.close()
* })
* })
* })
* })
*/
exports.ttl = as.ttl
/**
* @summary Enumeration of job status codes.
*
* @enum {number}
*
* @property {number} UNDEF - The job status is undefined. This is likely due to the
* status not being properly checked.
* @property {number} INPROGRESS - The job is currently running.
* @property {number} COMPLETED - The job completed successfully.
*
* @see {@link Job#infoCallback} returns the job status.
*/
exports.jobStatus = as.jobStatus
/**
* @summary Enumeration of SI data types.
*
* @enum {number}
*
* @property {number} STRING - Values contained in the SI are strings.
* @property {number} NUMERIC - Values contained in the SI are integers.
* @property {number} GEO2DSPHERE - Values contained in the SI are GeoJSON values (points or polygons).
*
* @see {@link Client#createIndex}
*/
exports.indexDataType = as.indexDataType
/**
* @summary Enumeration of SI types.
*
* @enum {number}
*
* @property {number} DEFAULT - Default SI type for bins
* containing scalar values (i.e. integer, string).
* @property {number} LIST - SI for bins containing
* <a href="http://www.aerospike.com/docs/guide/cdt-list.html" title="Aerospike List Data Type">⇑Lists</a>;
* The index will be built over the individual entries of the list.
* @property {number} MAPKEYS - SI for bins containing
* <a href="http://www.aerospike.com/docs/guide/cdt-map.html" title="Aerospike Maps Data Type">⇑Maps</a>;
* The index will be built over the individual keys of the map entries.
* @property {number} MAPVALUES - SI for bins containing
* <a href="http://www.aerospike.com/docs/guide/cdt-map.html" title="Aerospike Maps Data Type">⇑Maps</a>;
* The index will be built over the individual values of the map entries.
*
* @see {@link Client#createIndex}
*/
exports.indexType = as.indexType
// ========================================================================
// Functions
// ========================================================================
exports.print = require('./utils').print
exports.releaseEventLoop = require('./event_loop').releaseEventLoop
const Client = exports.Client
/**
* Creates a new {@link Client} instance.
*
* @param {Config} [config] - The configuration for the client.
*/
exports.client = function (config) {
return new Client(config)
}
/**
* Creates a new {@link Client} instance and connects to the Aerospike cluster.
*
* @param {Config} [config] - The configuration for the client.
* @param {connectCallback} [callback] - The function to call, once the client is connected to the cluster successfully.
*
* @return {?Promise} If no callback function is passed, the function returns
* a Promise resolving to the connected client.
* @example <caption>Connection can be established using the {@link module:aerospike|aerospike} module.</caption>
*
* const Aerospike = require('aerospike')
*
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* }
*
* Aerospike.connect(config, (err, client) => {
* console.log("Connected. Closing now.")
* client.close()
* })
*
* @example <caption>Connection can also be established using the {@link Client} module.</caption>
*
* const Aerospike = require('aerospike')
*
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* }
*
* const client = Aerospike.client(config)
* client.connect((err) => {
* console.log("Connected. Closing now.")
* client.close()
* })
*
* @example <caption>A connection established using callback function.</caption>
*
* const Aerospike = require('aerospike')
*
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* }
* Aerospike.connect(config, (error, client) => {
* if (error) {
* console.error('Failed to connect to cluster: %s', error.message)
* process.exit()
* } else {
* // client is ready to accept commands
* console.log("Connected. Now closing connection.")
* client.close()
* }
* })
*
* @example <caption>A connection established by returning a Promise.</caption>
*
* const Aerospike = require('aerospike')
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* }
* Aerospike.connect(config)
* .then(client => {
* // client is ready to accept commands
* console.log("Connected. Now Closing Connection.")
* client.close()
* })
* .catch(error => {
* console.error('Failed to connect to cluster: %s', error.message)
* })
*/
exports.connect = function (config, callback) {
if (typeof config === 'function') {
callback = config
config = null
}
const client = this.client(config)
if (typeof callback === 'function') {
client.connect(callback)
return client
} else {
return client.connect()
}
}
/**
* Sets the global, default log level and destination. The default log settings
* are used for all new client instances, unless different log settings are
* supplied in the client's configuration.
*
* The global log settings are also used to control the logging of the Aerospike
* C client SDK which is included in the <code>aerospike</code> native add-on.
* The C client SDK log settings are global and cannot be set separately per
* {@link Client} instance.
*
* @param {Object} log
* @param {Number} [log.level] - Log level; see {@link module:aerospike.log}
* for details.
* @param {Number} [log.file] - File descriptor returned by
* <code>fs.open()</code> or one of <code>process.stdout.fd</code> or
* <code>process.stderr.fd</code>.
*
* @since v3.1.0
*
* @example
*
* const Aerospike = require('aerospike')
*
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* }
*
* Aerospike.setDefaultLogging({
* level: Aerospike.log.TRACE
* })
*
* Aerospike.connect(config, (error, client) => {
* if (error) {
* console.error('Failed to connect to cluster: %s', error.message)
* process.exit()
* } else {
* // client is ready to accept commands
* console.log("Connected. Now closing connection.")
* client.close()
* }
* })
*/
exports.setDefaultLogging = function (logInfo) {
as.setDefaultLogging(logInfo)
}
/**
* @summary Configures the global command queue. (Disabled by default.)
*
* @description Note that there is only one instance of the command queue that
* is shared by all client instances, even client instances connected to
* different Aerospike clusters. The <code>setupGlobalCommandQueue</code>
* method must be called before any client instances are connected.
*
* @param {CommandQueuePolicy} policy - Set of policy values governing the
* behaviour of the global command queue.
*
* @see {@link CommandQueuePolicy} for more information about the use of the
* command queue.
*/
exports.setupGlobalCommandQueue = function (policy) {
EventLoop.setCommandQueuePolicy(policy)
}
/**
* The {@link module:aerospike/batchType|aerospike/batch_type}
* module contains a list of batch record types.
*
* @summary {@link module:aerospike/batchType|aerospike/batch_type} module
*/
exports.batchType = require('./batch_type')
/**
* The {@link module:aerospike/privilegeCode|aerospike/privilege_code}
* module is comprised of permission codes which define the type of
* permission granted for a user's role.
*
* @summary {@link module:aerospike/privilegeCode|aerospike/privilege_code} module
*/
exports.privilegeCode = require('./privilege_code')
// Set default log level
as.setDefaultLogging({
level: as.log.WARN,
file: process.stderr.fd
})