Skip to content
DocspackagesreplicaguidesDocumentation

Custom SQLite adapters

Implement SqliteAdapter for any SQLite runtime (React Native, bun:sqlite, expo-sqlite, etc.).

PackagesReplicaGuides

@lunora/replica ships adapters for sql.js, better-sqlite3, and the official SQLite WASM. If your runtime uses a different SQLite backend (React Native's expo-sqlite, bun:sqlite, capataz), you can write a custom adapter.

The SqliteAdapter interface

interface SqliteAdapter {
    close: () => void;
    exec: (sql: string, params?: ReadonlyArray<unknown>) => void;
    query: <T = Record<string, unknown>>(sql: string, params?: ReadonlyArray<unknown>) => T[];
    transaction: (fn: () => void) => void;
}
MethodDescription
closeTear down the database connection.
execExecute a SQL statement with optional bound params. No result rows returned.
queryExecute SQL and return result rows as objects keyed by column name.
transactionRun all statements in the callback inside a single transaction.

Example: bun:sqlite adapter

import { Database } from "bun:sqlite";
import type { SqliteAdapter } from "@lunora/replica";

export const createBunSqliteAdapter = (database: Database): SqliteAdapter => {
    return {
        exec(sql, params) {
            if (params && params.length > 0) {
                database.run(sql, ...params);
            } else {
                database.run(sql);
            }
        },
        query(sql, params) {
            const stmt = database.prepare(sql);
            if (params && params.length > 0) {
                return stmt.all(...params) as Record<string, unknown>[];
            }
            return stmt.all() as Record<string, unknown>[];
        },
        transaction(fn) {
            database.transaction(fn)();
        },
        close() {
            database.close();
        },
    };
};

Example: expo-sqlite adapter

import type { SqliteAdapter } from "@lunora/replica";
import type { SQLiteDatabase } from "expo-sqlite";

export const createExpoSqliteAdapter = (database: SQLiteDatabase): SqliteAdapter => {
    return {
        exec(sql, params) {
            if (params && params.length > 0) {
                database.runSync(sql, params);
            } else {
                database.runSync(sql);
            }
        },
        query(sql, params) {
            const result = params?.length ? database.getAllSync(sql, params) : database.getAllSync(sql);
            return result as Record<string, unknown>[];
        },
        transaction(fn) {
            database.withTransactionSync(fn);
        },
        close() {
            database.closeSync();
        },
    };
};

Usage

Pass your adapter to LocalMirror:

const adapter = createBunSqliteAdapter(new Database(":memory:"));
const mirror = new LocalMirror({ db: adapter });