How to load and query an existing db from OPFS? #221
-
Hi 👋, I'm new to world of sqlite-wasm and OPFS and interested in adding some offline persistence for my PWA, previously I was using sqliteworker.ts:74 NotFoundError: A requested file or directory could not be found at the time an operation was processed.
+page.svelte:20 Uncaught (in promise) Error: sqlite3_open_v2
at check (sqlite-api.js?v=0d90b6dd:856:11)
at Object.open_v2 (sqlite-api.js?v=0d90b6dd:495:9)
at async Object.openDb (sqliteworker.ts?work…e&type=module:61:12) This is my import * as Comlink from 'comlink';
import { Factory, SQLITE_OPEN_READWRITE } from 'wa-sqlite';
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs';
import { OPFSCoopSyncVFS } from 'wa-sqlite/src/examples/OPFSCoopSyncVFS';
const log = console.log;
const error = console.error;
const sqlite = () => {
let db: number | null = null;
let sqlite3: SQLiteAPI | null = null;
async function addStaticAssetToOPFS(url, fileName) {
try {
const response = await fetch(url);
const blob = await response.blob();
const fileHash = await computeHash(blob);
if (await fileExistsWithHash(fileName, fileHash)) {
console.log(`File ${fileName} already exists with the same hash.`);
return;
}
await writeFileToOPFS(fileName, blob);
console.log(`Added ${fileName} to OPFS`);
} catch (error) {
console.error(`Error adding ${fileName} to OPFS:`, error);
}
}
async function computeHash(file) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
}
async function fileExistsWithHash(fileName, hash) {
const root = await navigator.storage.getDirectory();
try {
const fileHandle = await root.getFileHandle(fileName);
const file = await fileHandle.getFile();
const existingHash = await computeHash(file);
return existingHash === hash;
} catch (error) {
// File doesn't exist
return false;
}
}
async function writeFileToOPFS(fileName, fileOrBlob) {
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle(fileName, { create: true });
const writable = await fileHandle.createWritable({ keepExistingData: false });
await writable.write(fileOrBlob);
await writable.close();
}
const preparation = async () => {
const SQLiteEMSModule = await SQLiteESMFactory();
const sqlite = Factory(SQLiteEMSModule);
const vfs = await OPFSCoopSyncVFS.create('sq-vfs', SQLiteEMSModule);
// vfs.jOpen('datatest.db');
sqlite.vfs_register(vfs, true);
return sqlite;
};
async function openDb() {
if (!db) {
sqlite3 = await preparation();
db = await sqlite3.open_v2('datatest.db', SQLITE_OPEN_READWRITE, 'sq-vfs');
}
}
async function closeDb() {
if (db) {
sqlite3?.close(db);
}
}
return {
addStaticAssetToOPFS,
openDb,
closeDb,
};
};
export type SqliteType = ReturnType<typeof sqlite>;
const sqliteInstance = sqlite();
Comlink.expose(sqliteInstance); And this is how I call: await sqlite.addStaticAssetToOPFS(
`<db-blob-url>`,
'datatest.db',
true
);
await sqlite.openDb() I tried to read the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 6 replies
-
I think I understand the issue. It is a peculiarity with OPFSCoopSyncVFS, which has to work some magic to provide synchronous VFS methods even though some of its operations - like opening a file - are asynchronous. You can try one of two workarounds:
If either of these workarounds fixes your problem then I'll attempt to explain why. |
Beta Was this translation helpful? Give feedback.
Using SQLITE_OPEN_CREATE seems to work for me.
https://github.com/rhashimoto/opfs-import-test
https://github.com/rhashimoto/opfs-import-test/blob/master/worker.js