UNPKG

couchbase

Version:

The official Couchbase Node.js Client Library.

1,210 lines 71 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Collection = void 0; const binarycollection_1 = require("./binarycollection"); const binding_1 = __importStar(require("./binding")); const bindingutilities_1 = require("./bindingutilities"); const crudoptypes_1 = require("./crudoptypes"); const datastructures_1 = require("./datastructures"); const errors_1 = require("./errors"); const generaltypes_1 = require("./generaltypes"); const observability_1 = require("./observability"); const observabilityhandler_1 = require("./observabilityhandler"); const observabilitytypes_1 = require("./observabilitytypes"); const queryindexmanager_1 = require("./queryindexmanager"); const rangeScan_1 = require("./rangeScan"); const sdspecs_1 = require("./sdspecs"); const sdutils_1 = require("./sdutils"); const streamablepromises_1 = require("./streamablepromises"); const utilities_1 = require("./utilities"); /** * Exposes the operations which are available to be performed against a collection. * Namely the ability to perform KV operations. * * @category Core */ class Collection { /** * @internal */ static get DEFAULT_NAME() { return '_default'; } /** @internal */ constructor(scope, collectionName) { this._scope = scope; this._name = collectionName; this._conn = scope.conn; this._kvScanTimeout = 75000; this._scanBatchByteLimit = 15000; this._scanBatchItemLimit = 50; } /** @internal */ get conn() { return this._conn; } /** @internal */ get cluster() { return this._scope.bucket.cluster; } /** @internal */ get scope() { return this._scope; } /** @internal */ get transcoder() { return this._scope.transcoder; } /** * @internal */ get observabilityInstruments() { return this._scope.bucket.cluster.observabilityInstruments; } /** @internal */ _mutationTimeout(durabilityLevel) { if (durabilityLevel !== undefined && durabilityLevel !== null && durabilityLevel !== generaltypes_1.DurabilityLevel.None) { return this.cluster.kvDurableTimeout; } return this.cluster.kvTimeout; } /** * @internal */ _cppDocId(key) { return { bucket: this.scope.bucket.name, scope: this.scope.name || '_default', collection: this.name || '_default', key: key, }; } /** * @internal */ _encodeDoc(transcoder, value, callback) { try { const [bytesBuf, flagsOut] = transcoder.encode(value); callback(null, bytesBuf, flagsOut); } catch (e) { return callback(e, Buffer.alloc(0), 0); } } /** * @internal */ _decodeDoc(transcoder, bytes, flags, callback) { try { const content = transcoder.decode(bytes, flags); callback(null, content); } catch (e) { return callback(e, null); } } /** * @internal */ _subdocEncode(value) { return Buffer.from(value); } /** * @internal */ _subdocDecode(bytes) { try { return JSON.parse(bytes.toString('utf8')); } catch (_e) { // If we encounter a parse error, assume that we need // to return bytes instead of an object. return bytes; } } /** * The name of the collection this Collection object references. */ get name() { return this._name; } /** * Retrieves the value of a document from the collection. * * @param key The document key to retrieve. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ get(key, options, callback) { if (options instanceof Function) { callback = arguments[1]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Get, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); obsReqHandler.setRequestKeyValueAttributes(cppDocId); if (options.project || options.withExpiry) { options.parentSpan = obsReqHandler.wrappedSpan; return this._projectedGet(key, options, obsReqHandler, callback); } const transcoder = options.transcoder || this.transcoder; const timeout = options.timeout || this.cluster.kvTimeout; return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.get.bind(this._conn), { id: cppDocId, timeout, partition: 0, opaque: 0, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } const content = transcoder.decode(resp.value, resp.flags); obsReqHandler.end(); return new crudoptypes_1.GetResult({ content: content, cas: resp.cas, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } _projectedGet(key, options, obsReqHandler, callback) { let expiryStart = -1; let projStart = -1; let paths = []; let spec = []; let needReproject = false; if (options.withExpiry) { expiryStart = spec.length; spec.push(sdspecs_1.LookupInSpec.get(sdspecs_1.LookupInMacro.Expiry)); } projStart = spec.length; if (!options.project) { paths = ['']; spec.push(sdspecs_1.LookupInSpec.get('')); } else { let projects = options.project; if (!Array.isArray(projects)) { projects = [projects]; } for (let i = 0; i < projects.length; ++i) { paths.push(projects[i]); spec.push(sdspecs_1.LookupInSpec.get(projects[i])); } } // The following code relies on the projections being // the last segment of the specs array, this way we handle // an overburdened operation in a single area. if (spec.length > 16) { spec = spec.splice(0, projStart); spec.push(sdspecs_1.LookupInSpec.get('')); needReproject = true; } return utilities_1.PromiseHelper.wrapAsync(async () => { let res; try { res = await this.lookupIn(key, spec, { ...options, }); } catch (e) { obsReqHandler.endWithError(e); throw e; } let content = null; let expiry = undefined; if (expiryStart >= 0) { const expiryRes = res.content[expiryStart]; expiry = expiryRes.value; } if (projStart >= 0) { if (!needReproject) { for (let i = 0; i < paths.length; ++i) { const projPath = paths[i]; const projRes = res.content[projStart + i]; if (!projRes.error) { content = sdutils_1.SdUtils.insertByPath(content, projPath, projRes.value); } } } else { content = {}; const reprojRes = res.content[projStart]; for (let j = 0; j < paths.length; ++j) { const reprojPath = paths[j]; const value = sdutils_1.SdUtils.getByPath(reprojRes.value, reprojPath); content = sdutils_1.SdUtils.insertByPath(content, reprojPath, value); } } } // The parent span is created w/in the get() operation obsReqHandler.end(); return new crudoptypes_1.GetResult({ content: content, cas: res.cas, expiryTime: expiry, }); }, callback); } /** * Checks whether a specific document exists or not. * * @param key The document key to check for existence. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ exists(key, options, callback) { if (options instanceof Function) { callback = arguments[1]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Exists, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const timeout = options.timeout || this.cluster.kvTimeout; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.exists.bind(this._conn), { id: cppDocId, partition: 0, opaque: 0, timeout, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); if (resp.deleted) { return new crudoptypes_1.ExistsResult({ cas: undefined, exists: false, }); } return new crudoptypes_1.ExistsResult({ cas: resp.cas, exists: resp.document_exists, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * @internal */ _getReplica(key, obsReqHandler, options, callback) { const cppDocId = this._cppDocId(key); obsReqHandler.setRequestKeyValueAttributes(cppDocId); const emitter = new streamablepromises_1.StreamableReplicasPromise((replicas) => replicas); const transcoder = options.transcoder || this.transcoder; const timeout = options.timeout || this.cluster.kvTimeout; if (obsReqHandler.opType == observabilitytypes_1.KeyValueOp.GetAllReplicas) { utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.getAllReplicas.bind(this._conn), { id: cppDocId, timeout: timeout, read_preference: (0, bindingutilities_1.readPreferenceToCpp)(options.readPreference), }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); emitter.emit('end'); return; } resp.entries.forEach((replica) => { try { const content = transcoder.decode(replica.value, replica.flags); emitter.emit('replica', new crudoptypes_1.GetReplicaResult({ content: content, cas: replica.cas, isReplica: replica.replica, })); } catch (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); emitter.emit('end'); return; } }); obsReqHandler.end(); emitter.emit('end'); }); } else { utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.getAnyReplica.bind(this._conn), { id: cppDocId, timeout: timeout, read_preference: (0, bindingutilities_1.readPreferenceToCpp)(options.readPreference), }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); emitter.emit('end'); return; } try { const content = transcoder.decode(resp.value, resp.flags); emitter.emit('replica', new crudoptypes_1.GetReplicaResult({ content: content, cas: resp.cas, isReplica: resp.replica, })); } catch (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); } obsReqHandler.end(); emitter.emit('end'); }); } return utilities_1.PromiseHelper.wrapAsync(() => emitter, callback); } /** * Retrieves the value of the document from any of the available replicas. This * will return as soon as the first response is received from any replica node. * * @param key The document key to retrieve. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ getAnyReplica(key, options, callback) { if (options instanceof Function) { callback = arguments[1]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.GetAnyReplica, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { return utilities_1.PromiseHelper.wrapAsync(async () => { const replicas = await this._getReplica(key, obsReqHandler, options); return replicas[0]; }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Retrieves the value of the document from all available replicas. Note that * as replication is asynchronous, each node may return a different value. * * @param key The document key to retrieve. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ getAllReplicas(key, options, callback) { if (options instanceof Function) { callback = arguments[1]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.GetAllReplicas, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { return this._getReplica(key, obsReqHandler, options, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Inserts a new document to the collection, failing if the document already exists. * * @param key The document key to insert. * @param value The value of the document to insert. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ insert(key, value, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Insert, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const cppDurability = (0, bindingutilities_1.durabilityToCpp)(options.durabilityLevel); const expiry = (0, utilities_1.parseExpiry)(options.expiry); const transcoder = options.transcoder || this.transcoder; const persistTo = options.durabilityPersistTo; const replicateTo = options.durabilityReplicateTo; const timeout = options.timeout || this._mutationTimeout(options.durabilityLevel); obsReqHandler.setRequestKeyValueAttributes(cppDocId, cppDurability); const [bytesBuf, flags] = obsReqHandler.maybeCreateEncodingSpan(() => { return transcoder.encode(value); }); const insertReq = { id: cppDocId, value: bytesBuf, flags: flags, expiry: expiry, timeout, partition: 0, opaque: 0, }; return utilities_1.PromiseHelper.wrapAsync(async () => { let err = null; let resp = null; if (persistTo || replicateTo) { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.insertWithLegacyDurability.bind(this._conn), { ...insertReq, persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo), replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo), }, obsReqHandler); } else { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.insert.bind(this._conn), { ...insertReq, durability_level: cppDurability, }, obsReqHandler); } if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); return new crudoptypes_1.MutationResult({ cas: resp.cas, token: resp.token, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Upserts a document to the collection. This operation succeeds whether or not the * document already exists. * * @param key The document key to upsert. * @param value The new value for the document. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ upsert(key, value, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Upsert, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const cppDurability = (0, bindingutilities_1.durabilityToCpp)(options.durabilityLevel); const expiry = (0, utilities_1.parseExpiry)(options.expiry); const preserve_expiry = options.preserveExpiry; const transcoder = options.transcoder || this.transcoder; const persistTo = options.durabilityPersistTo; const replicateTo = options.durabilityReplicateTo; const timeout = options.timeout || this._mutationTimeout(options.durabilityLevel); obsReqHandler.setRequestKeyValueAttributes(cppDocId, cppDurability); const [bytesBuf, flags] = obsReqHandler.maybeCreateEncodingSpan(() => { return transcoder.encode(value); }); const upsertReq = { id: cppDocId, value: bytesBuf, flags: flags, expiry: expiry, preserve_expiry: preserve_expiry || false, timeout, partition: 0, opaque: 0, }; return utilities_1.PromiseHelper.wrapAsync(async () => { let err = null; let resp = null; if (persistTo || replicateTo) { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.upsertWithLegacyDurability.bind(this._conn), { ...upsertReq, persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo), replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo), }, obsReqHandler); } else { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.upsert.bind(this._conn), { ...upsertReq, durability_level: cppDurability, }, obsReqHandler); } if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); return new crudoptypes_1.MutationResult({ cas: resp.cas, token: resp.token, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Replaces the value of an existing document. Failing if the document does not exist. * * @param key The document key to replace. * @param value The new value for the document. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ replace(key, value, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Replace, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const cppDurability = (0, bindingutilities_1.durabilityToCpp)(options.durabilityLevel); const expiry = (0, utilities_1.parseExpiry)(options.expiry); const cas = options.cas; const preserve_expiry = options.preserveExpiry; const transcoder = options.transcoder || this.transcoder; const persistTo = options.durabilityPersistTo; const replicateTo = options.durabilityReplicateTo; const timeout = options.timeout || this._mutationTimeout(options.durabilityLevel); obsReqHandler.setRequestKeyValueAttributes(cppDocId, cppDurability); const [bytesBuf, flags] = obsReqHandler.maybeCreateEncodingSpan(() => { return transcoder.encode(value); }); const replaceReq = { id: cppDocId, value: bytesBuf, flags: flags, expiry, cas: cas || binding_1.zeroCas, preserve_expiry: preserve_expiry || false, timeout, partition: 0, opaque: 0, }; return utilities_1.PromiseHelper.wrapAsync(async () => { let err = null; let resp = null; if (persistTo || replicateTo) { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.replaceWithLegacyDurability.bind(this._conn), { ...replaceReq, persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo), replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo), }, obsReqHandler); } else { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.replace.bind(this._conn), { ...replaceReq, durability_level: cppDurability, }, obsReqHandler); } if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); return new crudoptypes_1.MutationResult({ cas: resp.cas, token: resp.token, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Remove an existing document from the collection. * * @param key The document key to remove. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ remove(key, options, callback) { if (options instanceof Function) { callback = arguments[1]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Remove, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const cppDurability = (0, bindingutilities_1.durabilityToCpp)(options.durabilityLevel); const cas = options.cas; const persistTo = options.durabilityPersistTo; const replicateTo = options.durabilityReplicateTo; const timeout = options.timeout || this._mutationTimeout(options.durabilityLevel); obsReqHandler.setRequestKeyValueAttributes(cppDocId, cppDurability); const removeReq = { id: cppDocId, cas: cas || binding_1.zeroCas, timeout, partition: 0, opaque: 0, }; return utilities_1.PromiseHelper.wrapAsync(async () => { let err = null; let resp = null; if (persistTo || replicateTo) { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.removeWithLegacyDurability.bind(this._conn), { ...removeReq, persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo), replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo), }, obsReqHandler); } else { ; [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.remove.bind(this._conn), { ...removeReq, durability_level: cppDurability, }, obsReqHandler); } if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); return new crudoptypes_1.MutationResult({ cas: resp.cas, token: resp.token, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Retrieves the value of the document and simultanously updates the expiry time * for the same document. * * @param key The document to fetch and touch. * @param expiry The new expiry to apply to the document. * The expiry can be provided as: * - A `number` of seconds relative to the current time. * - A `Date` object for an absolute expiry time. * * **IMPORTANT:** To use a Unix timestamp for expiry, construct a Date from it ( new Date(UNIX_TIMESTAMP * 1000) ). * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ getAndTouch(key, expiry, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.GetAndTouch, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const transcoder = options.transcoder || this.transcoder; const timeout = options.timeout || this.cluster.kvTimeout; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.getAndTouch.bind(this._conn), { id: cppDocId, expiry: (0, utilities_1.parseExpiry)(expiry), timeout, partition: 0, opaque: 0, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } const content = transcoder.decode(resp.value, resp.flags); obsReqHandler.end(); return new crudoptypes_1.GetResult({ content: content, cas: resp.cas, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Updates the expiry on an existing document. * * @param key The document key to touch. * @param expiry The new expiry to set for the document, specified in seconds. * The expiry can be provided as: * - A `number` of seconds relative to the current time. * - A `Date` object for an absolute expiry time. * * **IMPORTANT:** To use a Unix timestamp for expiry, construct a Date from it ( new Date(UNIX_TIMESTAMP * 1000) ). * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ touch(key, expiry, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Touch, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const timeout = options.timeout || this.cluster.kvTimeout; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.touch.bind(this._conn), { id: cppDocId, expiry: (0, utilities_1.parseExpiry)(expiry), timeout, partition: 0, opaque: 0, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); return new crudoptypes_1.MutationResult({ cas: resp.cas, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Locks a document and retrieves the value of that document at the time it is locked. * * @param key The document key to retrieve and lock. * @param lockTime The amount of time to lock the document for, specified in seconds. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ getAndLock(key, lockTime, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.GetAndLock, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const transcoder = options.transcoder || this.transcoder; const timeout = options.timeout || this.cluster.kvTimeout; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.getAndLock.bind(this._conn), { id: cppDocId, lock_time: lockTime, timeout, partition: 0, opaque: 0, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } const content = transcoder.decode(resp.value, resp.flags); obsReqHandler.end(); return new crudoptypes_1.GetResult({ content: content, cas: resp.cas, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * Unlocks a previously locked document. * * @param key The document key to unlock. * @param cas The CAS of the document, used to validate lock ownership. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ unlock(key, cas, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.Unlock, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { const cppDocId = this._cppDocId(key); const timeout = options.timeout || this.cluster.kvTimeout; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, _] = await (0, observability_1.wrapObservableBindingCall)(this._conn.unlock.bind(this._conn), { id: cppDocId, cas, timeout, partition: 0, opaque: 0, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } obsReqHandler.end(); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * @internal */ _continueScan(iterator, transcoder, emitter) { iterator.next((cppErr, resp) => { const err = (0, bindingutilities_1.errorFromCpp)(cppErr); if (err) { emitter.emit('error', err); emitter.emit('end'); return; } if (typeof resp === 'undefined') { emitter.emit('end'); return; } const key = resp.key; if (typeof resp.body !== 'undefined') { const cas = resp.body.cas; const expiry = resp.body.expiry; this._decodeDoc(transcoder, resp.body.value, resp.body.flags, (err, content) => { if (err) { emitter.emit('error', err); emitter.emit('end'); return; } emitter.emit('result', new crudoptypes_1.ScanResult({ id: key, content: content, cas: cas, expiryTime: expiry, })); }); } else { emitter.emit('result', new crudoptypes_1.ScanResult({ id: key, })); } if (emitter.cancelRequested && !iterator.cancelled) { iterator.cancel(); } this._continueScan(iterator, transcoder, emitter); return; }); } /** * @internal */ _doScan(scanType, options, transcoder, callback) { const bucketName = this._scope.bucket.name; const scopeName = this._scope.name; const collectionName = this._name; return utilities_1.PromiseHelper.wrapAsync(() => { const { cppErr, result } = this._conn.scan(bucketName, scopeName, collectionName, scanType.getScanType(), (0, bindingutilities_1.scanTypeToCpp)(scanType), options); const err = (0, bindingutilities_1.errorFromCpp)(cppErr); if (err) { throw err; } const emitter = new streamablepromises_1.StreamableScanPromise((results) => results); this._continueScan(result, transcoder, emitter); return emitter; }, callback); } /** * Performs a key-value scan operation. * * Use this API for low concurrency batch queries where latency is not a critical as the system * may have to scan a lot of documents to find the matching documents. * For low latency range queries, it is recommended that you use SQL++ with the necessary indexes. * * @param scanType The type of scan to execute. * @param options Optional parameters for the scan operation. * @param callback A node-style callback to be invoked after execution. */ scan(scanType, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const transcoder = options.transcoder || this.transcoder; const timeout = options.timeout || this._kvScanTimeout; const idsOnly = options.idsOnly || false; const batchByteLimit = options.batchByteLimit || this._scanBatchByteLimit; const batchItemLimit = options.batchByteLimit || this._scanBatchItemLimit; if (typeof options.concurrency !== 'undefined' && options.concurrency < 1) { throw new errors_1.InvalidArgumentError(new Error('Concurrency option must be positive')); } const concurrency = options.concurrency || 1; if (scanType instanceof rangeScan_1.SamplingScan && scanType.limit < 1) { throw new errors_1.InvalidArgumentError(new Error('Sampling scan limit must be positive')); } const orchestratorOptions = { ids_only: idsOnly, consistent_with: (0, bindingutilities_1.mutationStateToCpp)(options.consistentWith), batch_item_limit: batchItemLimit, batch_byte_limit: batchByteLimit, concurrency: concurrency, timeout: timeout, }; return this._doScan(scanType, orchestratorOptions, transcoder, callback); } /** * Performs a lookup-in operation against a document, fetching individual fields or * information about specific fields inside the document value. * * @param key The document key to look in. * @param specs A list of specs describing the data to fetch from the document. * @param options Optional parameters for this operation. * @param callback A node-style callback to be invoked after execution. */ lookupIn(key, specs, options, callback) { if (options instanceof Function) { callback = arguments[2]; options = undefined; } if (!options) { options = {}; } const obsReqHandler = new observabilityhandler_1.ObservableRequestHandler(observabilitytypes_1.KeyValueOp.LookupIn, this.observabilityInstruments, options === null || options === void 0 ? void 0 : options.parentSpan); try { if (specs.length === 0) { throw new errors_1.InvalidArgumentError(new Error('At least one lookup spec must be provided.')); } const cppDocId = this._cppDocId(key); const cppSpecs = []; for (let i = 0; i < specs.length; ++i) { cppSpecs.push({ opcode_: specs[i]._op, flags_: specs[i]._flags, path_: specs[i]._path, original_index_: i, }); } const timeout = options.timeout || this.cluster.kvTimeout; const accessDeleted = options.accessDeleted || false; obsReqHandler.setRequestKeyValueAttributes(cppDocId); return utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.lookupIn.bind(this._conn), { id: cppDocId, specs: cppSpecs, timeout, partition: 0, opaque: 0, access_deleted: accessDeleted, }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); throw err; } const content = []; for (let i = 0; i < resp.fields.length; ++i) { const itemRes = resp.fields[i]; const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec); let value = undefined; if (itemRes.value && itemRes.value.length > 0) { value = this._subdocDecode(itemRes.value); } if (itemRes.opcode === binding_1.default.protocol_subdoc_opcode.exists) { value = itemRes.exists; } content.push(new crudoptypes_1.LookupInResultEntry({ error, value, })); } obsReqHandler.end(); return new crudoptypes_1.LookupInResult({ content: content, cas: resp.cas, }); }, callback); } catch (e) { obsReqHandler.endWithError(e); throw e; } } /** * @internal */ _lookupInReplica(key, obsReqHandler, specs, options, callback) { if (specs.length === 0) { throw new errors_1.InvalidArgumentError(new Error('At least one lookup spec must be provided.')); } const cppDocId = this._cppDocId(key); obsReqHandler.setRequestKeyValueAttributes(cppDocId); const emitter = new streamablepromises_1.StreamableReplicasPromise((replicas) => replicas); const cppSpecs = []; for (let i = 0; i < specs.length; ++i) { cppSpecs.push({ opcode_: specs[i]._op, flags_: specs[i]._flags, path_: specs[i]._path, original_index_: i, }); } const timeout = options.timeout || this.cluster.kvTimeout; if (obsReqHandler.opType == observabilitytypes_1.KeyValueOp.LookupInAllReplicas) { utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.lookupInAllReplicas.bind(this._conn), { id: cppDocId, specs: cppSpecs, timeout: timeout, read_preference: (0, bindingutilities_1.readPreferenceToCpp)(options.readPreference), access_deleted: false, // only used in core transactions; false otherwise }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); emitter.emit('end'); return; } resp.entries.forEach((replica) => { const content = []; for (let i = 0; i < replica.fields.length; ++i) { const itemRes = replica.fields[i]; const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec); let value = undefined; if (itemRes.value && itemRes.value.length > 0) { value = this._subdocDecode(itemRes.value); } if (itemRes.opcode === binding_1.default.protocol_subdoc_opcode.exists) { value = itemRes.exists; } content.push(new crudoptypes_1.LookupInResultEntry({ error, value, })); } emitter.emit('replica', new crudoptypes_1.LookupInReplicaResult({ content: content, cas: replica.cas, isReplica: replica.is_replica, })); }); obsReqHandler.end(); emitter.emit('end'); }); } else { utilities_1.PromiseHelper.wrapAsync(async () => { const [err, resp] = await (0, observability_1.wrapObservableBindingCall)(this._conn.lookupInAnyReplica.bind(this._conn), { id: cppDocId, specs: cppSpecs, timeout: timeout, read_preference: (0, bindingutilities_1.readPreferenceToCpp)(options.readPreference), access_deleted: false, // only used in core transactions; false otherwise }, obsReqHandler); if (err) { obsReqHandler.endWithError(err); emitter.emit('error', err); emitter.emit('end'); return; } const content = []; for (let i = 0; i < resp.fields.length; ++i) { const itemRes = resp.fields[i]; const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec); let value = und