spice-couchbase 2.0.44 → 2.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +189 -68
- package/build/utility.js +352 -0
- package/build/utility.test.js +784 -0
- package/package.json +2 -2
- package/src/index.js +173 -79
- package/src/utility.js +368 -0
- package/src/utility.test.js +986 -0
package/build/index.js
CHANGED
|
@@ -36,8 +36,10 @@ if (!Promise.allSettled) {
|
|
|
36
36
|
status: "rejected",
|
|
37
37
|
reason
|
|
38
38
|
}))));
|
|
39
|
-
}
|
|
39
|
+
} // Couchbase lookupIn has a limit of 16 operations per call
|
|
40
40
|
|
|
41
|
+
|
|
42
|
+
var LOOKUP_IN_MAX_SPECS = 16;
|
|
41
43
|
module.exports = class Database {
|
|
42
44
|
constructor(connection) {
|
|
43
45
|
var {
|
|
@@ -305,24 +307,40 @@ module.exports = class Database {
|
|
|
305
307
|
return _asyncToGenerator(function* () {
|
|
306
308
|
try {
|
|
307
309
|
var useLookupIn = columns.length > 0;
|
|
308
|
-
var
|
|
310
|
+
var collection = _this8.use_bucket_name ? _this8.connection : _this8.collection;
|
|
309
311
|
|
|
310
|
-
if (useLookupIn) {
|
|
311
|
-
|
|
312
|
-
var value = {
|
|
313
|
-
id: doc_id
|
|
314
|
-
};
|
|
315
|
-
columns.forEach((col, colIndex) => {
|
|
316
|
-
if (response.content && response.content[colIndex]) {
|
|
317
|
-
value[col] = response.content[colIndex].value;
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
return value;
|
|
321
|
-
} else {
|
|
312
|
+
if (!useLookupIn) {
|
|
313
|
+
var response = yield collection.get(doc_id);
|
|
322
314
|
return _objectSpread({
|
|
323
315
|
id: doc_id
|
|
324
316
|
}, response.content);
|
|
325
|
-
}
|
|
317
|
+
} // Batch columns into chunks of LOOKUP_IN_MAX_SPECS (16)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
var value = {
|
|
321
|
+
id: doc_id
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
var columnBatches = _.chunk(columns, LOOKUP_IN_MAX_SPECS); // Execute all batch requests in parallel
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
var batchPromises = columnBatches.map(batch => {
|
|
328
|
+
var specs = batch.map(col => couchbase.LookupInSpec.get(col));
|
|
329
|
+
return collection.lookupIn(doc_id, specs);
|
|
330
|
+
});
|
|
331
|
+
var batchResults = yield Promise.allSettled(batchPromises); // Merge results from all batches
|
|
332
|
+
|
|
333
|
+
batchResults.forEach((result, batchIndex) => {
|
|
334
|
+
if (result.status === "fulfilled" && result.value) {
|
|
335
|
+
var batch = columnBatches[batchIndex];
|
|
336
|
+
batch.forEach((col, colIndex) => {
|
|
337
|
+
if (result.value.content && result.value.content[colIndex]) {
|
|
338
|
+
value[col] = result.value.content[colIndex].value;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
return value;
|
|
326
344
|
} catch (e) {
|
|
327
345
|
console.error(e);
|
|
328
346
|
}
|
|
@@ -400,42 +418,89 @@ module.exports = class Database {
|
|
|
400
418
|
|
|
401
419
|
if (_.isArray(keys) && keys.length > 0) {
|
|
402
420
|
var useLookupIn = columns.length > 0;
|
|
421
|
+
var collection = _this14.use_bucket_name ? _this14.connection : _this14.collection;
|
|
403
422
|
|
|
404
|
-
|
|
423
|
+
if (!useLookupIn) {
|
|
424
|
+
// Regular get - no batching needed
|
|
425
|
+
var functions = _.map(keys, key => collection.get(key));
|
|
405
426
|
|
|
406
|
-
|
|
427
|
+
var returned_all = yield Promise.allSettled(functions);
|
|
407
428
|
|
|
408
|
-
|
|
409
|
-
return returned_obj === null || returned_obj === void 0 ? void 0 : returned_obj.value;
|
|
410
|
-
}));
|
|
429
|
+
var responses = _.flatten(_.map(returned_all, returned_obj => returned_obj === null || returned_obj === void 0 ? void 0 : returned_obj.value));
|
|
411
430
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
431
|
+
var _final_responses = _.compact(_.map(responses, (res, index) => {
|
|
432
|
+
if (res) {
|
|
433
|
+
var value = res.value;
|
|
415
434
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
435
|
+
if (!keep_type && value) {
|
|
436
|
+
delete value.type;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (value) {
|
|
440
|
+
value.id = keys[index];
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return value;
|
|
444
|
+
}
|
|
445
|
+
}));
|
|
446
|
+
|
|
447
|
+
return _final_responses;
|
|
448
|
+
} // lookupIn with batching for columns > 16
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
var columnBatches = _.chunk(columns, LOOKUP_IN_MAX_SPECS); // For each key, we need to fetch all column batches and merge the results
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
var keyPromises = _.map(keys,
|
|
455
|
+
/*#__PURE__*/
|
|
456
|
+
function () {
|
|
457
|
+
var _ref = _asyncToGenerator(function* (key) {
|
|
458
|
+
try {
|
|
459
|
+
var value = {
|
|
460
|
+
id: key
|
|
461
|
+
}; // Execute all batch requests for this key in parallel
|
|
462
|
+
|
|
463
|
+
var batchPromises = columnBatches.map(batch => {
|
|
464
|
+
var specs = batch.map(col => couchbase.LookupInSpec.get(col));
|
|
465
|
+
return collection.lookupIn(key, specs);
|
|
466
|
+
});
|
|
467
|
+
var batchResults = yield Promise.allSettled(batchPromises); // Merge results from all batches
|
|
468
|
+
|
|
469
|
+
batchResults.forEach((result, batchIndex) => {
|
|
470
|
+
if (result.status === "fulfilled" && result.value) {
|
|
471
|
+
var batch = columnBatches[batchIndex];
|
|
472
|
+
batch.forEach((col, colIndex) => {
|
|
473
|
+
if (result.value.content && result.value.content[colIndex]) {
|
|
474
|
+
value[col] = result.value.content[colIndex].value;
|
|
475
|
+
}
|
|
476
|
+
});
|
|
422
477
|
}
|
|
423
478
|
});
|
|
424
|
-
} else {
|
|
425
|
-
// regular get returns the full document in value
|
|
426
|
-
value = res.value;
|
|
427
|
-
}
|
|
428
479
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
480
|
+
if (!keep_type && value) {
|
|
481
|
+
delete value.type;
|
|
482
|
+
}
|
|
432
483
|
|
|
433
|
-
|
|
434
|
-
|
|
484
|
+
return value;
|
|
485
|
+
} catch (e) {
|
|
486
|
+
return null;
|
|
435
487
|
}
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
return function (_x) {
|
|
491
|
+
return _ref.apply(this, arguments);
|
|
492
|
+
};
|
|
493
|
+
}());
|
|
494
|
+
|
|
495
|
+
var results = yield Promise.allSettled(keyPromises);
|
|
436
496
|
|
|
437
|
-
|
|
497
|
+
var final_responses = _.compact(_.map(results, result => {
|
|
498
|
+
if (result.status === "fulfilled" && result.value) {
|
|
499
|
+
// Only return if we got at least some data beyond just the id
|
|
500
|
+
return Object.keys(result.value).length > 1 ? result.value : null;
|
|
438
501
|
}
|
|
502
|
+
|
|
503
|
+
return null;
|
|
439
504
|
}));
|
|
440
505
|
|
|
441
506
|
return final_responses;
|
|
@@ -450,7 +515,7 @@ module.exports = class Database {
|
|
|
450
515
|
return new Promise(
|
|
451
516
|
/*#__PURE__*/
|
|
452
517
|
function () {
|
|
453
|
-
var
|
|
518
|
+
var _ref2 = _asyncToGenerator(function* (resolve, reject) {
|
|
454
519
|
var ViewQuery = couchbase.ViewQuery;
|
|
455
520
|
var query = ViewQuery.from(design_doc, view);
|
|
456
521
|
|
|
@@ -477,7 +542,7 @@ module.exports = class Database {
|
|
|
477
542
|
that.connection.query(query,
|
|
478
543
|
/*#__PURE__*/
|
|
479
544
|
function () {
|
|
480
|
-
var
|
|
545
|
+
var _ref3 = _asyncToGenerator(function* (err, results, matrix) {
|
|
481
546
|
var return_value = [];
|
|
482
547
|
|
|
483
548
|
if (err) {
|
|
@@ -500,14 +565,14 @@ module.exports = class Database {
|
|
|
500
565
|
}
|
|
501
566
|
});
|
|
502
567
|
|
|
503
|
-
return function (
|
|
504
|
-
return
|
|
568
|
+
return function (_x4, _x5, _x6) {
|
|
569
|
+
return _ref3.apply(this, arguments);
|
|
505
570
|
};
|
|
506
571
|
}());
|
|
507
572
|
});
|
|
508
573
|
|
|
509
|
-
return function (
|
|
510
|
-
return
|
|
574
|
+
return function (_x2, _x3) {
|
|
575
|
+
return _ref2.apply(this, arguments);
|
|
511
576
|
};
|
|
512
577
|
}());
|
|
513
578
|
}
|
|
@@ -611,7 +676,7 @@ module.exports = class Database {
|
|
|
611
676
|
return new Promise(
|
|
612
677
|
/*#__PURE__*/
|
|
613
678
|
function () {
|
|
614
|
-
var
|
|
679
|
+
var _ref4 = _asyncToGenerator(function* (resolve, reject) {
|
|
615
680
|
try {
|
|
616
681
|
var full_query = search_query + " AND type:" + type;
|
|
617
682
|
var query = that.SearchQuery.new(that.full_text_index || full_text_index, that.SearchQuery.queryString(full_query));
|
|
@@ -632,7 +697,7 @@ module.exports = class Database {
|
|
|
632
697
|
that.cluster.query(query,
|
|
633
698
|
/*#__PURE__*/
|
|
634
699
|
function () {
|
|
635
|
-
var
|
|
700
|
+
var _ref5 = _asyncToGenerator(function* (err, results, matrix) {
|
|
636
701
|
var return_value = [];
|
|
637
702
|
|
|
638
703
|
if (err) {
|
|
@@ -658,8 +723,8 @@ module.exports = class Database {
|
|
|
658
723
|
}
|
|
659
724
|
});
|
|
660
725
|
|
|
661
|
-
return function (
|
|
662
|
-
return
|
|
726
|
+
return function (_x9, _x10, _x11) {
|
|
727
|
+
return _ref5.apply(this, arguments);
|
|
663
728
|
};
|
|
664
729
|
}());
|
|
665
730
|
} catch (e) {
|
|
@@ -667,8 +732,8 @@ module.exports = class Database {
|
|
|
667
732
|
}
|
|
668
733
|
});
|
|
669
734
|
|
|
670
|
-
return function (
|
|
671
|
-
return
|
|
735
|
+
return function (_x7, _x8) {
|
|
736
|
+
return _ref4.apply(this, arguments);
|
|
672
737
|
};
|
|
673
738
|
}());
|
|
674
739
|
}
|
|
@@ -692,40 +757,96 @@ module.exports = class Database {
|
|
|
692
757
|
return response.rows;
|
|
693
758
|
})();
|
|
694
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Recursively checks if the query plan contains a Fetch operator
|
|
762
|
+
* @param {Object} plan - The EXPLAIN query plan
|
|
763
|
+
* @returns {boolean} - True if Fetch operator is found
|
|
764
|
+
*/
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
hasFetchOperator(plan) {
|
|
768
|
+
if (!plan || typeof plan !== "object") {
|
|
769
|
+
return false;
|
|
770
|
+
} // Check if this node is a Fetch operator
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
if (plan["#operator"] === "Fetch") {
|
|
774
|
+
return true;
|
|
775
|
+
} // Recursively check all child properties
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
for (var key of Object.keys(plan)) {
|
|
779
|
+
var value = plan[key];
|
|
780
|
+
|
|
781
|
+
if (Array.isArray(value)) {
|
|
782
|
+
for (var item of value) {
|
|
783
|
+
if (this.hasFetchOperator(item)) {
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
} else if (typeof value === "object" && value !== null) {
|
|
788
|
+
if (this.hasFetchOperator(value)) {
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
695
796
|
|
|
696
797
|
optimize(query, exec_scope) {
|
|
798
|
+
var _this18 = this;
|
|
799
|
+
|
|
697
800
|
return _asyncToGenerator(function* () {
|
|
698
801
|
try {
|
|
699
|
-
var
|
|
802
|
+
var _explainResponse$rows;
|
|
700
803
|
|
|
701
|
-
var
|
|
702
|
-
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
var
|
|
804
|
+
var {
|
|
805
|
+
buildCoveringIndex
|
|
806
|
+
} = require("./utility"); // 1. Run EXPLAIN to get the query plan
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
var explainQuery = "EXPLAIN ".concat(query);
|
|
810
|
+
var explainResponse = yield exec_scope.query(explainQuery); // 2. Check if query plan contains Fetch operator (not covered)
|
|
707
811
|
|
|
708
|
-
|
|
709
|
-
|
|
812
|
+
var plan = explainResponse === null || explainResponse === void 0 ? void 0 : (_explainResponse$rows = explainResponse.rows) === null || _explainResponse$rows === void 0 ? void 0 : _explainResponse$rows[0];
|
|
813
|
+
|
|
814
|
+
if (!_this18.hasFetchOperator(plan)) {
|
|
815
|
+
// Query is already covered, no need to create index
|
|
816
|
+
return;
|
|
817
|
+
} // 3. Build covering index from the query
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
var indexStatement = buildCoveringIndex(query, {
|
|
821
|
+
bucket: _this18.bucket,
|
|
822
|
+
scope: _this18.scope_name,
|
|
823
|
+
collection: _this18.collection_name
|
|
824
|
+
}); // 4. Execute the index creation if we got a valid statement
|
|
825
|
+
|
|
826
|
+
if (indexStatement) {
|
|
827
|
+
console.log("Executing index creation:", indexStatement);
|
|
828
|
+
var response = yield exec_scope.query(indexStatement);
|
|
829
|
+
console.log("Index creation response:", response);
|
|
710
830
|
}
|
|
711
|
-
} catch (e) {
|
|
831
|
+
} catch (e) {// Silently handle errors (index may already exist, etc.)
|
|
832
|
+
}
|
|
712
833
|
})();
|
|
713
834
|
}
|
|
714
835
|
|
|
715
836
|
query(query) {
|
|
716
|
-
var
|
|
837
|
+
var _this19 = this;
|
|
717
838
|
|
|
718
839
|
var query_scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "cluster";
|
|
719
840
|
return _asyncToGenerator(function* () {
|
|
720
|
-
var scope = query_scope ||
|
|
841
|
+
var scope = query_scope || _this19.query_scope;
|
|
721
842
|
var sanitizedQuery = query; //sanitization step to be implemented
|
|
722
843
|
|
|
723
844
|
var exec_scope = null;
|
|
724
845
|
|
|
725
846
|
if (scope === "cluster") {
|
|
726
|
-
exec_scope =
|
|
847
|
+
exec_scope = _this19.cluster;
|
|
727
848
|
} else {
|
|
728
|
-
exec_scope =
|
|
849
|
+
exec_scope = _this19.scope;
|
|
729
850
|
} // Start time
|
|
730
851
|
|
|
731
852
|
|
|
@@ -738,10 +859,10 @@ module.exports = class Database {
|
|
|
738
859
|
var endTime = process.hrtime.bigint(); // Calculate duration in microseconds
|
|
739
860
|
|
|
740
861
|
var durationInMilliseconds = (endTime - startTime) / BigInt(1000000); // optimize if response time is greater than 1 second
|
|
862
|
+
//if (durationInMilliseconds > 2000) {
|
|
863
|
+
|
|
864
|
+
_this19.optimize(query, exec_scope); //}
|
|
741
865
|
|
|
742
|
-
if (durationInMilliseconds > 2000) {
|
|
743
|
-
_this18.optimize(query, exec_scope);
|
|
744
|
-
}
|
|
745
866
|
|
|
746
867
|
return response;
|
|
747
868
|
})();
|