UNPKG

56.6 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19 if (mod && mod.__esModule) return mod;
20 var result = {};
21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 __setModuleDefault(result, mod);
23 return result;
24};
25Object.defineProperty(exports, "__esModule", { value: true });
26exports.Collection = void 0;
27const binarycollection_1 = require("./binarycollection");
28const binding_1 = __importStar(require("./binding"));
29const bindingutilities_1 = require("./bindingutilities");
30const crudoptypes_1 = require("./crudoptypes");
31const datastructures_1 = require("./datastructures");
32const errors_1 = require("./errors");
33const generaltypes_1 = require("./generaltypes");
34const queryindexmanager_1 = require("./queryindexmanager");
35const rangeScan_1 = require("./rangeScan");
36const sdspecs_1 = require("./sdspecs");
37const sdutils_1 = require("./sdutils");
38const streamablepromises_1 = require("./streamablepromises");
39const utilities_1 = require("./utilities");
40/**
41 * Exposes the operations which are available to be performed against a collection.
42 * Namely the ability to perform KV operations.
43 *
44 * @category Core
45 */
46class Collection {
47 /**
48 * @internal
49 */
50 static get DEFAULT_NAME() {
51 return '_default';
52 }
53 /**
54 @internal
55 */
56 constructor(scope, collectionName) {
57 this._scope = scope;
58 this._name = collectionName;
59 this._conn = scope.conn;
60 this._kvScanTimeout = 75000;
61 this._scanBatchByteLimit = 15000;
62 this._scanBatchItemLimit = 50;
63 }
64 /**
65 @internal
66 */
67 get conn() {
68 return this._conn;
69 }
70 /**
71 @internal
72 */
73 get cluster() {
74 return this._scope.bucket.cluster;
75 }
76 /**
77 @internal
78 */
79 get scope() {
80 return this._scope;
81 }
82 /**
83 @internal
84 */
85 get transcoder() {
86 return this._scope.transcoder;
87 }
88 /**
89 @internal
90 */
91 _mutationTimeout(durabilityLevel) {
92 if (durabilityLevel !== undefined &&
93 durabilityLevel !== null &&
94 durabilityLevel !== generaltypes_1.DurabilityLevel.None) {
95 return this.cluster.kvDurableTimeout;
96 }
97 return this.cluster.kvTimeout;
98 }
99 /**
100 * @internal
101 */
102 _cppDocId(key) {
103 return {
104 bucket: this.scope.bucket.name,
105 scope: this.scope.name || '_default',
106 collection: this.name || '_default',
107 key: key,
108 };
109 }
110 /**
111 * @internal
112 */
113 _encodeDoc(transcoder, value, callback) {
114 try {
115 const [bytesBuf, flagsOut] = transcoder.encode(value);
116 callback(null, bytesBuf, flagsOut);
117 }
118 catch (e) {
119 return callback(e, Buffer.alloc(0), 0);
120 }
121 }
122 /**
123 * @internal
124 */
125 _decodeDoc(transcoder, bytes, flags, callback) {
126 try {
127 const content = transcoder.decode(bytes, flags);
128 callback(null, content);
129 }
130 catch (e) {
131 return callback(e, null);
132 }
133 }
134 /**
135 * @internal
136 */
137 _subdocEncode(value) {
138 return Buffer.from(value);
139 }
140 /**
141 * @internal
142 */
143 _subdocDecode(bytes) {
144 try {
145 return JSON.parse(bytes.toString('utf8'));
146 }
147 catch (e) {
148 // If we encounter a parse error, assume that we need
149 // to return bytes instead of an object.
150 return bytes;
151 }
152 }
153 /**
154 * The name of the collection this Collection object references.
155 */
156 get name() {
157 return this._name;
158 }
159 /**
160 * Retrieves the value of a document from the collection.
161 *
162 * @param key The document key to retrieve.
163 * @param options Optional parameters for this operation.
164 * @param callback A node-style callback to be invoked after execution.
165 */
166 get(key, options, callback) {
167 if (options instanceof Function) {
168 callback = arguments[1];
169 options = undefined;
170 }
171 if (!options) {
172 options = {};
173 }
174 if (options.project || options.withExpiry) {
175 return this._projectedGet(key, options, callback);
176 }
177 const transcoder = options.transcoder || this.transcoder;
178 const timeout = options.timeout || this.cluster.kvTimeout;
179 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
180 this._conn.get({
181 id: this._cppDocId(key),
182 timeout,
183 partition: 0,
184 opaque: 0,
185 }, (cppErr, resp) => {
186 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
187 if (err) {
188 return wrapCallback(err, null);
189 }
190 this._decodeDoc(transcoder, resp.value, resp.flags, (err, content) => {
191 if (err) {
192 return wrapCallback(err, null);
193 }
194 wrapCallback(null, new crudoptypes_1.GetResult({
195 content: content,
196 cas: resp.cas,
197 }));
198 });
199 });
200 }, callback);
201 }
202 _projectedGet(key, options, callback) {
203 let expiryStart = -1;
204 let projStart = -1;
205 let paths = [];
206 let spec = [];
207 let needReproject = false;
208 if (options.withExpiry) {
209 expiryStart = spec.length;
210 spec.push(sdspecs_1.LookupInSpec.get(sdspecs_1.LookupInMacro.Expiry));
211 }
212 projStart = spec.length;
213 if (!options.project) {
214 paths = [''];
215 spec.push(sdspecs_1.LookupInSpec.get(''));
216 }
217 else {
218 let projects = options.project;
219 if (!Array.isArray(projects)) {
220 projects = [projects];
221 }
222 for (let i = 0; i < projects.length; ++i) {
223 paths.push(projects[i]);
224 spec.push(sdspecs_1.LookupInSpec.get(projects[i]));
225 }
226 }
227 // The following code relies on the projections being
228 // the last segment of the specs array, this way we handle
229 // an overburdened operation in a single area.
230 if (spec.length > 16) {
231 spec = spec.splice(0, projStart);
232 spec.push(sdspecs_1.LookupInSpec.get(''));
233 needReproject = true;
234 }
235 return utilities_1.PromiseHelper.wrapAsync(async () => {
236 const res = await this.lookupIn(key, spec, {
237 ...options,
238 });
239 let content = null;
240 let expiry = undefined;
241 if (expiryStart >= 0) {
242 const expiryRes = res.content[expiryStart];
243 expiry = expiryRes.value;
244 }
245 if (projStart >= 0) {
246 if (!needReproject) {
247 for (let i = 0; i < paths.length; ++i) {
248 const projPath = paths[i];
249 const projRes = res.content[projStart + i];
250 if (!projRes.error) {
251 content = sdutils_1.SdUtils.insertByPath(content, projPath, projRes.value);
252 }
253 }
254 }
255 else {
256 content = {};
257 const reprojRes = res.content[projStart];
258 for (let j = 0; j < paths.length; ++j) {
259 const reprojPath = paths[j];
260 const value = sdutils_1.SdUtils.getByPath(reprojRes.value, reprojPath);
261 content = sdutils_1.SdUtils.insertByPath(content, reprojPath, value);
262 }
263 }
264 }
265 return new crudoptypes_1.GetResult({
266 content: content,
267 cas: res.cas,
268 expiryTime: expiry,
269 });
270 }, callback);
271 }
272 /**
273 * Checks whether a specific document exists or not.
274 *
275 * @param key The document key to check for existence.
276 * @param options Optional parameters for this operation.
277 * @param callback A node-style callback to be invoked after execution.
278 */
279 exists(key, options, callback) {
280 if (options instanceof Function) {
281 callback = arguments[1];
282 options = undefined;
283 }
284 if (!options) {
285 options = {};
286 }
287 const timeout = options.timeout || this.cluster.kvTimeout;
288 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
289 this._conn.exists({
290 id: this._cppDocId(key),
291 partition: 0,
292 opaque: 0,
293 timeout,
294 }, (cppErr, resp) => {
295 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
296 if (err) {
297 return wrapCallback(err, null);
298 }
299 if (resp.deleted) {
300 return wrapCallback(null, new crudoptypes_1.ExistsResult({
301 cas: undefined,
302 exists: false,
303 }));
304 }
305 wrapCallback(null, new crudoptypes_1.ExistsResult({
306 cas: resp.cas,
307 exists: resp.document_exists,
308 }));
309 });
310 }, callback);
311 }
312 /**
313 * @internal
314 */
315 _getReplica(key, getAllReplicas, options, callback) {
316 if (options instanceof Function) {
317 callback = arguments[2];
318 options = undefined;
319 }
320 if (!options) {
321 options = {};
322 }
323 const emitter = new streamablepromises_1.StreamableReplicasPromise((replicas) => replicas);
324 const transcoder = options.transcoder || this.transcoder;
325 const timeout = options.timeout || this.cluster.kvTimeout;
326 if (getAllReplicas) {
327 this._conn.getAllReplicas({
328 id: this._cppDocId(key),
329 timeout: timeout,
330 }, (cppErr, resp) => {
331 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
332 if (err) {
333 emitter.emit('error', err);
334 emitter.emit('end');
335 return;
336 }
337 resp.entries.forEach((replica) => {
338 this._decodeDoc(transcoder, replica.value, replica.flags, (err, content) => {
339 if (err) {
340 emitter.emit('error', err);
341 emitter.emit('end');
342 return;
343 }
344 emitter.emit('replica', new crudoptypes_1.GetReplicaResult({
345 content: content,
346 cas: replica.cas,
347 isReplica: replica.replica,
348 }));
349 });
350 });
351 emitter.emit('end');
352 return;
353 });
354 }
355 else {
356 this._conn.getAnyReplica({
357 id: this._cppDocId(key),
358 timeout: timeout,
359 }, (cppErr, resp) => {
360 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
361 if (err) {
362 emitter.emit('error', err);
363 emitter.emit('end');
364 return;
365 }
366 this._decodeDoc(transcoder, resp.value, resp.flags, (err, content) => {
367 if (err) {
368 emitter.emit('error', err);
369 emitter.emit('end');
370 return;
371 }
372 emitter.emit('replica', new crudoptypes_1.GetReplicaResult({
373 content: content,
374 cas: resp.cas,
375 isReplica: resp.replica,
376 }));
377 });
378 emitter.emit('end');
379 return;
380 });
381 }
382 return utilities_1.PromiseHelper.wrapAsync(() => emitter, callback);
383 }
384 /**
385 * Retrieves the value of the document from any of the available replicas. This
386 * will return as soon as the first response is received from any replica node.
387 *
388 * @param key The document key to retrieve.
389 * @param options Optional parameters for this operation.
390 * @param callback A node-style callback to be invoked after execution.
391 */
392 getAnyReplica(key, options, callback) {
393 if (options instanceof Function) {
394 callback = arguments[1];
395 options = undefined;
396 }
397 return utilities_1.PromiseHelper.wrapAsync(async () => {
398 const replicas = await this._getReplica(key, false, options);
399 return replicas[0];
400 }, callback);
401 }
402 /**
403 * Retrieves the value of the document from all available replicas. Note that
404 * as replication is asynchronous, each node may return a different value.
405 *
406 * @param key The document key to retrieve.
407 * @param options Optional parameters for this operation.
408 * @param callback A node-style callback to be invoked after execution.
409 */
410 getAllReplicas(key, options, callback) {
411 return this._getReplica(key, true, options, callback);
412 }
413 /**
414 * Inserts a new document to the collection, failing if the document already exists.
415 *
416 * @param key The document key to insert.
417 * @param value The value of the document to insert.
418 * @param options Optional parameters for this operation.
419 * @param callback A node-style callback to be invoked after execution.
420 */
421 insert(key, value, options, callback) {
422 if (options instanceof Function) {
423 callback = arguments[2];
424 options = undefined;
425 }
426 if (!options) {
427 options = {};
428 }
429 const expiry = options.expiry ? (0, utilities_1.expiryToTimestamp)(options.expiry) : 0;
430 const transcoder = options.transcoder || this.transcoder;
431 const durabilityLevel = options.durabilityLevel;
432 const persistTo = options.durabilityPersistTo;
433 const replicateTo = options.durabilityReplicateTo;
434 const timeout = options.timeout || this._mutationTimeout(durabilityLevel);
435 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
436 this._encodeDoc(transcoder, value, (err, bytes, flags) => {
437 if (err) {
438 return wrapCallback(err, null);
439 }
440 const insertReq = {
441 id: this._cppDocId(key),
442 value: bytes,
443 flags,
444 expiry: expiry,
445 timeout,
446 partition: 0,
447 opaque: 0,
448 };
449 const insertCallback = (cppErr, resp) => {
450 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
451 if (err) {
452 return wrapCallback(err, null);
453 }
454 wrapCallback(err, new crudoptypes_1.MutationResult({
455 cas: resp.cas,
456 token: resp.token,
457 }));
458 };
459 if (persistTo || replicateTo) {
460 this._conn.insertWithLegacyDurability({
461 ...insertReq,
462 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
463 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
464 }, insertCallback);
465 }
466 else {
467 this._conn.insert({
468 ...insertReq,
469 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
470 }, insertCallback);
471 }
472 });
473 }, callback);
474 }
475 /**
476 * Upserts a document to the collection. This operation succeeds whether or not the
477 * document already exists.
478 *
479 * @param key The document key to upsert.
480 * @param value The new value for the document.
481 * @param options Optional parameters for this operation.
482 * @param callback A node-style callback to be invoked after execution.
483 */
484 upsert(key, value, options, callback) {
485 if (options instanceof Function) {
486 callback = arguments[2];
487 options = undefined;
488 }
489 if (!options) {
490 options = {};
491 }
492 const expiry = options.expiry ? (0, utilities_1.expiryToTimestamp)(options.expiry) : 0;
493 const preserve_expiry = options.preserveExpiry;
494 const transcoder = options.transcoder || this.transcoder;
495 const durabilityLevel = options.durabilityLevel;
496 const persistTo = options.durabilityPersistTo;
497 const replicateTo = options.durabilityReplicateTo;
498 const timeout = options.timeout || this._mutationTimeout(durabilityLevel);
499 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
500 this._encodeDoc(transcoder, value, (err, bytes, flags) => {
501 if (err) {
502 return wrapCallback(err, null);
503 }
504 const upsertReq = {
505 id: this._cppDocId(key),
506 value: bytes,
507 flags,
508 expiry: expiry,
509 preserve_expiry: preserve_expiry || false,
510 timeout,
511 partition: 0,
512 opaque: 0,
513 };
514 const upsertCallback = (cppErr, resp) => {
515 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
516 if (err) {
517 return wrapCallback(err, null);
518 }
519 wrapCallback(err, new crudoptypes_1.MutationResult({
520 cas: resp.cas,
521 token: resp.token,
522 }));
523 };
524 if (persistTo || replicateTo) {
525 this._conn.upsertWithLegacyDurability({
526 ...upsertReq,
527 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
528 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
529 }, upsertCallback);
530 }
531 else {
532 this._conn.upsert({
533 ...upsertReq,
534 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
535 }, upsertCallback);
536 }
537 });
538 }, callback);
539 }
540 /**
541 * Replaces the value of an existing document. Failing if the document does not exist.
542 *
543 * @param key The document key to replace.
544 * @param value The new value for the document.
545 * @param options Optional parameters for this operation.
546 * @param callback A node-style callback to be invoked after execution.
547 */
548 replace(key, value, options, callback) {
549 if (options instanceof Function) {
550 callback = arguments[2];
551 options = undefined;
552 }
553 if (!options) {
554 options = {};
555 }
556 const expiry = options.expiry ? (0, utilities_1.expiryToTimestamp)(options.expiry) : 0;
557 const cas = options.cas;
558 const preserve_expiry = options.preserveExpiry;
559 const transcoder = options.transcoder || this.transcoder;
560 const durabilityLevel = options.durabilityLevel;
561 const persistTo = options.durabilityPersistTo;
562 const replicateTo = options.durabilityReplicateTo;
563 const timeout = options.timeout || this._mutationTimeout(durabilityLevel);
564 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
565 this._encodeDoc(transcoder, value, (err, bytes, flags) => {
566 if (err) {
567 return wrapCallback(err, null);
568 }
569 const replaceReq = {
570 id: this._cppDocId(key),
571 value: bytes,
572 flags,
573 expiry,
574 cas: cas || binding_1.zeroCas,
575 preserve_expiry: preserve_expiry || false,
576 timeout,
577 partition: 0,
578 opaque: 0,
579 };
580 const replaceCallback = (cppErr, resp) => {
581 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
582 if (err) {
583 return wrapCallback(err, null);
584 }
585 wrapCallback(err, new crudoptypes_1.MutationResult({
586 cas: resp.cas,
587 token: resp.token,
588 }));
589 };
590 if (persistTo || replicateTo) {
591 this._conn.replaceWithLegacyDurability({
592 ...replaceReq,
593 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
594 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
595 }, replaceCallback);
596 }
597 else {
598 this._conn.replace({
599 ...replaceReq,
600 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
601 }, replaceCallback);
602 }
603 });
604 }, callback);
605 }
606 /**
607 * Remove an existing document from the collection.
608 *
609 * @param key The document key to remove.
610 * @param options Optional parameters for this operation.
611 * @param callback A node-style callback to be invoked after execution.
612 */
613 remove(key, options, callback) {
614 if (options instanceof Function) {
615 callback = arguments[1];
616 options = undefined;
617 }
618 if (!options) {
619 options = {};
620 }
621 const cas = options.cas;
622 const durabilityLevel = options.durabilityLevel;
623 const persistTo = options.durabilityPersistTo;
624 const replicateTo = options.durabilityReplicateTo;
625 const timeout = options.timeout || this._mutationTimeout(durabilityLevel);
626 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
627 const removeReq = {
628 id: this._cppDocId(key),
629 cas: cas || binding_1.zeroCas,
630 timeout,
631 partition: 0,
632 opaque: 0,
633 };
634 const removeCallback = (cppErr, resp) => {
635 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
636 if (err) {
637 return wrapCallback(err, null);
638 }
639 wrapCallback(err, new crudoptypes_1.MutationResult({
640 cas: resp.cas,
641 token: resp.token,
642 }));
643 };
644 if (persistTo || replicateTo) {
645 this._conn.removeWithLegacyDurability({
646 ...removeReq,
647 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
648 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
649 }, removeCallback);
650 }
651 else {
652 this._conn.remove({
653 ...removeReq,
654 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
655 }, removeCallback);
656 }
657 }, callback);
658 }
659 /**
660 * Retrieves the value of the document and simultanously updates the expiry time
661 * for the same document.
662 *
663 * @param key The document to fetch and touch.
664 * @param expiry The new expiry to apply to the document, specified in seconds.
665 * @param options Optional parameters for this operation.
666 * @param callback A node-style callback to be invoked after execution.
667 */
668 getAndTouch(key, expiry, options, callback) {
669 if (options instanceof Function) {
670 callback = arguments[2];
671 options = undefined;
672 }
673 if (!options) {
674 options = {};
675 }
676 const transcoder = options.transcoder || this.transcoder;
677 const timeout = options.timeout || this.cluster.kvTimeout;
678 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
679 this._conn.getAndTouch({
680 id: this._cppDocId(key),
681 expiry: (0, utilities_1.expiryToTimestamp)(expiry),
682 timeout,
683 partition: 0,
684 opaque: 0,
685 }, (cppErr, resp) => {
686 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
687 if (err) {
688 return wrapCallback(err, null);
689 }
690 this._decodeDoc(transcoder, resp.value, resp.flags, (err, content) => {
691 if (err) {
692 return wrapCallback(err, null);
693 }
694 wrapCallback(err, new crudoptypes_1.GetResult({
695 content: content,
696 cas: resp.cas,
697 }));
698 });
699 });
700 }, callback);
701 }
702 /**
703 * Updates the expiry on an existing document.
704 *
705 * @param key The document key to touch.
706 * @param expiry The new expiry to set for the document, specified in seconds.
707 * @param options Optional parameters for this operation.
708 * @param callback A node-style callback to be invoked after execution.
709 */
710 touch(key, expiry, options, callback) {
711 if (options instanceof Function) {
712 callback = arguments[2];
713 options = undefined;
714 }
715 if (!options) {
716 options = {};
717 }
718 const timeout = options.timeout || this.cluster.kvTimeout;
719 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
720 this._conn.touch({
721 id: this._cppDocId(key),
722 expiry: (0, utilities_1.expiryToTimestamp)(expiry),
723 timeout,
724 partition: 0,
725 opaque: 0,
726 }, (cppErr, resp) => {
727 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
728 if (err) {
729 return wrapCallback(err, null);
730 }
731 wrapCallback(err, new crudoptypes_1.MutationResult({
732 cas: resp.cas,
733 }));
734 });
735 }, callback);
736 }
737 /**
738 * Locks a document and retrieves the value of that document at the time it is locked.
739 *
740 * @param key The document key to retrieve and lock.
741 * @param lockTime The amount of time to lock the document for, specified in seconds.
742 * @param options Optional parameters for this operation.
743 * @param callback A node-style callback to be invoked after execution.
744 */
745 getAndLock(key, lockTime, options, callback) {
746 if (options instanceof Function) {
747 callback = arguments[2];
748 options = undefined;
749 }
750 if (!options) {
751 options = {};
752 }
753 const transcoder = options.transcoder || this.transcoder;
754 const timeout = options.timeout || this.cluster.kvTimeout;
755 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
756 this._conn.getAndLock({
757 id: this._cppDocId(key),
758 lock_time: lockTime,
759 timeout,
760 partition: 0,
761 opaque: 0,
762 }, (cppErr, resp) => {
763 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
764 if (err) {
765 return wrapCallback(err, null);
766 }
767 this._decodeDoc(transcoder, resp.value, resp.flags, (err, content) => {
768 if (err) {
769 return wrapCallback(err, null);
770 }
771 wrapCallback(err, new crudoptypes_1.GetResult({
772 cas: resp.cas,
773 content: content,
774 }));
775 });
776 });
777 }, callback);
778 }
779 /**
780 * Unlocks a previously locked document.
781 *
782 * @param key The document key to unlock.
783 * @param cas The CAS of the document, used to validate lock ownership.
784 * @param options Optional parameters for this operation.
785 * @param callback A node-style callback to be invoked after execution.
786 */
787 unlock(key, cas, options, callback) {
788 if (options instanceof Function) {
789 callback = arguments[2];
790 options = undefined;
791 }
792 if (!options) {
793 options = {};
794 }
795 const timeout = options.timeout || this.cluster.kvTimeout;
796 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
797 this._conn.unlock({
798 id: this._cppDocId(key),
799 cas,
800 timeout,
801 partition: 0,
802 opaque: 0,
803 }, (cppErr) => {
804 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
805 if (err) {
806 return wrapCallback(err);
807 }
808 wrapCallback(null);
809 });
810 }, callback);
811 }
812 /**
813 * @internal
814 */
815 _continueScan(iterator, transcoder, emitter) {
816 iterator.next((cppErr, resp) => {
817 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
818 if (err) {
819 emitter.emit('error', err);
820 emitter.emit('end');
821 return;
822 }
823 if (typeof resp === 'undefined') {
824 emitter.emit('end');
825 return;
826 }
827 const key = resp.key;
828 if (typeof resp.body !== 'undefined') {
829 const cas = resp.body.cas;
830 const expiry = resp.body.expiry;
831 this._decodeDoc(transcoder, resp.body.value, resp.body.flags, (err, content) => {
832 if (err) {
833 emitter.emit('error', err);
834 emitter.emit('end');
835 return;
836 }
837 emitter.emit('result', new crudoptypes_1.ScanResult({
838 id: key,
839 content: content,
840 cas: cas,
841 expiryTime: expiry,
842 }));
843 });
844 }
845 else {
846 emitter.emit('result', new crudoptypes_1.ScanResult({
847 id: key,
848 }));
849 }
850 if (emitter.cancelRequested && !iterator.cancelled) {
851 iterator.cancel();
852 }
853 this._continueScan(iterator, transcoder, emitter);
854 return;
855 });
856 }
857 /**
858 * @internal
859 */
860 _doScan(scanType, options, transcoder, callback) {
861 const bucketName = this._scope.bucket.name;
862 const scopeName = this._scope.name;
863 const collectionName = this._name;
864 return utilities_1.PromiseHelper.wrapAsync(() => {
865 const { cppErr, result } = this._conn.scan(bucketName, scopeName, collectionName, scanType.getScanType(), (0, bindingutilities_1.scanTypeToCpp)(scanType), options);
866 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
867 if (err) {
868 throw err;
869 }
870 const emitter = new streamablepromises_1.StreamableScanPromise((results) => results);
871 this._continueScan(result, transcoder, emitter);
872 return emitter;
873 }, callback);
874 }
875 /**
876 * Performs a key-value scan operation.
877 *
878 * Use this API for low concurrency batch queries where latency is not a critical as the system
879 * may have to scan a lot of documents to find the matching documents.
880 * For low latency range queries, it is recommended that you use SQL++ with the necessary indexes.
881 *
882 * @param scanType The type of scan to execute.
883 * @param options Optional parameters for the scan operation.
884 * @param callback A node-style callback to be invoked after execution.
885 */
886 scan(scanType, options, callback) {
887 if (options instanceof Function) {
888 callback = arguments[2];
889 options = undefined;
890 }
891 if (!options) {
892 options = {};
893 }
894 const transcoder = options.transcoder || this.transcoder;
895 const timeout = options.timeout || this._kvScanTimeout;
896 const idsOnly = options.idsOnly || false;
897 const batchByteLimit = options.batchByteLimit || this._scanBatchByteLimit;
898 const batchItemLimit = options.batchByteLimit || this._scanBatchItemLimit;
899 if (typeof options.concurrency !== 'undefined' && options.concurrency < 1) {
900 throw new errors_1.InvalidArgumentError(new Error('Concurrency option must be positive'));
901 }
902 const concurrency = options.concurrency || 1;
903 if (scanType instanceof rangeScan_1.SamplingScan && scanType.limit < 1) {
904 throw new errors_1.InvalidArgumentError(new Error('Sampling scan limit must be positive'));
905 }
906 const orchestratorOptions = {
907 ids_only: idsOnly,
908 consistent_with: (0, bindingutilities_1.mutationStateToCpp)(options.consistentWith),
909 batch_item_limit: batchItemLimit,
910 batch_byte_limit: batchByteLimit,
911 concurrency: concurrency,
912 timeout: timeout,
913 };
914 return this._doScan(scanType, orchestratorOptions, transcoder, callback);
915 }
916 /**
917 * Performs a lookup-in operation against a document, fetching individual fields or
918 * information about specific fields inside the document value.
919 *
920 * @param key The document key to look in.
921 * @param specs A list of specs describing the data to fetch from the document.
922 * @param options Optional parameters for this operation.
923 * @param callback A node-style callback to be invoked after execution.
924 */
925 lookupIn(key, specs, options, callback) {
926 if (options instanceof Function) {
927 callback = arguments[2];
928 options = undefined;
929 }
930 if (!options) {
931 options = {};
932 }
933 const cppSpecs = [];
934 for (let i = 0; i < specs.length; ++i) {
935 cppSpecs.push({
936 opcode_: specs[i]._op,
937 flags_: specs[i]._flags,
938 path_: specs[i]._path,
939 original_index_: i,
940 });
941 }
942 const timeout = options.timeout || this.cluster.kvTimeout;
943 const accessDeleted = options.accessDeleted || false;
944 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
945 this._conn.lookupIn({
946 id: this._cppDocId(key),
947 specs: cppSpecs,
948 timeout,
949 partition: 0,
950 opaque: 0,
951 access_deleted: accessDeleted,
952 }, (cppErr, resp) => {
953 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
954 if (resp && resp.fields) {
955 const content = [];
956 for (let i = 0; i < resp.fields.length; ++i) {
957 const itemRes = resp.fields[i];
958 const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec);
959 let value = undefined;
960 if (itemRes.value && itemRes.value.length > 0) {
961 value = this._subdocDecode(itemRes.value);
962 }
963 if (itemRes.opcode === binding_1.default.protocol_subdoc_opcode.exists) {
964 value = itemRes.exists;
965 }
966 content.push(new crudoptypes_1.LookupInResultEntry({
967 error,
968 value,
969 }));
970 }
971 wrapCallback(err, new crudoptypes_1.LookupInResult({
972 content: content,
973 cas: resp.cas,
974 }));
975 return;
976 }
977 wrapCallback(err, null);
978 });
979 }, callback);
980 }
981 /**
982 * @internal
983 */
984 _lookupInReplica(key, lookupInAllReplicas, specs, options, callback) {
985 if (options instanceof Function) {
986 callback = arguments[3];
987 options = undefined;
988 }
989 if (!options) {
990 options = {};
991 }
992 const emitter = new streamablepromises_1.StreamableReplicasPromise((replicas) => replicas);
993 const cppSpecs = [];
994 for (let i = 0; i < specs.length; ++i) {
995 cppSpecs.push({
996 opcode_: specs[i]._op,
997 flags_: specs[i]._flags,
998 path_: specs[i]._path,
999 original_index_: i,
1000 });
1001 }
1002 const timeout = options.timeout || this.cluster.kvTimeout;
1003 if (lookupInAllReplicas) {
1004 this._conn.lookupInAllReplicas({
1005 id: this._cppDocId(key),
1006 specs: cppSpecs,
1007 timeout: timeout,
1008 }, (cppErr, resp) => {
1009 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1010 if (err) {
1011 emitter.emit('error', err);
1012 emitter.emit('end');
1013 return;
1014 }
1015 resp.entries.forEach((replica) => {
1016 const content = [];
1017 for (let i = 0; i < replica.fields.length; ++i) {
1018 const itemRes = replica.fields[i];
1019 const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec);
1020 let value = undefined;
1021 if (itemRes.value && itemRes.value.length > 0) {
1022 value = this._subdocDecode(itemRes.value);
1023 }
1024 if (itemRes.opcode === binding_1.default.protocol_subdoc_opcode.exists) {
1025 value = itemRes.exists;
1026 }
1027 content.push(new crudoptypes_1.LookupInResultEntry({
1028 error,
1029 value,
1030 }));
1031 }
1032 emitter.emit('replica', new crudoptypes_1.LookupInReplicaResult({
1033 content: content,
1034 cas: replica.cas,
1035 isReplica: replica.is_replica,
1036 }));
1037 });
1038 emitter.emit('end');
1039 return;
1040 });
1041 }
1042 else {
1043 this._conn.lookupInAnyReplica({
1044 id: this._cppDocId(key),
1045 specs: cppSpecs,
1046 timeout: timeout,
1047 }, (cppErr, resp) => {
1048 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1049 if (err) {
1050 emitter.emit('error', err);
1051 emitter.emit('end');
1052 return;
1053 }
1054 const content = [];
1055 for (let i = 0; i < resp.fields.length; ++i) {
1056 const itemRes = resp.fields[i];
1057 const error = (0, bindingutilities_1.errorFromCpp)(itemRes.ec);
1058 let value = undefined;
1059 if (itemRes.value && itemRes.value.length > 0) {
1060 value = this._subdocDecode(itemRes.value);
1061 }
1062 if (itemRes.opcode === binding_1.default.protocol_subdoc_opcode.exists) {
1063 value = itemRes.exists;
1064 }
1065 content.push(new crudoptypes_1.LookupInResultEntry({
1066 error,
1067 value,
1068 }));
1069 }
1070 emitter.emit('replica', new crudoptypes_1.GetReplicaResult({
1071 content: content,
1072 cas: resp.cas,
1073 isReplica: resp.is_replica,
1074 }));
1075 emitter.emit('end');
1076 return;
1077 });
1078 }
1079 return utilities_1.PromiseHelper.wrapAsync(() => emitter, callback);
1080 }
1081 /**
1082 * Performs a lookup-in operation against a document, fetching individual fields or
1083 * information about specific fields inside the document value from any of the available
1084 * replicas in the cluster.
1085 *
1086 * @param key The document key to look in.
1087 * @param specs A list of specs describing the data to fetch from the document.
1088 * @param options Optional parameters for this operation.
1089 * @param callback A node-style callback to be invoked after execution.
1090 */
1091 lookupInAnyReplica(key, specs, options, callback) {
1092 if (options instanceof Function) {
1093 callback = arguments[2];
1094 options = undefined;
1095 }
1096 return utilities_1.PromiseHelper.wrapAsync(async () => {
1097 const replicas = await this._lookupInReplica(key, false, specs, options);
1098 return replicas[0];
1099 }, callback);
1100 }
1101 /**
1102 * Performs a lookup-in operation against a document, fetching individual fields or
1103 * information about specific fields inside the document value from all available replicas.
1104 * Note that as replication is asynchronous, each node may return a different value.
1105 *
1106 * @param key The document key to look in.
1107 * @param specs A list of specs describing the data to fetch from the document.
1108 * @param options Optional parameters for this operation.
1109 * @param callback A node-style callback to be invoked after execution.
1110 */
1111 lookupInAllReplicas(key, specs, options, callback) {
1112 return this._lookupInReplica(key, true, specs, options, callback);
1113 }
1114 /**
1115 * Performs a mutate-in operation against a document. Allowing atomic modification of
1116 * specific fields within a document. Also enables access to document extended-attributes.
1117 *
1118 * @param key The document key to mutate.
1119 * @param specs A list of specs describing the operations to perform on the document.
1120 * @param options Optional parameters for this operation.
1121 * @param callback A node-style callback to be invoked after execution.
1122 */
1123 mutateIn(key, specs, options, callback) {
1124 if (options instanceof Function) {
1125 callback = arguments[2];
1126 options = undefined;
1127 }
1128 if (!options) {
1129 options = {};
1130 }
1131 const cppSpecs = [];
1132 for (let i = 0; i < specs.length; ++i) {
1133 cppSpecs.push({
1134 opcode_: specs[i]._op,
1135 flags_: specs[i]._flags,
1136 path_: specs[i]._path,
1137 value_: specs[i]._data
1138 ? this._subdocEncode(specs[i]._data)
1139 : specs[i]._data,
1140 original_index_: 0,
1141 });
1142 }
1143 const storeSemantics = options.upsertDocument
1144 ? generaltypes_1.StoreSemantics.Upsert
1145 : options.storeSemantics;
1146 const expiry = options.expiry
1147 ? (0, utilities_1.expiryToTimestamp)(options.expiry)
1148 : undefined;
1149 const preserveExpiry = options.preserveExpiry;
1150 const cas = options.cas;
1151 const durabilityLevel = options.durabilityLevel;
1152 const persistTo = options.durabilityPersistTo;
1153 const replicateTo = options.durabilityReplicateTo;
1154 const timeout = options.timeout || this._mutationTimeout(durabilityLevel);
1155 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
1156 const mutateInReq = {
1157 id: this._cppDocId(key),
1158 store_semantics: (0, bindingutilities_1.storeSemanticToCpp)(storeSemantics),
1159 specs: cppSpecs,
1160 expiry,
1161 preserve_expiry: preserveExpiry || false,
1162 cas: cas || binding_1.zeroCas,
1163 timeout,
1164 partition: 0,
1165 opaque: 0,
1166 access_deleted: false,
1167 create_as_deleted: false,
1168 };
1169 const mutateInCallback = (cppErr, resp) => {
1170 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1171 if (resp && resp.fields) {
1172 const content = [];
1173 for (let i = 0; i < resp.fields.length; ++i) {
1174 const itemRes = resp.fields[i];
1175 let value = undefined;
1176 if (itemRes.value && itemRes.value.length > 0) {
1177 value = this._subdocDecode(itemRes.value);
1178 }
1179 content.push(new crudoptypes_1.MutateInResultEntry({
1180 value,
1181 }));
1182 }
1183 wrapCallback(err, new crudoptypes_1.MutateInResult({
1184 content: content,
1185 cas: resp.cas,
1186 token: resp.token,
1187 }));
1188 return;
1189 }
1190 wrapCallback(err, null);
1191 };
1192 if (persistTo || replicateTo) {
1193 this._conn.mutateInWithLegacyDurability({
1194 ...mutateInReq,
1195 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
1196 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
1197 }, mutateInCallback);
1198 }
1199 else {
1200 this._conn.mutateIn({
1201 ...mutateInReq,
1202 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
1203 }, mutateInCallback);
1204 }
1205 }, callback);
1206 }
1207 /**
1208 * Returns a CouchbaseList permitting simple list storage in a document.
1209 *
1210 * @param key The document key the data-structure resides in.
1211 */
1212 list(key) {
1213 return new datastructures_1.CouchbaseList(this, key);
1214 }
1215 /**
1216 * Returns a CouchbaseQueue permitting simple queue storage in a document.
1217 *
1218 * @param key The document key the data-structure resides in.
1219 */
1220 queue(key) {
1221 return new datastructures_1.CouchbaseQueue(this, key);
1222 }
1223 /**
1224 * Returns a CouchbaseMap permitting simple map storage in a document.
1225 *
1226 * @param key The document key the data-structure resides in.
1227 */
1228 map(key) {
1229 return new datastructures_1.CouchbaseMap(this, key);
1230 }
1231 /**
1232 * Returns a CouchbaseSet permitting simple set storage in a document.
1233 *
1234 * @param key The document key the data-structure resides in.
1235 */
1236 set(key) {
1237 return new datastructures_1.CouchbaseSet(this, key);
1238 }
1239 /**
1240 * Returns a BinaryCollection object reference, allowing access to various
1241 * binary operations possible against a collection.
1242 */
1243 binary() {
1244 return new binarycollection_1.BinaryCollection(this);
1245 }
1246 /**
1247 * @internal
1248 */
1249 _binaryIncrement(key, delta, options, callback) {
1250 if (options instanceof Function) {
1251 callback = arguments[2];
1252 options = undefined;
1253 }
1254 if (!options) {
1255 options = {};
1256 }
1257 const initial_value = options.initial;
1258 const expiry = options.expiry ? (0, utilities_1.expiryToTimestamp)(options.expiry) : 0;
1259 const durabilityLevel = options.durabilityLevel;
1260 const persistTo = options.durabilityPersistTo;
1261 const replicateTo = options.durabilityReplicateTo;
1262 const timeout = options.timeout || this.cluster.kvTimeout;
1263 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
1264 const incrementReq = {
1265 id: this._cppDocId(key),
1266 delta,
1267 initial_value,
1268 expiry: expiry,
1269 timeout,
1270 partition: 0,
1271 opaque: 0,
1272 };
1273 const incrementCallback = (cppErr, resp) => {
1274 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1275 if (err) {
1276 return wrapCallback(err, null);
1277 }
1278 wrapCallback(err, new crudoptypes_1.CounterResult({
1279 cas: resp.cas,
1280 token: resp.token,
1281 value: resp.content,
1282 }));
1283 };
1284 if (persistTo || replicateTo) {
1285 this._conn.incrementWithLegacyDurability({
1286 ...incrementReq,
1287 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
1288 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
1289 }, incrementCallback);
1290 }
1291 else {
1292 this._conn.increment({
1293 ...incrementReq,
1294 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
1295 }, incrementCallback);
1296 }
1297 }, callback);
1298 }
1299 /**
1300 * @internal
1301 */
1302 _binaryDecrement(key, delta, options, callback) {
1303 if (options instanceof Function) {
1304 callback = arguments[2];
1305 options = undefined;
1306 }
1307 if (!options) {
1308 options = {};
1309 }
1310 const initial_value = options.initial;
1311 const expiry = options.expiry ? (0, utilities_1.expiryToTimestamp)(options.expiry) : 0;
1312 const durabilityLevel = options.durabilityLevel;
1313 const persistTo = options.durabilityPersistTo;
1314 const replicateTo = options.durabilityReplicateTo;
1315 const timeout = options.timeout || this.cluster.kvTimeout;
1316 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
1317 const decrementReq = {
1318 id: this._cppDocId(key),
1319 delta,
1320 initial_value,
1321 expiry: expiry,
1322 timeout,
1323 partition: 0,
1324 opaque: 0,
1325 };
1326 const decrementCallback = (cppErr, resp) => {
1327 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1328 if (err) {
1329 return wrapCallback(err, null);
1330 }
1331 wrapCallback(err, new crudoptypes_1.CounterResult({
1332 cas: resp.cas,
1333 token: resp.token,
1334 value: resp.content,
1335 }));
1336 };
1337 if (persistTo || replicateTo) {
1338 this._conn.decrementWithLegacyDurability({
1339 ...decrementReq,
1340 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
1341 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
1342 }, decrementCallback);
1343 }
1344 else {
1345 this._conn.decrement({
1346 ...decrementReq,
1347 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
1348 }, decrementCallback);
1349 }
1350 }, callback);
1351 }
1352 /**
1353 * @internal
1354 */
1355 _binaryAppend(key, value, options, callback) {
1356 if (options instanceof Function) {
1357 callback = arguments[2];
1358 options = undefined;
1359 }
1360 if (!options) {
1361 options = {};
1362 }
1363 const durabilityLevel = options.durabilityLevel;
1364 const persistTo = options.durabilityPersistTo;
1365 const replicateTo = options.durabilityReplicateTo;
1366 const timeout = options.timeout || this.cluster.kvTimeout;
1367 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
1368 if (!Buffer.isBuffer(value)) {
1369 value = Buffer.from(value);
1370 }
1371 const appendReq = {
1372 id: this._cppDocId(key),
1373 value,
1374 timeout,
1375 partition: 0,
1376 opaque: 0,
1377 };
1378 const appendCallback = (cppErr, resp) => {
1379 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1380 if (err) {
1381 return wrapCallback(err, null);
1382 }
1383 wrapCallback(err, new crudoptypes_1.MutationResult({
1384 cas: resp.cas,
1385 token: resp.token,
1386 }));
1387 };
1388 if (persistTo || replicateTo) {
1389 this._conn.appendWithLegacyDurability({
1390 ...appendReq,
1391 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
1392 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
1393 }, appendCallback);
1394 }
1395 else {
1396 this._conn.append({
1397 ...appendReq,
1398 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
1399 }, appendCallback);
1400 }
1401 }, callback);
1402 }
1403 /**
1404 * @internal
1405 */
1406 _binaryPrepend(key, value, options, callback) {
1407 if (options instanceof Function) {
1408 callback = arguments[2];
1409 options = undefined;
1410 }
1411 if (!options) {
1412 options = {};
1413 }
1414 const durabilityLevel = options.durabilityLevel;
1415 const persistTo = options.durabilityPersistTo;
1416 const replicateTo = options.durabilityReplicateTo;
1417 const timeout = options.timeout || this.cluster.kvTimeout;
1418 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
1419 if (!Buffer.isBuffer(value)) {
1420 value = Buffer.from(value);
1421 }
1422 const prependReq = {
1423 id: this._cppDocId(key),
1424 value,
1425 timeout,
1426 partition: 0,
1427 opaque: 0,
1428 };
1429 const prependCallback = (cppErr, resp) => {
1430 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
1431 if (err) {
1432 return wrapCallback(err, null);
1433 }
1434 wrapCallback(err, new crudoptypes_1.MutationResult({
1435 cas: resp.cas,
1436 token: resp.token,
1437 }));
1438 };
1439 if (persistTo || replicateTo) {
1440 this._conn.prependWithLegacyDurability({
1441 ...prependReq,
1442 persist_to: (0, bindingutilities_1.persistToToCpp)(persistTo),
1443 replicate_to: (0, bindingutilities_1.replicateToToCpp)(replicateTo),
1444 }, prependCallback);
1445 }
1446 else {
1447 this._conn.prepend({
1448 ...prependReq,
1449 durability_level: (0, bindingutilities_1.durabilityToCpp)(durabilityLevel),
1450 }, prependCallback);
1451 }
1452 }, callback);
1453 }
1454 /**
1455 * Returns a CollectionQueryIndexManager which can be used to manage the query indexes
1456 * of this collection.
1457 */
1458 queryIndexes() {
1459 return new queryindexmanager_1.CollectionQueryIndexManager(this);
1460 }
1461}
1462exports.Collection = Collection;