Skip to content

Commit

Permalink
indexed
Browse files Browse the repository at this point in the history
  • Loading branch information
retorquere committed May 7, 2024
1 parent a82b25f commit f525aeb
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
77 changes: 77 additions & 0 deletions content/db/indexed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { default as AsyncIndexedDB, AsyncIDBObjectStore } from 'async-indexed-db'

export class Cache extends AsyncIndexedDB {
constructor() {
// eslint-disable-next-line @typescript-eslint/no-empty-function
super('better-bibtex:cache', async (_db: IDBDatabase) => {}, 1)
}

async open(lastUpdated?: string): Promise<Cache> {
if (this.db) return this

return new Promise((resolve, reject) => {
const openRequest = indexedDB.open(this.name, 1)

openRequest.onerror = openRequest.onblocked = (): void => {
const error = `could not open cache ${this.name}: ${openRequest.error?.message || 'Unknown error'}`
Zotero.debug(error)
reject(new Error(error))
}

openRequest.onsuccess = async () => {
try {
this.db = openRequest.result
const clear = lastUpdated && (lastUpdated > (Zotero.Prefs.get('translators.better-bibtex.cache.lastUpdated') || ''))
if (clear) {
await this.tx(['ExportFormat', 'Exported', 'ExportContext'], 'readwriteflush', async ({ ExportFormat, Exported, ExportContext }) => {
await Promise.all([ExportFormat.clear(), Exported.clear(), ExportContext.clear()])
})
}
resolve(this)
}
catch (err) {
reject(err)
}
}

openRequest.onupgradeneeded = () => {
const cache = openRequest.result
const stores = {
ExportFormat: { keyPath: 'itemID', indices: undefined },
/*
Exported: { keyPath: ['context', 'itemID'], indices: { // keyPath order matters for key retrieval!
itemID: { unique: false },
context: { unique: false }
} },
ExportContext:{ keyPath: 'id', autoIncrement: true, indices: {
properties: { unique: false, multiEntry: true },
} }
*/
}

for (const [name, config] of Object.entries(stores)) {
if (cache.objectStoreNames.contains(name)) cache.deleteObjectStore(name)
const indices = config.indices
delete config.indices
const store = cache.createObjectStore(name, config)
if (indices) {
for (const [index, setup] of Object.entries(indices)) {
store.createIndex(index, index, setup)
}
}
}
}
})
}

public async tx(stores: string | string[], mode: 'readonly' | 'readwrite' | 'readwriteflush' = 'readonly', handler: (stores: Record<string, AsyncIDBObjectStore>) => Promise<void>): Promise<void> {
if (typeof stores === 'string') stores = [ stores ]
const tx = this.db.transaction(stores, mode as IDBTransactionMode)
const env: Record<string, AsyncIDBObjectStore> = {}
for (const store of stores) {
env[store] = AsyncIndexedDB.proxy(tx.objectStore(store)) as AsyncIDBObjectStore
}
await handler(env)
tx.commit()
}
}
34 changes: 34 additions & 0 deletions typings/async-indexed-db.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
declare module 'async-indexed-db' {
class AsyncIndexedDB {
public name: string
public db: IDBDatabase

constructor(name: string, schema: (db: IDBDatabase) => Promise<void>, version: number)

static proxy(obj: any): any
}

export class AsyncIDBObjectStore {
name: string
keyPath: string | string[] | null
indexNames: DOMStringList
// transaction: IDBTransaction
autoIncrement: boolean
async add(value: any, key?: IDBValidKey | IDBKeyRange | null): Promise<IDBValidKey>
clear(): Promise<void>
// count(key?: IDBValidKey | IDBKeyRange | null): IDBRequest<number>
// createIndex(name: string, keyPath: string | string[], options?: IDBIndexParameters): IDBIndex
// delete(key: IDBValidKey | IDBKeyRange): IDBRequest<void>
// deleteIndex(indexName: string): void
// get(key: IDBValidKey | IDBKeyRange): IDBRequest<any>
// getAll(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<any[]>
// getAllKeys(query?: IDBValidKey | IDBKeyRange | null, count?: number): IDBRequest<IDBValidKey[]>
// getKey(key: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey | undefined>
// index(name: string): IDBIndex
// openCursor(range?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null>
// openKeyCursor(range?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): IDBRequest<IDBCursor | null>
// put(value: any, key?: IDBValidKey | IDBKeyRange | null): IDBRequest<IDBValidKey>
}

export = AsyncIndexedDB
}

0 comments on commit f525aeb

Please sign in to comment.