Last active
September 2, 2024 03:54
-
-
Save ritalin/4fcffc8ffdf5fcfe31dc94ab853fe917 to your computer and use it in GitHub Desktop.
IndexedDBでWASM版Duckdbをキャッシュ
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
import * as duckdb from '@duckdb/duckdb-wasm' | |
import { AsyncDuckDB, type DuckDBBundle } from '@duckdb/duckdb-wasm' | |
export const initAsyncDb = async (): Promise<AsyncDuckDB> => { | |
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles(); | |
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES); | |
const cache = await openDatabase("cache.duckdb", 3, bundle) | |
return readFromCache(cache, bundle) | |
} | |
type CacheEntry = { | |
key: string, | |
wasm: Blob, | |
worker: Blob, | |
} | |
const openDatabase = (name: string, version: number, resource: DuckDBBundle): Promise<IDBDatabase> => { | |
return new Promise((resolve: ((instance: IDBDatabase) => void), reject: ((reaqson?: any) => void)) => { | |
const req_create = indexedDB.open(name, version) | |
req_create.onerror = (ev: Event) => { | |
console.error(`Can not open cache database (${ev})`) | |
reject(ev) | |
} | |
req_create.onupgradeneeded = async (ev: IDBVersionChangeEvent) => { | |
console.log("(Re)creating database...") | |
const db = req_create.result | |
if (db.objectStoreNames.contains("cache")) { | |
db.deleteObjectStore("cache"); | |
} | |
const storage = db.createObjectStore("cache", {keyPath: 'key'}) | |
const res_wasm = await fetch(resource.mainModule) | |
const buf_wasm = await res_wasm.blob() | |
const res_worker = await fetch(resource.mainWorker!) | |
const buf_worker = await res_worker.blob() | |
const transaction = db.transaction("cache", "readwrite") | |
const store = transaction.objectStore("cache") | |
store.add({key: "wasm", wasm: buf_wasm, worker: buf_worker}) | |
transaction.oncomplete = (ev: Event) => { | |
console.log('Add cache entry successfully'); | |
} | |
transaction.onerror = (ev) => { | |
console.error('Error adding cache entry:', (ev.target as IDBRequest).error); | |
reject(ev) | |
}; | |
} | |
req_create.onsuccess = (_) => { | |
resolve(req_create.result) | |
} | |
}) | |
} | |
const readFromCache = (cache: IDBDatabase, resource: DuckDBBundle): Promise<AsyncDuckDB> => { | |
return new Promise((resolve: ((instance: AsyncDuckDB) => void), reject: ((reaqson?: any) => void)) => { | |
const storage = cache.transaction("cache", "readonly").objectStore("cache") | |
const req_get = storage.get("wasm") | |
req_get.onerror = (ev: Event) => { | |
console.error(`Can not get cache entry... (${ev})`) | |
reject(ev) | |
} | |
req_get.onsuccess = async (ev: Event) => { | |
const req = ev.target as IDBRequest | |
const entry = req.result as CacheEntry | |
const wasm_url = URL.createObjectURL(entry.wasm) | |
const worker_url = URL.createObjectURL(entry.worker); | |
const logger = import.meta.env.PROD ? new duckdb.VoidLogger(): new duckdb.ConsoleLogger() | |
const worker = new Worker(worker_url!) | |
const instance = new AsyncDuckDB(logger, worker) | |
await instance.instantiate(wasm_url, resource.pthreadWorker) | |
URL.revokeObjectURL(url_worker) | |
URL.revokeObjectURL(url_wasm) | |
resolve(instance) | |
} | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment