diff --git a/index.html b/index.html
index e8d460c35b..986027e2c1 100644
--- a/index.html
+++ b/index.html
@@ -103,7 +103,8 @@
const TWO_HOURS = ONE_HOUR * 2;
const ONE_DAY = ONE_HOUR * 24;
- openmct.install(openmct.plugins.LocalStorage());
+ //openmct.install(openmct.plugins.LocalStorage());
+ openmct.install(openmct.plugins.CouchDB("http://localhost:5984/openmct"));
openmct.install(openmct.plugins.example.Generator());
openmct.install(openmct.plugins.example.EventGeneratorPlugin());
diff --git a/src/plugins/persistence/couch/CouchSearchProvider.js b/src/plugins/persistence/couch/CouchSearchProvider.js
index aa7efa74d8..b1fef2d129 100644
--- a/src/plugins/persistence/couch/CouchSearchProvider.js
+++ b/src/plugins/persistence/couch/CouchSearchProvider.js
@@ -27,7 +27,13 @@
// If the above namespace is ever resolved, we can fold this search provider
// back into the object provider.
+const BATCH_ANNOTATION_DEBOUNCE_MS = 500;
+
class CouchSearchProvider {
+ #bulkPromise;
+ #batchIds;
+ #lastAbortSignal;
+
constructor(couchObjectProvider) {
this.couchObjectProvider = couchObjectProvider;
this.searchTypes = couchObjectProvider.openmct.objects.SEARCH_TYPES;
@@ -36,6 +42,8 @@ class CouchSearchProvider {
this.searchTypes.ANNOTATIONS,
this.searchTypes.TAGS
];
+ this.#batchIds = [];
+ this.#bulkPromise = null;
}
supportsSearchType(searchType) {
@@ -68,28 +76,79 @@ class CouchSearchProvider {
return this.couchObjectProvider.getObjectsByFilter(filter, abortSignal);
}
- searchForAnnotations(keyString, abortSignal) {
+ async #deferBatchAnnotationSearch() {
+ // We until the next event loop cycle to "collect" all of the get
+ // requests triggered in this iteration of the event loop
+ await this.#waitForDebounce();
+ const batchIdsToSearch = [...this.#batchIds];
+ this.#clearBatch();
+ return this.#bulkAnnotationSearch(batchIdsToSearch);
+ }
+
+ #clearBatch() {
+ this.#batchIds = [];
+ this.#bulkPromise = undefined;
+ }
+
+ #waitForDebounce() {
+ let timeoutID;
+ clearTimeout(timeoutID);
+
+ return new Promise((resolve) => {
+ timeoutID = setTimeout(() => {
+ resolve();
+ }, BATCH_ANNOTATION_DEBOUNCE_MS);
+ });
+ }
+
+ #bulkAnnotationSearch(batchIdsToSearch) {
const filter = {
selector: {
$and: [
- {
- model: {
- targets: {}
- }
- },
{
'model.type': {
$eq: 'annotation'
}
+ },
+ {
+ $or: []
}
]
}
};
- filter.selector.$and[0].model.targets[keyString] = {
- $exists: true
- };
+ let lastAbortSignal = null;
+ // TODO: should remove duplicates from batchIds
+ batchIdsToSearch.forEach(({ keyString, abortSignal }) => {
+ const modelFilter = {
+ model: {
+ targets: {}
+ }
+ };
+ modelFilter.model.targets[keyString] = {
+ $exists: true
+ };
- return this.couchObjectProvider.getObjectsByFilter(filter, abortSignal);
+ filter.selector.$and[1].$or.push(modelFilter);
+ lastAbortSignal = abortSignal;
+ });
+
+ return this.couchObjectProvider.getObjectsByFilter(filter, lastAbortSignal);
+ }
+
+ async searchForAnnotations(keyString, abortSignal) {
+ this.#batchIds.push({ keyString, abortSignal });
+ console.debug(`🔍 Searching for annotations with key: ${keyString}`);
+ if (!this.#bulkPromise) {
+ this.#bulkPromise = this.#deferBatchAnnotationSearch();
+ }
+
+ try {
+ const returnedData = await this.#bulkPromise;
+ // TODO: find the latest annotation for given key
+ return returnedData;
+ } catch (error) {
+ console.error(error);
+ }
}
searchForTags(tagsArray, abortSignal) {