From 406b2edba13ec123ff09d4a9e39cb112c6c0c87c Mon Sep 17 00:00:00 2001 From: Michael Green <84688932+michael-j-green@users.noreply.github.com> Date: Sat, 22 Nov 2025 20:38:58 +1100 Subject: [PATCH] Enhance EJS_STORAGE and EJS_Cache to support optional indexing for improved data retrieval --- data/src/cache.js | 16 ++++++++++++--- data/src/storage.js | 49 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/data/src/cache.js b/data/src/cache.js index cae0568..34029d1 100644 --- a/data/src/cache.js +++ b/data/src/cache.js @@ -41,17 +41,27 @@ class EJS_Cache { if (this.storage && this.blobStorage) return; return new Promise((resolve, reject) => { + const indexes = ["type", "url"]; const request = window.indexedDB.open(this.databaseName, 1); request.onupgradeneeded = (event) => { const db = event.target.result; - // Create object stores - db.createObjectStore("cache"); + // Create metadata stores + const cacheStore = db.createObjectStore("cache"); + // Create indexes for cache store if indexes array is present + if (Array.isArray(indexes)) { + for (const idx of indexes) { + if (!cacheStore.indexNames.contains(idx)) { + cacheStore.createIndex(idx, idx, { unique: false }); + } + } + } + // Create blobs store db.createObjectStore("blobs"); }; request.onsuccess = (event) => { - this.storage = new EJS_STORAGE(this.databaseName, "cache"); + this.storage = new EJS_STORAGE(this.databaseName, "cache", indexes); this.blobStorage = new EJS_STORAGE(this.databaseName, "blobs"); resolve(); }; diff --git a/data/src/storage.js b/data/src/storage.js index 2eb25a6..cf17863 100644 --- a/data/src/storage.js +++ b/data/src/storage.js @@ -1,7 +1,13 @@ class EJS_STORAGE { - constructor(dbName, storeName) { + /** + * @param {string} dbName + * @param {string} storeName + * @param {string[]?} indexes - Optional array of field names to create non-unique indexes on + */ + constructor(dbName, storeName, indexes = null) { this.dbName = dbName; this.storeName = storeName; + this.indexes = indexes; } #addFileToDB(key, add) { (async () => { @@ -30,19 +36,50 @@ class EJS_STORAGE { }; openRequest.onupgradeneeded = () => { let db = openRequest.result; + let objectStore; if (!db.objectStoreNames.contains(this.storeName)) { - db.createObjectStore(this.storeName); + objectStore = db.createObjectStore(this.storeName); + } else { + objectStore = openRequest.transaction.objectStore(this.storeName); + } + // Create indexes if provided + if (this.indexes && Array.isArray(this.indexes)) { + for (const idx of this.indexes) { + if (!objectStore.indexNames.contains(idx)) { + objectStore.createIndex(idx, idx, { unique: false }); + } + } } }; }); } - get(key) { + /** + * Get a value by key or by index. + * @param {string|any} key - The key or index value to search for + * @param {string|null} indexName - Optional index name to search by + * @returns {Promise} + */ + get(key, indexName = null) { return new Promise(async (resolve, reject) => { const objectStore = await this.#getObjectStore(); if (!objectStore) return resolve(); - let request = objectStore.get(key); - request.onsuccess = () => resolve(request.result); - request.onerror = () => resolve(); + if (!indexName) { + // Default: get by primary key + let request = objectStore.get(key); + request.onsuccess = () => resolve(request.result); + request.onerror = () => resolve(); + } else { + // Get by index + try { + const index = objectStore.index(indexName); + let req = index.get(key); + req.onsuccess = () => resolve(req.result); + req.onerror = () => resolve(); + } catch (e) { + // Index not found + resolve(); + } + } }); } put(key, data) {