--- description: globs: alwaysApply: true --- # wa-sqlite Usage Guide ## Table of Contents - [1. Overview](#1-overview) - [2. Installation](#2-installation) - [3. Basic Setup](#3-basic-setup) - [3.1 Import and Initialize](#31-import-and-initialize) - [3.2 Basic Database Operations](#32-basic-database-operations) - [4. Virtual File Systems (VFS)](#4-virtual-file-systems-vfs) - [4.1 Available VFS Options](#41-available-vfs-options) - [4.2 Using a VFS](#42-using-a-vfs) - [5. Best Practices](#5-best-practices) - [5.1 Error Handling](#51-error-handling) - [5.2 Transaction Management](#52-transaction-management) - [5.3 Prepared Statements](#53-prepared-statements) - [6. Performance Considerations](#6-performance-considerations) - [7. Common Issues and Solutions](#7-common-issues-and-solutions) - [8. TypeScript Support](#8-typescript-support) ## 1. Overview wa-sqlite is a WebAssembly build of SQLite that enables SQLite database operations in web browsers and JavaScript environments. It provides both synchronous and asynchronous builds, with support for custom virtual file systems (VFS) for persistent storage. ## 2. Installation ```bash npm install wa-sqlite # or yarn add wa-sqlite ``` ## 3. Basic Setup ### 3.1 Import and Initialize ```javascript // Choose one of these imports based on your needs: // - wa-sqlite.mjs: Synchronous build // - wa-sqlite-async.mjs: Asynchronous build (required for async VFS) // - wa-sqlite-jspi.mjs: JSPI-based async build (experimental, Chromium only) import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs'; import * as SQLite from 'wa-sqlite'; async function initDatabase() { // Initialize SQLite module const module = await SQLiteESMFactory(); const sqlite3 = SQLite.Factory(module); // Open database (returns a Promise) const db = await sqlite3.open_v2('myDatabase'); return { sqlite3, db }; } ``` ### 3.2 Basic Database Operations ```javascript async function basicOperations() { const { sqlite3, db } = await initDatabase(); try { // Create a table await sqlite3.exec(db, ` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE ) `); // Insert data await sqlite3.exec(db, ` INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com') `); // Query data const results = []; await sqlite3.exec(db, 'SELECT * FROM users', (row, columns) => { results.push({ row, columns }); }); return results; } finally { // Always close the database when done await sqlite3.close(db); } } ``` ## 4. Virtual File Systems (VFS) ### 4.1 Available VFS Options wa-sqlite provides several VFS implementations for persistent storage: 1. **IDBBatchAtomicVFS** (Recommended for general use) - Uses IndexedDB with batch atomic writes - Works in all contexts (Window, Worker, Service Worker) - Supports WAL mode - Best performance with `PRAGMA synchronous=normal` 2. **IDBMirrorVFS** - Keeps files in memory, persists to IndexedDB - Works in all contexts - Good for smaller databases 3. **OPFS-based VFS** (Origin Private File System) - Various implementations available: - AccessHandlePoolVFS - OPFSAdaptiveVFS - OPFSCoopSyncVFS - OPFSPermutedVFS - Better performance but limited to Worker contexts ### 4.2 Using a VFS ```javascript import { IDBBatchAtomicVFS } from 'wa-sqlite/src/examples/IDBBatchAtomicVFS.js'; import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs'; import * as SQLite from 'wa-sqlite'; async function initDatabaseWithVFS() { const module = await SQLiteESMFactory(); const sqlite3 = SQLite.Factory(module); // Register VFS const vfs = await IDBBatchAtomicVFS.create('myApp', module); sqlite3.vfs_register(vfs, true); // Open database with VFS const db = await sqlite3.open_v2('myDatabase'); // Configure for better performance await sqlite3.exec(db, 'PRAGMA synchronous = normal'); await sqlite3.exec(db, 'PRAGMA journal_mode = WAL'); return { sqlite3, db }; } ``` ## 5. Best Practices ### 5.1 Error Handling ```javascript async function safeDatabaseOperation() { const { sqlite3, db } = await initDatabase(); try { await sqlite3.exec(db, 'SELECT * FROM non_existent_table'); } catch (error) { if (error.code === SQLite.SQLITE_ERROR) { console.error('SQL error:', error.message); } else { console.error('Database error:', error); } } finally { await sqlite3.close(db); } } ``` ### 5.2 Transaction Management ```javascript async function transactionExample() { const { sqlite3, db } = await initDatabase(); try { await sqlite3.exec(db, 'BEGIN TRANSACTION'); // Perform multiple operations await sqlite3.exec(db, 'INSERT INTO users (name) VALUES (?)', ['Alice']); await sqlite3.exec(db, 'INSERT INTO users (name) VALUES (?)', ['Bob']); await sqlite3.exec(db, 'COMMIT'); } catch (error) { await sqlite3.exec(db, 'ROLLBACK'); throw error; } finally { await sqlite3.close(db); } } ``` ### 5.3 Prepared Statements ```javascript async function preparedStatementExample() { const { sqlite3, db } = await initDatabase(); try { // Prepare statement const stmt = await sqlite3.prepare(db, 'SELECT * FROM users WHERE id = ?'); // Execute with different parameters await sqlite3.bind(stmt, 1, 1); while (await sqlite3.step(stmt) === SQLite.SQLITE_ROW) { const row = sqlite3.row(stmt); console.log(row); } // Reset and reuse await sqlite3.reset(stmt); await sqlite3.bind(stmt, 1, 2); // ... execute again await sqlite3.finalize(stmt); } finally { await sqlite3.close(db); } } ``` ## 6. Performance Considerations 1. **VFS Selection** - Use IDBBatchAtomicVFS for general-purpose applications - Consider OPFS-based VFS for better performance in Worker contexts - Use MemoryVFS for temporary databases 2. **Configuration** - Set appropriate page size (default is usually fine) - Use WAL mode for better concurrency - Consider `PRAGMA synchronous=normal` for better performance - Adjust cache size based on your needs 3. **Concurrency** - Use transactions for multiple operations - Be aware of VFS-specific concurrency limitations - Consider using Web Workers for heavy database operations ## 7. Common Issues and Solutions 1. **Database Locking** - Use appropriate transaction isolation levels - Implement retry logic for busy errors - Consider using WAL mode 2. **Storage Limitations** - Be aware of browser storage quotas - Implement cleanup strategies - Monitor database size 3. **Cross-Context Access** - Use appropriate VFS for your context - Consider message passing for cross-context communication - Be aware of storage access limitations ## 8. TypeScript Support wa-sqlite includes TypeScript definitions. The main types are: ```typescript type SQLiteCompatibleType = number | string | Uint8Array | Array | bigint | null; interface SQLiteAPI { open_v2(filename: string, flags?: number, zVfs?: string): Promise; exec(db: number, sql: string, callback?: (row: any[], columns: string[]) => void): Promise; close(db: number): Promise; // ... other methods } ``` ## Additional Resources - [Official GitHub Repository](https://github.com/rhashimoto/wa-sqlite) - [Online Demo](https://rhashimoto.github.io/wa-sqlite/demo/) - [API Reference](https://rhashimoto.github.io/wa-sqlite/docs/) - [FAQ](https://github.com/rhashimoto/wa-sqlite/issues?q=is%3Aissue+label%3Afaq+) - [Discussion Forums](https://github.com/rhashimoto/wa-sqlite/discussions)