sync-idb-kvs
Version:
Synchronous IndexedDB Key-Value Store(Requires async Initialization)
114 lines • 4.4 kB
JavaScript
export class SyncIDBStorage {
static async create(dbName = "SyncStorageDB", storeName = "kvStore") {
const s = new SyncIDBStorage(dbName, storeName);
await s._initDB();
return s;
}
constructor(dbName = "SyncStorageDB", storeName = "kvStore") {
this.dbName = dbName;
this.storeName = storeName;
this.db = null;
this.memoryCache = {}; // メモリキャッシュ
this.uncommited = 0;
}
async _initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName);
}
};
request.onsuccess = (event) => {
this.db = event.target.result;
this._loadAllData().then(resolve).catch(reject);
};
request.onerror = (event) => reject(event.target.error);
});
}
async _loadAllData() {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(this.storeName, "readonly");
const store = transaction.objectStore(this.storeName);
const request = store.getAllKeys();
request.onsuccess = async () => {
const keys = request.result;
const values = await Promise.all(keys.map(key => this._getFromIndexedDB(key)));
keys.forEach((key, i) => {
if (!(key in this.memoryCache)) {
this.memoryCache[key] = values[i] ?? "";
}
});
resolve();
};
request.onerror = (event) => reject(event.target.error);
});
}
getItem(key) {
return this.memoryCache[key] ?? null;
}
setItem(key, value) {
this.memoryCache[key] = value;
this._saveToIndexedDB(key, value);
}
removeItem(key) {
delete this.memoryCache[key];
this._deleteFromIndexedDB(key);
}
itemExists(key) {
return key in this.memoryCache;
}
keys() {
return Object.keys(this.memoryCache)[Symbol.iterator]();
}
async reload(key) {
const value = await this._getFromIndexedDB(key);
if (value) {
if (value !== this.memoryCache[key]) {
this.memoryCache[key] = value;
}
}
else {
if (key in this.memoryCache) {
delete this.memoryCache[key];
}
}
return value;
}
async _getFromIndexedDB(key) {
return new Promise((resolve, reject) => {
if (!this.db)
return resolve(null);
const transaction = this.db.transaction(this.storeName, "readonly");
const store = transaction.objectStore(this.storeName);
const request = store.get(key);
request.onsuccess = () => resolve(request.result ?? null);
request.onerror = () => reject(request.error);
});
}
async _saveToIndexedDB(key, value) {
return new Promise((resolve, reject) => {
this.uncommited++;
if (!this.db)
return resolve();
const transaction = this.db.transaction(this.storeName, "readwrite");
const store = transaction.objectStore(this.storeName);
const request = store.put(value, key);
request.onsuccess = () => resolve();
request.onerror = (event) => reject(event.target.error);
}).finally(() => { this.uncommited--; });
}
async _deleteFromIndexedDB(key) {
return new Promise((resolve, reject) => {
if (!this.db)
return resolve();
const transaction = this.db.transaction(this.storeName, "readwrite");
const store = transaction.objectStore(this.storeName);
const request = store.delete(key);
request.onsuccess = () => resolve();
request.onerror = (event) => reject(event.target.error);
});
}
}
//# sourceMappingURL=index.js.map