Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add sqlite example demonstrating task-arg caching for shared db

Opens a SQLite database once on the worker via a task-arg. All
subsequent queries receive the cached db instance — the DatabaseSync
object never crosses thread boundaries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+68
+1
README.md
··· 244 244 - [`examples/shared-state`](examples/shared-state) -- mutex-protected shared struct 245 245 - [`examples/multi-module`](examples/multi-module) -- moroutines from multiple modules on one worker 246 246 - [`examples/transfer`](examples/transfer) -- zero-copy buffer transfer to and from a worker 247 + - [`examples/sqlite`](examples/sqlite) -- shared SQLite database on a worker via task-arg caching
+36
examples/sqlite/db.ts
··· 1 + import { DatabaseSync } from 'node:sqlite'; 2 + import { mo } from '../../src/index.ts'; 3 + 4 + export const openDb = mo(import.meta, (filename: string): DatabaseSync => { 5 + const db = new DatabaseSync(filename); 6 + db.exec(` 7 + CREATE TABLE IF NOT EXISTS users ( 8 + id INTEGER PRIMARY KEY AUTOINCREMENT, 9 + name TEXT NOT NULL, 10 + email TEXT NOT NULL 11 + ) 12 + `); 13 + return db; 14 + }); 15 + 16 + export const insertUser = mo(import.meta, (db: DatabaseSync, name: string, email: string): number => { 17 + const stmt = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); 18 + const result = stmt.run(name, email); 19 + return Number(result.lastInsertRowid); 20 + }); 21 + 22 + export const getUser = mo(import.meta, (db: DatabaseSync, id: number): { id: number; name: string; email: string } | undefined => { 23 + const stmt = db.prepare('SELECT id, name, email FROM users WHERE id = ?'); 24 + return stmt.get(id) as { id: number; name: string; email: string } | undefined; 25 + }); 26 + 27 + export const listUsers = mo(import.meta, (db: DatabaseSync): { id: number; name: string; email: string }[] => { 28 + const stmt = db.prepare('SELECT id, name, email FROM users'); 29 + return stmt.all() as { id: number; name: string; email: string }[]; 30 + }); 31 + 32 + export const countUsers = mo(import.meta, (db: DatabaseSync): number => { 33 + const stmt = db.prepare('SELECT COUNT(*) as count FROM users'); 34 + const row = stmt.get() as { count: number }; 35 + return row.count; 36 + });
+31
examples/sqlite/main.ts
··· 1 + // Shared SQLite database across multiple moroutine calls on a single worker. 2 + // The db is opened once via a task-arg and cached for all subsequent queries. 3 + // Requires Node v24+. 4 + // 5 + // Run: node examples/sqlite/main.ts 6 + 7 + import { workers } from '../../src/index.ts'; 8 + import { openDb, insertUser, getUser, listUsers, countUsers } from './db.ts'; 9 + 10 + // openDb(':memory:') is a task — it runs once on the worker and is cached. 11 + // Every query receives the cached db instance without re-opening it. 12 + const db = openDb(':memory:'); 13 + 14 + { 15 + using run = workers(1); 16 + 17 + const id1 = await run(insertUser(db, 'Alice', 'alice@example.com')); 18 + const id2 = await run(insertUser(db, 'Bob', 'bob@example.com')); 19 + const id3 = await run(insertUser(db, 'Charlie', 'charlie@example.com')); 20 + 21 + console.log(`Inserted users with ids: ${id1}, ${id2}, ${id3}`); 22 + 23 + const alice = await run(getUser(db, id1)); 24 + console.log('Get Alice:', alice); 25 + 26 + const count = await run(countUsers(db)); 27 + console.log(`Total users: ${count}`); 28 + 29 + const all = await run(listUsers(db)); 30 + console.log('All users:', all); 31 + }