UNPKG

aerospike

Version:
1,441 lines (1,395 loc) 676 kB
import * as Buffer from "buffer"; import { EventEmitter, Stream } from "stream"; /** * Codes representing each of the various scalar operation types. */ export enum ScalarOperations { /** * Write operation code. */ WRITE, /** * Read operation code. */ READ, /** * Increment operation code. */ INCR, /** * Prepend operation code. */ PREPEND, /** * Append operation code. */ APPEND, /** * Touch operation code. */ TOUCH, /** * Delete operation code. */ DELETE } /* TYPES */ /** * Represents a basic value in an Aerospike bin. */ export type PartialAerospikeBinValue = null | undefined | boolean | string | number | Double | BigInt | Buffer | GeoJSON | Array<PartialAerospikeBinValue> | object; /** * Represents an object containing one or more `AerospikeBinValues` with associated string keys. */ export type AerospikeBins = { [key: string]: AerospikeBinValue }; export const _transactionPool: any; /** * Represents a complete Aerospike bin value. Bin values can included nested lists and maps. */ export type AerospikeBinValue = PartialAerospikeBinValue | PartialAerospikeBinValue[] | Record<string, PartialAerospikeBinValue>; /** * Represents an Aerospike Expression. Contains an op number which specifiies the operation type, and properties with values relevant to the operation. */ export type AerospikeExp = { op: number, [key: string]: any }[] /** * Contains geolocation information releavant to the GEOJSON Aerospike type. */ export type GeoJSONType = { type: string, coordinates: NumberArray } /** * Represents an array which can contain number or nested number array. */ export type NumberArray = number | NumberArray[]; /** * Callback used to return results in synchronous Aerospike database commands */ export type TypedCallback<T> = (error?: AerospikeError, result?: T) => void; /* CLASSES */ /** * A record with the Aerospike database consists of one or more record "bins" * (name-value pairs) and meta-data, including time-to-live and generation; a * record is uniquely identified by it's key within a given namespace. * * @example <caption>Writing a new record with 5 bins while setting a record TTL.</caption> * * const Aerospike = require('aerospike') * * // 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: { * write : new Aerospike.WritePolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * let bins = { * int: 123, * double: 3.1415, * string: 'xyz', * bytes: Buffer.from('hello world!'), * list: [1, 2, 3], * map: {num: 123, str: 'abc', list: ['a', 'b', 'c']} * } * let meta = { * ttl: 386400 // 1 day * } * let key = new Aerospike.Key('test', 'demo', 'myKey') * * Aerospike.connect(config) * .then(client => { * return client.put(key, bins, meta) * .then(() => { * client.get(key) * .then((record) => { * console.log(record) * client.close() * }) * .catch(error => { * console.log(record) * client.close() * return Promise.reject(error) * }) * }) * .catch(error => { * client.close() * return Promise.reject(error) * }) * }) * .catch(error => console.error('Error:', error)) * * @example <caption>Fetching a single database record by it's key.</caption> * * const Aerospike = require('aerospike') * * // 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}), * } * } * * let key = new Aerospike.Key('test', 'demo', 'myKey') * * Aerospike.connect(config) * .then(client => { * client.put(key, {tags : ['blue', 'pink']}) * .then(() => { * client.get(key) * .then(record => { * console.info('Key:', record.key) * console.info('Bins:', record.bins) * console.info('TTL:', record.ttl) * console.info('Gen:', record.gen) * }) * .then(() => client.close()) * .catch(error => { * client.close() * return Promise.reject(error) * }) * }) * .catch(error => { * client.close() * return Promise.reject(error) * }) * }) * .catch(error => console.error('Error:', error)) * * @since v5.0.0 * * @example <caption>Fetching a batch of records.</caption> * * const Aerospike = require('aerospike') * const op = Aerospike.operations * // 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}), * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}) * * } * } * * var batchRecords = [ * { type: Aerospike.batchType.BATCH_READ, * key: new Aerospike.Key('test', 'demo', 'key1'), bins: ['i', 's'] }, * { type: Aerospike.batchType.BATCH_READ, * key: new Aerospike.Key('test', 'demo', 'key2'), readAllBins: true }, * { type: Aerospike.batchType.BATCH_READ, * key: new Aerospike.Key('test', 'demo', 'key3'), * ops:[ * op.read('blob-bin') * ]} * ] * Aerospike.connect(config, function (error, client) { * if (error) throw error * client.batchRead(batchRecords, function (error, results) { * if (error) throw error * results.forEach(function (result) { * console.log(result) * * }) * client.close() * }) * * }) * * @since v5.0.0 * * @example <caption>Applying functions on batch of records.</caption> * * const Aerospike = require('aerospike') * * // 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}), * * } * } * * const batchType = Aerospike.batchType * var batchRecords = [ * { type: batchType.BATCH_READ, * key: new Aerospike.Key('test', 'demo', 'key1'), * bins: ['i', 's'] }, * { type: batchType.BATCH_READ, * key: new Aerospike.Key('test', 'demo', 'key2'), * readAllBins: true }, * { type: batchType.BATCH_APPLY, * key: new Aerospike.Key('test', 'demo', 'key4'), * policy: new Aerospike.BatchApplyPolicy({ * filterExpression: exp.eq(exp.binInt('i'), exp.int(37)), * key: Aerospike.policy.key.SEND, * commitLevel: Aerospike.policy.commitLevel.ALL, * durableDelete: true * }), * udf: { * module: 'udf', * funcname: 'function1', * args: [[1, 2, 3]] * } * }, * { type: batchType.BATCH_APPLY, * key: new Aerospike.Key('test', 'demo', 'key5'), * policy: new Aerospike.BatchApplyPolicy({ * filterExpression: exp.eq(exp.binInt('i'), exp.int(37)), * key: Aerospike.policy.key.SEND, * commitLevel: Aerospike.policy.commitLevel.ALL, * durableDelete: true * }), * udf: { * module: 'udf', * funcname: 'function2', * args: [[1, 2, 3]] * } * } * ] * Aerospike.connect(config, function (error, client) { * if (error) throw error * client.batchApply(batchRecords, udf, function (error, results) { * if (error) throw error * results.forEach(function (result) { * console.log(result) * }) * }) * }) */ export class AerospikeRecord { /** * Unique record identifier. * * @type {Key} */ public key: Key; /** * Map of bin name to bin value. * * @type {AerospikeBins} */ public bins: AerospikeBins; /** * The record's remaining time-to-live in seconds before it expires. * * @type {number} */ public ttl: number; /** * Record modification count. * * @type {number} */ public gen: number; /** * Construct a new Aerospike Record instance. */ constructor(key: KeyOptions, bins: AerospikeBins, metadata?: RecordMetadata); } /** * Transaction class. Each command in a transaction must use the same namespace. * * note: By default, open transactions are destroyed when the final client in a process is closed. * If you need your transaction to persist after the last client has been closed, provide `false` for the * destroy Transactions argument in {@link Client#close}. For more information on memory management, see {@link Transaction.destroyAll}. * * @example <caption>Commit a simple transaction.</caption> * * const Aerospike = require('aerospike') * * // 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: { * write : new Aerospike.WritePolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * let bins = { * int: 123, * double: 3.1415, * string: 'xyz', * bytes: Buffer.from('hello world!'), * list: [1, 2, 3], * map: {num: 123, str: 'abc', list: ['a', 'b', 'c']} * } * let meta = { * ttl: 386400 // 1 day * } * let key = new Aerospike.Key('test', 'demo', 'myKey') * * let policy = { * txn: tran * }; * ;(async () => { * let client = await Aerospike.connect(config) * let tran = new Aerospike.Transaction() * * * await client.put(key, bins, meta, policy) * * let get_result = await client.get(key1, policy) * * let result = await client.commit(tran) * await client.close() * })(); * * @example <caption>Abort a transaction.</caption> * * const Aerospike = require('aerospike') * * // 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}), * } * } * * let key1 = new Aerospike.Key('test', 'demo', 'myKey') * let key2 = new Aerospike.Key('test', 'demo', 'myKey') * * let record1 = {abc: 123} * let record2 = {def: 456} * * ;(async () => { * let client = await Aerospike.connect(config) * * const policy = { * txn: tran * } * * await client.put(key4, record2, meta, policy) * * const policyRead = { * txn: tran * } * * let get_result = await client.get(key1, policy) // Will reflect the new value recently put. * * await client.put(key2, record2, meta, policy) * * let result = await client.abort(tran) * * get_result = await client.get(key4) // Will reset to the value present before transaction started. * * get_result = await client.get(key5) // Will reset to the value present before transaction started. * * await client.close() * })(); * * @since v6.0.0 */ export class Transaction { /** * Construct a new Aerospike Transaction instance. */ public constructor(reads_capacity?: number, writes_capacity?: number); /** * Transaction state enumeration */ static state: { /** * Transaction is still open. */ OPEN: 0, /** * Transaction was verified. */ VERIFIED: 1, /** * Transaction was commited. */ COMMITTED: 2, /** * Transaction was aborted. */ ABORTED: 3 }; /** * Default Transaction capacity values. */ static capacity: { /** * Contains the default reeadDefault for aerospike.Transaction */ READ_DEFAULT: 128, /** * Contains the default writeCapacity for aerospike.Transaction */ WRITE_DEFAULT: 128, }; /** * Transaction abort status code. */ static abortStatus: { /** * Abort succeeded. */ OK: 0, /** * Transaction has already been aborted. */ ALREADY_ABORTED: 1, /** * Client roll back abandoned. Server will eventually abort the transaction. */ ROLL_BACK_ABANDONED: 2, /** * Transaction has been rolled back, but client transaction close was abandoned. * Server will eventually close the transaction. */ CLOSE_ABANDONED: 3 }; /** * Transaction commit status code. */ static commitStatus: { /** * Commit succeeded. */ OK: 0, /** * Transaction has already been committed. */ ALREADY_COMMITTED: 1, /** * Transaction verify failed. Transaction will be aborted. */ VERIFY_FAILED: 2, /** * Transaction mark roll forward abandoned. Transaction will be aborted when error is not in doubt. * If the error is in doubt (usually timeout), the commit is in doubt. */ MARK_ROLL_FORWARD_ABANDONED: 3, /** * Client roll forward abandoned. Server will eventually commit the transaction. */ ROLL_FORWARD_ABANDONED: 4, /** * Transaction has been rolled forward, but client transaction close was abandoned. * Server will eventually close the transaction. */ CLOSE_ABANDONED: 5 }; private prepareToClose(): void; private close(): void; /** * Destroys all open transactions * * @remarks * * Use of this API is only necessary when the client is closed with * the destroyTransactions parameter set is set to false. * See example below for usage details. * * To avoid using this API, close the final connected client in the process * with destroyTransactions set to true (default is true), and the transaction will be destroyed automatically. * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * let tran1 = new Aerospike.Transaction() * let client = await Aerospike.connect(config) * client.close(false, true) // `destroyTransactions is true`, tran1 is no longer usable. * * let tran2 = new Aerospike.Transaction() * client = await Aerospike.connect(config) * client.close(false, true) // `destroyTransactions is false`, tran2 can still be used. * * // In order to properly manage the memory at this point, do one of two things before the process exits: * * // 1: call destroyAll() to destroy all outstanding transactions from this process. * tran1.destroyAll() * * // 2: reopen and close the final connected client with destroyTransactions * // client = await Aerospike.connect(config) * // client.close() // Default will destory the transactions * * })(); * * @since v6.0.0 */ public destroyAll(): void; /** * Get ID for this transaction * * @returns Transaction ID * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let id = tran.getId() * })(); * * @since v6.0.0 */ public getId(): number; /** * Get inDoubt status for this transaction. * * @returns Transaction inDoubt status * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let inDoubt = tran.getInDoubt() * })(); * * @since v6.0.0 */ public getInDoubt(): boolean; /** * * Gets the expected number of record reads in the Transaction. Minimum value is 16. * * @returns number of records reads in the Transaction. * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let readsCapacity = tran.getReadsCapacity() * console.log(readsCapacity) // 128 * })(); * * @since v6.0.0 */ public getReadsCapacity(): number; /** * * Gets the current state of the Transaction. * * @returns Transaction timeout in seconds * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let state = tran.getState() * * })(); * */ public getState(): number; /** * * Gets the current Transaction timeout value. * * @returns Transaction timeout in seconds * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let timeout = tran.getTimeout() * })(); * * @since v6.0.0 */ public getTimeout(): number; /** * * Gets the expected number of record reads in the tran. Minimum value is 16. * * @returns number of records reads in the tran. * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * let writesCapacity = tran.getWritesCapacity() * console.log(writesCapacity) // 128 * })(); * * @since v6.0.0 */ public getWritesCapacity(): number; /** * * Set transaction timeout in seconds. The timer starts when the transaction monitor record is created. This occurs when the first command in the transaction is executed. * * If the timeout is reached before a commit or abort is called, the server will expire and rollback the transaction. * * If the transaction timeout is zero, the server configuration mrt-duration is used. The default mrt-duration is 10 seconds. * * Default Client transaction timeout is 0. * * @param timeout - Transaction timeout in seconds * * @example * * 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: { * batch : new Aerospike.BatchPolicy({socketTimeout : 0, totalTimeout : 0}), * } * } * * ;(async () => { * // Establishes a connection to the server * let tran = new Aerospike.Transaction() * tran.setTimeout(5) // Set timeout for 5 seconds! * * console.log(tran.getTimeout()) // 5 * })(); * */ public setTimeout(timeout: number): void; } /** * 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). The major difference * between bins and RDBMS columns is that you don't need to define a schema. Each record can * have multiple bins. Bins accept the data types listed {@link https://docs.aerospike.com/apidocs/nodejs/#toc4__anchor|here}. * * For information about these data types and how bins support them, see {@link https://docs.aerospike.com/server/guide/data-types/scalar-data-types|this}. * * Although the bin for a given record or object must be typed, bins in different rows do not * have to be the same type. There are some internal performance optimizations for single-bin namespaces. * */ export class Bin { /** * Construct a new Aerospike Bin instance. */ public constructor(name: string, value: AerospikeBinValue, mapOrder?: maps.order); /** * Bin name. */ name: string; /** * Bin name. */ value: AerospikeBinValue; } export class BatchResult { /** * Construct a new BatchResult instance. */ public constructor(status: typeof statusNamespace[keyof typeof statusNamespace], record: AerospikeRecord, inDoubt: boolean); /** * Result code for this returned record. If not {@link statusNamespace.AEROSPIKE_OK|AEROSPIKE_OK}, the record will be null. */ status: typeof statusNamespace[keyof typeof statusNamespace]; /** * Record result for the requested key. This record will only be populated when the result is * {@link statusNamespace.AEROSPIKE_OK|AEROSPIKE_OK} or {@link statusNamespace.AEROSPIKE_ERR_UDF|AEROSPIKE_ERR_UDF}. */ record: AerospikeRecord; /** * It is possible that a write command completed even though the client * returned this error. This may be the case when a client error occurs * (like timeout) after the command was sent to the server. */ inDoubt: boolean; } /** * Aerospike Query commands perform value-based searches using * secondary indexes (SI). A Query object, created by calling {@link Client#query}, * is used to execute queries on the specified namespace and set (optional). * Queries can return a set of records as a {@link RecordStream} or be * processed using Aeorspike User-Defined Functions (UDFs) before returning to * the client. * * For more information, please refer to the section on * <a href="http://www.aerospike.com/docs/guide/query.html" title="Aerospike Queries">&uArr;Queries</a> * in the Aerospike technical documentation. * * To scan _all_ records in a database namespace or set, it is more efficient * to use {@link Scan.operate}, which provide more fine-grained control over * execution priority, concurrency, etc. * * #### SI Filters * * With a SI, the following queries can be made: * * - [Equal query]{@link filter.equal} against string or * numeric indexes * - [Range query]{@link filter.range} against numeric * indexes * - [Point-In-Region query]{@link filter.geoWithinGeoJSONRegion} * or [Region-Contain-Point query]{@link filter.geoContainsGeoJSONPoint} against geo indexes * * See {@link filter} for a list of all supported secondary * index filter. * * Before a secondary index filter can be applied, a SI needs to be * created on the bins which the index filter matches on. Using the Node.js * client, a SI can be created using {@link Client#createIndex}. * * Currently, only a single SI index filter is supported for * each query. To do more advanced filtering, a expressions can be * applied to the query using policy (see below). Alternatively, User-Defined Functions * (UDFs) can be used to further process the query results on the server. * * Previously, predicate filtering was used to perform secondary index queries. * SI filter predicates have been deprecated since server 5.2, and obsolete since * server 6.0. * * For more information about Predicate Filtering, please refer to the <a * href="https://www.aerospike.com/docs/guide/predicate.html">&uArr;Predicate * Filtering</a> documentation in the Aerospike Feature Guide. * * #### Selecting Bins * * Using {@link Query#select} it is possible to select a subset of bins which * should be returned by the query. If no bins are selected, then the whole * record will be returned. If the {@link Query#nobins} property is set to * <code>true</code> the only the record meta data (ttl, generation, etc.) will * be returned. * * #### Executing a Query * * A query is executed using {@link Query#foreach}. The method returns a {@link * RecordStream} which emits a <code>data</code> event for each record returned * by the query. The query can be aborted at any time by calling * {@link RecordStream#abort}. * * #### Applying User-Defined Functions * * User-defined functions (UDFs) can be used to filter, transform, and * aggregate query results. Stream UDFs can process a stream of data by * defining a sequence of operations to perform. Stream UDFs perform read-only * operations on a collection of records. Use {@link Query#setUdf} to set the * UDF parameters (module name, function name and optional list of arguments) * before executing the query using {@link Query#foreach}. * * The feature guides on * <a href="http://www.aerospike.com/docs/guide/udf.html">&uArr;User-Defined Functions</a> and * <a href="http://www.aerospike.com/docs/guide/stream_udf.html">&uArr;Stream UDFs</a> * contain more detailed information and examples. * * #### Query Aggregation using Stream UDFs * * Use Aerospike Stream UDFs to aggregate query results using {@link * Query#apply}. Aggregation queries work similar to a MapReduce system and * return a single result value instead of stream of records. Aggregation * results can be basic data types (string, number, byte array) or collection * types (list, map). * * Please refer to the technical documentation on * <a href="http://www.aerospike.com/docs/guide/aggregation.html">&uArr;Aggregation</a> * for more information. * * #### Executing Record UDFs using Background Queries * * Record UDFs perform operations on a single record such as updating records * based on a set of parameters. Using {@link Query#background} you can run a * Record UDF on the result set of a query. Queries using Records UDFs are run * in the background on the server and do not return the records to the client. * * For additional information please refer to the section on * <a href="http://www.aerospike.com/docs/guide/record_udf.html">&uArr;Record UDFs</a> * in the Aerospike technical documentation. * * #### Query pagination * * Query pagination allows for queries return records in pages rather than all at once. * To enable query pagination, the query property {@link paginate} must be true * and the previously stated query property {@link Query.maxRecords} must be set to a * nonzero positive integer in order to specify a maximum page size. * * When a page is complete, {@link RecordStream} event {@link RecordStream#on 'error'} will * emit a {@link Query#queryState} object containing a serialized version of the query. * This serialized query, if be assigned back to {@link Query#queryState}, allows the query * to retrieve the next page of records in the query upon calling {@link Query#foreach}. * If {@link Query#queryState} is undefined, pagination is not enabled or the query has completed. * If {@link RecordStream#on 'error'} emits an <code>undefined</code> object, either {@link paginate} * is not <code>true</code>, or the query has successfully returned all the specified records. * * For additional information and examples, please refer to the {@link paginate} section * below. * * @see {@link Client#query} to create new instances of this class. * * @example * * const Aerospike = require('aerospike') * const namespace = 'test' * const set = 'demo' * * Aerospike.connect((error, client) => { * if (error) throw error * var index = { * ns: namespace, * set: set, * bin: 'tags', * index: 'tags_idx', * type: Aerospike.indexType.LIST, * datatype: Aerospike.indexDataType.STRING * } * client.createIndex(index, (error, job) => { * if (error) throw error * job.waitUntilDone((error) => { * if (error) throw error * * var query = client.query('test', 'demo') * const queryPolicy = { filterExpression: exp.keyExist('uniqueExpKey') } * query.select('id', 'tags') * query.where(Aerospike.filter.contains('tags', 'green', Aerospike.indexType.LIST)) * var stream = query.foreach(queryPolicy) * stream.on('error', (error) => { * console.error(error) * throw error * }) * stream.on('data', (record) => { * console.info(record) * }) * stream.on('end', () => { * client.close() * }) * }) * }) * }) */ export class Query { /** * Aerospike Client Instance */ public client: Client; /** * Namespace to query. */ public ns: string; /** * Name of the set to query. */ public set: string; /** * Filters to apply to the query. * * *Note:* Currently, a single index filter is supported. To do more * advanced filtering, you need to use a user-defined function (UDF) to * process the result set on the server. */ public filters: filter.SindexFilterPredicate[]; /** * List of bin names to be selected by the query. If a query specifies bins to * be selected, then only those bins will be returned. If no bins are * selected, then all bins will be returned (unless {@link Query#nobins} is * set to `true`). */ public selected: string[]; /** * If set to `true`, the query will return only meta data, and exclude bins. */ public nobins: boolean; /** * User-defined function parameters to be applied to the query executed using * {@link Query#foreach}. */ public udf: UDF; /** * Approximate number of records to return to client. * * When {@link paginate} is <code>true</code>, * then maxRecords will be the page size if there are enough records remaining in the query to fill the page size. * * When {@link paginate} is <code>false</code>, this number is divided by the number of nodes involved in the scan, * and actual number of records returned may be less than maxRecords if node record counts are small and unbalanced across nodes. */ public maxRecords?: number; /** * Specifies operations to be executed when {@link operate} is called. */ public ops?: operations.Operation[]; /** * If set to <code>true</code>, paginated queries are enabled. In order to receive paginated * results, the {@link maxRecords} property must assign a nonzero integer value. * * @example <caption>Asynchronous pagination over a set of thirty records with {@link Query#foreach}.</caption> * * const Aerospike = require('./lib/aerospike'); * // Define host configuration * let config = { * hosts: '34.213.88.142:3000', * policies: { * batchWrite : new Aerospike.BatchWritePolicy({socketTimeout : 0, totalTimeout : 0}), * } * }; * * var batchRecords = [] * for(let i = 0; i < 30; i++){ * batchRecords.push({ * type: Aerospike.batchType;.BATCH_WRITE, * key: new Aerospike.Key('test', 'demo', 'key' + i), * ops:[Aerospike.operations.write('exampleBin', i)] * }) * } * * ;(async function() { * try { * client = await Aerospike.connect(config) * await client.truncate('test', 'demo', 0) * await client.batchWrite(batchRecords, {socketTimeout : 0, totalTimeout : 0}) * * const query = client.query('test', 'demo', { paginate: true, maxRecords: 10}) * do { * const stream = query.foreach() * stream.on('error', (error) => { throw error }) * stream.on('data', (record) => { * console.log(record.bins) * }) * await new Promise(resolve => { * stream.on('end', (queryState) => { * query.queryState = queryState * resolve() * }) * }) * } while (query.queryState !== undefined) * * } catch (error) { * console.error('An error occurred at some point.', error) * process.exit(1) * } finally { * if (client) client.close() * } * })() * * @example <caption>Asynchronous pagination over a set of thirty records with {@link Query#results}</caption> * * * const Aerospike = require('./lib/aerospike'); * // Define host configuration * let config = { * hosts: '34.213.88.142:3000', * policies: { * batchWrite : new Aerospike.BatchWritePolicy({socketTimeout : 0, totalTimeout : 0}), * } * }; * * var batchRecords = [] * for(let i = 0; i < 30; i++){ * batchRecords.push({ * type: Aerospike.batchType.BATCH_WRITE, * key: new Aerospike.Key('test', 'demo', 'key' + i), * ops:[Aerospike.operations.write('exampleBin', i)] * }) * } * * * ;(async function() { * try { * client = await Aerospike.connect(config) * await client.truncate('test', 'demo', 0) * await client.batchWrite(batchRecords, {socketTimeout : 0, totalTimeout : 0}) * * const query = client.query('test', 'demo', { paginate: true, maxRecords: 11}) * * let allResults = [] * let results = await query.results() * allResults = [...allResults, ...results] * * * results = await query.results() * allResults = [...allResults, ...results] * * results = await query.results() * allResults = [...allResults, ...results] * * console.log("Records returned in total: " + allResults.length) // Should be 30 records * } catch (error) { * console.error('An error occurred at some point.', error) * process.exit(1) * } finally { * if (client) client.close() * } * })() * */ public paginate?: boolean; /** * Used when querying partitions to manage the query. For internal use only. */ public partFilter?: PartFilter; /** * If set to <code>true</code>, the query will return records belonging to the partitions specified * in {@link Query#partFilter}. */ public pfEnabled?: boolean; /** * The time-to-live (expiration) of the record in seconds. * * There are also special values that can be set in the record TTL For details * * Note that the TTL value will be employed ONLY on background query writes. */ public ttl: number; /** * If set to a valid serialized query, calling {@link Query.foreach} will allow the next page of records to be queried while preserving the progress * of the previous query. If set to <code>null</code>, calling {@link Query.foreach} will begin a new query. */ public queryState?: number[]; /** * Construct a Query instance. * * @param client - A client instance. * @param ns - The namescape. * @param set - The name of a set. * @param options - Query options. * * */ constructor(client: Client, ns: string, set: string, options?: QueryOptions | null); /** * * Checks compiliation status of a paginated query. * * If <code>false</code> is returned, there are no more records left in the query, and the query is complete. * If <code>true</code> is returned, calling {@link Query#foreach} will continue from the state specified by {@link Query#queryState}. * * @returns `true` if another page remains. */ public hasNextPage(): boolean; /** * Sets {@link Query#queryState} to the value specified by the <code>state</code> argument. * * setter function for the {@link Query#queryState} member variable. * * @param state - serialized query emitted from the {@link RecordStream#on 'error'} event. */ public nextPage(state: number[]): void; /** * Specify the begin and count of the partitions * to be queried by the Query foreach op. * * If a Query specifies partitions begin and count, * then only those partitons will be queried and returned. * If no partitions are specified, * then all partitions will be queried and returned. * * @param begin - Start partition number to query. * @param count - Number of partitions from the start to query. * @param digest - Start from this digest if it is specified. */ public partitions(begin: number, count: number, digest?: Buffer | null): void; /** * Specify the names of bins to be selected by the query. * * If a query specifies bins to be selected, then only those bins * will be returned. If no bins are selected, then all bins will be returned. * (Unless {@link Query.nobins} is set to <code>true</code>.) * * @param bins - List of bin names or multiple bin names to return. * @return {void} */ public select(bins: string[]): void; /** * * @param bins - A spread of bin names to return. * @return {void} */ public select(...bins: string[]): void; /** * Applies a SI to the query. * * Use a SI to limit the results returned by the query. * This method takes SI created using the {@link * filter | filter module} as argument. * * @param predicate - The index filter to * apply to the function. * * @example <caption>Applying a SI filter to find all records * where the 'tags' list bin contains the value 'blue':</caption> * * const Aerospike = require('aerospike') * * Aerospike.connect().then(client => { * let query = client.query('test', 'demo') * * let tagsFilter = Aerospike.filter.contains('tags', 'blue', Aerospike.indexType.LIST) * query.where(tagsFilter) * * let stream = query.foreach() * stream.on('data', record => { console.info(record.bins.tags) }) * stream.on('error', error => { throw error }) * stream.on('end', () => client.close()) * }) * * @see {@link filter} to create SI filters. */ public where(predicate: filter.SindexFilterPredicate): void; private setSindexFilter(sindexFilter: filter.SindexFilterPredicate): void; /** * * Set user-defined function parameters to be applied to the query. * * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. */ public setUdf(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null): void; /** * Asynchronously executes the query and returns each result item * through the stream. * * *Applying a Stream UDF to the query results* * * A stream UDF can be applied to the query to filter, transform and aggregate * the query results. The UDF parameters need to be set on the query object * using {@link Query#setUdf} before the query is executed. * * If a UDF is applied to the query, the resulting stream will return * the results of the UDF stream function. Record meta data and the record keys * will not be returned. * * For aggregation queries that return a single result value instead of a * stream of values, you should use the {@link Query#apply} method instead. * * @param policy - The Query Policy to use for this command. * @param dataCb - The function to call when the * command completes with the results of the command; if no callback * function is provided, the method returns a <code>Promise<code> instead. * @param errorCb - Callback function called when there is an error. * @param endCb - Callback function called when an operation has completed. * * @returns {@link RecordStream} */ public foreach(policy?: policy.QueryPolicy | null, dataCb?: (data: AerospikeRecord) => void, errorCb?: (error: Error) => void, endCb?: () => void): RecordStream; /** * Executes the query and collects the results into an array. On paginated queries, * preparing the next page is also handled automatically. * * * This method returns a Promise that contains the query results * as an array of records, when fulfilled. It should only be used if the query * is expected to return only few records; otherwise it is recommended to use * {@link Query.foreach}, which returns the results as a {@link RecordStream} * instead. * * If pagination is enabled, the data emitted from the {@link RecordStream#on 'error'} * event will automatically be assigned to {@link Query.queryState}, allowing the next page * of records to be queried if {@link Query.foreach} or {@link Query.results} is called. * * * @param policy - The Query Policy to use for this command. * * @returns A promise that resolves with an Aerospike Record. */ public results(policy?: policy.QueryPolicy | null): Promise<AerospikeRecord[]>; /** * Applies a user-defined function (UDF) to aggregate the query results. * * The aggregation function is called on both server and client (final reduce). Therefore, the Lua script files must also reside on both server and client. * * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param policy - The Query Policy to use for this command. * * @returns A promise that resolves with an Aerospike bin value. * */ public apply(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, policy?: policy.QueryPolicy | null): Promise<AerospikeBinValue>; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param callback - The function to call when the command completes. * */ public apply(udfModule: string, udfFunction: string, callback: TypedCallback<AerospikeBinValue>): void; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param callback - The function to call when the command completes. * */ public apply(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, callback?: TypedCallback<AerospikeBinValue>): void; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param policy - The Query Policy to use for this command. * @param callback - The function to call when the command completes. * */ public apply(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[], policy?: policy.QueryPolicy | null, callback?: TypedCallback<AerospikeBinValue>): void; /** * Applies a user-defined function (UDF) on records that match the query filter. * Records are not returned to the client. * * When a background query is initiated, the client will not wait * for results from the database. Instead a {@link Job} instance will be * returned, which can be used to query the query status on the database. * * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param policy - The Write Policy to use for this command. * @param queryID - Job ID to use for the query; will be assigned * randomly if zero or undefined. * * @returns Promise that resolves to a {@link Job} instance. */ public background(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, policy?: policy.WritePolicy | null, queryID?: number | null): Promise<Job>; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param callback - The function to call when the command completes. * */ public background(udfModule: string, udfFunction: string, callback: TypedCallback<Job>): void; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param callback - The function to call when the command completes. * */ public background(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, callback?: TypedCallback<Job>): void; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param policy - The Write Policy to use for this command. * @param callback - The function to call when the command completes. * */ public background(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, policy?: policy.WritePolicy | null, callback?: TypedCallback<Job>): void; /** * @param udfModule - UDF module name. * @param udfFunction - UDF function name. * @param udfArgs - Arguments for the function. * @param policy - The Write Policy to use for this command. * @param queryID - Job ID to use for the query; will be assigned * randomly if zero or undefined. * @param callback - The function to call when the command completes. * */ public background(udfModule: string, udfFunction: string, udfArgs?: AerospikeBinValue[] | null, policy?: policy.WritePolicy | null, queryID?: number | null, callback?: TypedCallback<Job> | null): void; /** * Applies write operations to all matching records. * * Performs a background query and applies one or more write * operations to all records that match the query filter(s). Neither the * records nor the results of the operations are returned to the client. * Instead a {@link Job} instance will be returned, which can be used to query * the query status. * * This method requires server >= 3.7.0. * * @param operations - List of write * operations to perform on the matching records. * @param policy - The Query Policy to use for this command. * @param queryID - Job ID to use for the query; will be assigned * randomly if zero or undefined. * * @returns Promise that resolves to a Job instance. * * @since v3.14.0 * * @example <caption>Increment count