@quereus/plugin-leveldb
LevelDB storage plugin for Quereus. Provides persistent storage for Node.js environments using the @quereus/store module.
Features
- Fast: LevelDB offers excellent read/write performance for key-value workloads
- Transaction isolation: Read-your-own-writes and snapshot isolation by default
- Sorted keys: Efficient range queries with ordered iteration
- Crash-safe commits: A whole transaction's data + secondary-index writes commit in one atomic, durable LevelDB batch (see Storage layout)
- Compression: Built-in Snappy compression for reduced disk usage
Storage layout
All of a database's stores live inside one physical LevelDB at basePath,
each as a sublevel keyed by
its store name:
| Logical store | Sublevel name |
|---|---|
| Table data | {schema}.{table} |
| Secondary index | {schema}.{table}_idx_{name} |
| Unified stats | __stats__ |
| Catalog (DDL) | __catalog__ |
Because every sublevel shares one physical store, a single chained batch commits
across all of a table's sublevels (data + every secondary index) atomically and
durably — closing the crash window where a per-store commit loop could leave a
table's rows and its indexes divergent on disk. By default each commit is
fsync'd so it survives power loss; see syncCommits.
Hard cutover (no on-disk migration). This shared-root layout is the only LevelDB layout. Databases written by the older per-directory layout (
{basePath}/{schema}/{table}, a separate LevelDB per table) are not read by this version and must be re-created. Pre-1.0 dev data is expected to be thrown away; there is no migration importer.
Installation
npm install @quereus/plugin-leveldb @quereus/store @quereus/isolationQuick Start
With registerPlugin (Recommended)
import { Database, registerPlugin } from '@quereus/quereus';
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
const db = new Database();
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
await db.exec(`
create table users (id integer primary key, name text)
using store
`);
// Full transaction isolation enabled by default
await db.exec('BEGIN');
await db.exec(`INSERT INTO users VALUES (1, 'Alice')`);
const user = await db.get('SELECT * FROM users WHERE id = 1'); // Sees uncommitted insert
await db.exec('COMMIT');Disabling Isolation
If you need maximum performance and don't require read-your-own-writes within transactions:
await registerPlugin(db, leveldbPlugin, {
basePath: './data',
isolation: false // Disable isolation layer
});Direct Usage with Provider
import { Database } from '@quereus/quereus';
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
import { createIsolatedStoreModule } from '@quereus/store';
const db = new Database();
const provider = createLevelDBProvider({ basePath: './data' });
// With isolation (recommended)
const storeModule = createIsolatedStoreModule({ provider });
db.registerModule('store', storeModule);
await db.exec(`
create table users (id integer primary key, name text)
using store
`);API
LevelDBStore
Low-level KVStore implementation. LevelDBStore.open() opens a standalone
single physical LevelDB database — useful for one-off key-value stores (e.g. sync
metadata). The multi-table StoreModule backend does not use this directly; it
opens one shared root and hands out sublevel-backed stores via LevelDBProvider.
import { LevelDBStore } from '@quereus/plugin-leveldb';
const store = await LevelDBStore.open({ path: './data/mystore' });
await store.put(key, value);
const data = await store.get(key);
await store.delete(key);
// Range iteration
for await (const { key, value } of store.iterate({ gte: startKey, lt: endKey })) {
console.log(key, value);
}
// Batch writes
const batch = store.batch();
batch.put(key1, value1);
batch.put(key2, value2);
batch.delete(key3);
await batch.write();
await store.close();LevelDBProvider
Factory for managing multiple stores:
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
const provider = createLevelDBProvider({ basePath: './data' });
// All stores are sublevels of the single LevelDB at ./data
const userStore = await provider.getStore('main', 'users'); // sublevel main.users
const catalogStore = await provider.getCatalogStore(); // sublevel __catalog__
await provider.closeStore('main', 'users'); // drops the sublevel handle
await provider.closeAll(); // closes the shared rootConfiguration
Plugin Settings
| Setting | Type | Default | Description |
|---|---|---|---|
basePath |
string | './data' |
Directory of the single shared LevelDB database |
createIfMissing |
boolean | true |
Create the database if it doesn't exist |
syncCommits |
boolean | true |
fsync each transaction commit so it survives power loss (slower commits when on) |
moduleName |
string | 'store' |
Name to register the virtual table module under |
isolation |
boolean | true |
Wrap with the isolation layer (read-your-own-writes, snapshot isolation) |
LevelDBStore Options (standalone open)
| Option | Type | Default | Description |
|---|---|---|---|
path |
string | required | Directory path for the database |
createIfMissing |
boolean | true |
Create database if it doesn't exist |
Example with Transactions
import { Database, registerPlugin } from '@quereus/quereus';
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
const db = new Database();
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
await db.exec(`create table accounts (id integer primary key, balance real) using store`);
await db.exec('begin');
try {
await db.exec(`update accounts set balance = balance - 100 where id = 1`);
await db.exec(`update accounts set balance = balance + 100 where id = 2`);
await db.exec('commit');
} catch (e) {
await db.exec('rollback');
throw e;
}Related Packages
@quereus/store- Core storage module (StoreModule, StoreTable)@quereus/plugin-indexeddb- IndexedDB plugin for browsers
License
MIT