Created
October 5, 2023 04:50
-
-
Save xnohat/b7aa5035278478871697b7ad6255efb2 to your computer and use it in GitHub Desktop.
sync wrapper for IndexedDB to same localStorage API, working extractly same as localStorage, just replace localStorage to idbStorage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class IndexedDBStorage { | |
constructor(dbName = 'localStorageDB', storeName = 'localStorageStore') { | |
this.dbName = dbName; | |
this.storeName = storeName; | |
this._init(); | |
this.cache = {}; | |
} | |
_init() { | |
const request = window.indexedDB.open(this.dbName, 1); | |
request.onerror = (event) => console.error('Error opening indexedDB'); | |
request.onsuccess = async (event) => { | |
this.db = event.target.result; | |
await this._populateCache(); | |
this._syncCache(); | |
}; | |
request.onupgradeneeded = (event) => { | |
const db = event.target.result; | |
db.createObjectStore(this.storeName); | |
}; | |
} | |
async _populateCache() { | |
const store = this._getStore(); | |
return new Promise((resolve, reject) => { | |
const request = store.openCursor(); | |
request.onsuccess = (event) => { | |
const cursor = event.target.result; | |
if (cursor) { | |
this.cache[cursor.key] = cursor.value; | |
cursor.continue(); | |
} else { | |
resolve(); // Finished populating the cache | |
} | |
}; | |
request.onerror = (event) => reject('Error populating cache'); | |
}); | |
} | |
async _syncCache() { | |
for (const key in this.cache) { | |
await this._asyncSetItem(key, this.cache[key]); | |
} | |
} | |
async _asyncSetItem(key, value) { | |
const store = this._getStore('readwrite'); | |
return new Promise((resolve, reject) => { | |
const request = store.put(value, key); | |
request.onsuccess = () => resolve(); | |
request.onerror = (event) => reject('Error storing value'); | |
}); | |
} | |
_getStore(mode = 'readonly') { | |
const transaction = this.db.transaction([this.storeName], mode); | |
return transaction.objectStore(this.storeName); | |
} | |
setItem(key, value) { | |
this.cache[key] = value; | |
this._asyncSetItem(key, value).catch(console.error); | |
} | |
getItem(key) { | |
if (this.cache[key]) { | |
return this.cache[key]; | |
} | |
// Fetch from indexedDB and store in cache (in the background) | |
this._asyncGetItem(key).then(value => { | |
this.cache[key] = value; | |
}); | |
return null; // or some default value | |
} | |
async _asyncGetItem(key) { | |
const store = this._getStore(); | |
return new Promise((resolve, reject) => { | |
const request = store.get(key); | |
request.onsuccess = (event) => resolve(event.target.result); | |
request.onerror = (event) => reject('Error retrieving value'); | |
}); | |
} | |
removeItem(key) { | |
delete this.cache[key]; | |
this._asyncRemoveItem(key).catch(console.error); | |
} | |
async _asyncRemoveItem(key) { | |
const store = this._getStore('readwrite'); | |
return new Promise((resolve, reject) => { | |
const request = store.delete(key); | |
request.onsuccess = () => resolve(); | |
request.onerror = (event) => reject('Error removing value'); | |
}); | |
} | |
clear() { | |
this.cache = {}; | |
this._asyncClear().catch(console.error); | |
} | |
async _asyncClear() { | |
const store = this._getStore('readwrite'); | |
return new Promise((resolve, reject) => { | |
const request = store.clear(); | |
request.onsuccess = () => resolve(); | |
request.onerror = (event) => reject('Error clearing store'); | |
}); | |
} | |
} | |
const idbStorage = new Proxy(new IndexedDBStorage(), { | |
get: (target, prop) => { | |
if (typeof target[prop] === 'function') { | |
return target[prop].bind(target); | |
} | |
return target.getItem(prop); | |
}, | |
set: (target, prop, value) => { | |
target.setItem(prop, value); | |
return true; | |
} | |
}); | |
window.idbStorage = idbStorage; |
This thing have extractly same API with localStorage
yes have seen that. Equally TESTED to ensure _init() ain't called on every GET and SET operation and was glad it isn't.
Good Work Sir. Currently further extending it serioulsy as I needed much more features BUT wouldn't have bee able to do any of such without the foundation you gave me.
Thanks once more
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please I need quick example of how to use. Also is this a Module ?