A very fast embedded key/value store featuring ACID transactions using optimistic locking, based on LMDB.
OLMDB is a high-performance, embedded on-disk key/value store that combines the speed and reliability of LMDB with optimistic concurrency control and fast batched commits. It provides ACID transactions with automatic retries for handling concurrent access patterns, making it ideal for applications that need performance, consistency and parallel (long running) read/write transactions.
Features:
- 🚀 High Performance: Built on LMDB, one of the fastest embedded databases, providing zero-copy data access. Read/write commits are automatically batched to enhance throughput.
- 🔒 ACID Transactions: Full transaction support with optimistic locking and built-in retry for race conditions.
- 📦 Zero Dependencies: Minimal footprint, running on both Node and Bun. No server process to manage.
- 🔧 Simple API: Near-instantaneous synchronous database reads and updates. Promise-based commits.
Compared to lmdb-js (which I only learned about after having finished this project 😅), OLMDB...
- Uses optimistic locking to allow long-running parallel read/write transactions.
- Can aggregate write-operations from multiple processes into a single LMDB transaction, improving write throughput.
- Does not serialize your data for you, only working on binary data and strings.
- Is not as battle-hardened.
Important caveat: OLMDB (probably) only runs on Linux currently.
import { transact, put, getString, del, scan, asString } from 'olmdb';
async function main() {
// Basic operations (database auto-initializes)
const result = await transact(() => {
// Store data
put('user:1', JSON.stringify({ name: 'Alice', age: 30 }));
put('user:2', JSON.stringify({ name: 'Bob', age: 25 }));
put('user:3', JSON.stringify({ name: 'Charlie', age: 59 }));
// Read back (uncommitted transaction-local) data
const user = JSON.parse(getString('user:1') || '{}');
console.log(user); // { name: 'Alice', age: 30 }
// Delete data
del('user:2');
return user;
});
// Scan through data, starting at 'user:2' (meaning 'user:3' comes first as 'user:2' does not exist)
await transact(() => {
for (const { key, value } of scan({start: 'user:2'})) {
console.log(key, value);
}
});
}
main().catch(console.error);npm install olmdb
# or
bun add olmdbRequirements:
- Linux (contributions to support other platforms are very welcome!)
- Node.js 14+ or Bun runtime
- GCC for native module compilation
The database auto-initializes on first use, but you can explicitly initialize it specifying a directory for the database file.
import { init } from 'olmdb';
init('./my-app-data'); // Custom data directoryThe call to init may happen only once, and should be done before the first call to transact.
Without an explicit directory, the OLMDB_DIR environment variable is used or if that isn't set ./.olmdb is used.
All database operations must be performed within a transaction:
import { transact, put, get, getString, getBuffer, del } from 'olmdb';
let promise = transact(() => {
// Store different data types
put('string-key', 'string-value');
put('buffer-key', new Uint8Array([1, 2, 3, 4]));
put('json-key', JSON.stringify({ complex: 'data' }));
// Read data with different return types
const asBytes = get('string-key'); // Uint8Array
const asString = getString('string-key'); // "string-value"
const asBuffer = getBuffer('string-key'); // ArrayBuffer (zero-copy!)
// Delete entries
del('unwanted-key');
return asString;
});
// The `promise` resolves to the value that our function returned (`asString`).OLMDB provides convenience methods for different data types with zero-copy ArrayBuffer operations:
import { transact, put, get, getString, getBuffer } from 'olmdb';
await transact(() => {
// Store any data type
put('text', 'Hello World');
put('binary', new Uint8Array([0xFF, 0xEE, 0xDD]));
// Read as different types
const asBytes = get('text'); // Uint8Array (zero-copy!)
const asBuffer = getBuffer('text'); // ArrayBuffer (zero-copy!)
const asString = getString('text'); // "Hello World" (decoded)
console.log(asBytes, asBuffer, asString);
});Zero-copy means that the Uint8Array or ArrayBuffer directly points at LMDB's memory mapped data, so it'll be very fast even for large keys and values. Note that keys can only be 511 bytes long, while values can be up to 4 gigabytes.
However, the data is only guaranteed to be valid for the duration of the transaction! If you were to read from a Uint8Array or ArrayBuffer some time after the function you provided to transact() has finished, you may get back garbage/unrelated data (as LMDB pages and commit buffers are being recycled)!! So don't do that!
I'm considering marking all data buffers returned within a transaction as 'detached' when commit is called (so that any later access will throw an exception), but this involves a fair amount of bookkeeping and thus performance. I'll try this once we have a good way to measure performance.
import { transact, scan, asString, asBuffer } from 'olmdb';
transact(() => {
// Scan all entries
for (const { key, value } of scan()) {
console.log(`Key: ${asString(key.buffer)}, Value: ${asString(value.buffer)}`);
}
// Scan a specific range, with type conversion
for (const { key, value } of scan({
start: 'user:',
end: 'user;', // Note: ';' comes after ':' in ASCII
keyConvert: asString,
valueConvert: asString
})) {
console.log(`User: ${key} = ${value}`);
}
// Reverse iteration
for (const { key, value } of scan({
reverse: true,
keyConvert: asString,
valueConvert: asString
})) {
console.log(`${key}: ${value}`);
}
// Collection helper methods
let xs = scan({keyConvert: asString}).map((kv) => kv.key.includes('x')).toArray();
console.log(xs);
// Manual iterator control
const iterator = scan({start: 'prefix:'});
const first = iterator.next();
if (!first.done) {
console.log('First entry:', first.value);
}
// Closing iterators when not iterating them till the end is optional,
// as they will auto-close on transaction end, but recommended if many
// iterators are created (in a loop).
iterator.close();
});import { transact, put, getString } from 'olmdb';
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
await transact(() => {
put('counter', '42');
});
const result1 = transact(async () => {
// This will be retried up to 6 times if another transaction
// modifies the same data concurrently
const value = parseInt(getString('counter') || '0') + 1;
console.log('transaction1: put counter', value);
await sleep(1000);
put('counter', value.toString());
return value;
});
const result2 = transact(async () => {
await sleep(500);
const value = parseInt(getString('counter') || '0') + 10;
console.log('transaction2: put counter', value);
put('counter', value.toString());
return value;
});
console.log(await Promise.all([result1, result2]));
}
main();Expected output:
transaction1: put counter 43
transaction2: put counter 52
transaction1: put counter 53
[53, 52]
What this demonstrates is a race condition, gracefully handled by a retry:
- The result1 transaction will read
counterand then wait for a second, before writing back an updated value. - In the meantime, the result2 transaction will have read and updated the
counter. - On write-commit, the result1 transaction notices that
counterhas changed since it has read it, invalidating the transaction, and running the provided function again. This time it reads 52 instead of 42.
OLMDB retries a transaction 6 times before giving up (and throwing an exception).
Performance seems to be predictably strong, for various loads and data sizes.
To get some idea, on my mediocre laptop with a store prefilled with 1 million values of 100 bytes each, I get:
- 1 read + 0 writes per txn, 1 process, 1 task per process: 420,000 txn/s.
- 1 read + 0 writes per txn, 16 processes, 1 task per process: 2,495,000 txn/s.
- 10 reads + 0 writes per txn, 1 process, 1 task per process: 67,000 txn/s.
- 10 reads + 0 writes per txn, 16 processes, 1 task per process: 403,000 txn/s.
- 10 reads + 2 writes per txn, 1 process, 1 task per process: 100 txn/s.
- 10 reads + 2 writes per txn, 1 process, 1000 tasks per process: 6,000 txn/s.
- 10 reads + 2 writes per txn, 16 processes, 1000 tasks per process: 16,000 txn/s.
Scaling up the number of tasks per process wouldn't improve performance for read-only transactions, as they're fully synchronous anyway. The performance for 5) is pretty bad, but as expected, as each transaction requires a full sync() to disk (apparently taking about 10ms on my system) before starting the next transaction.
OLMDB consists of five parts, each building on the one below:
- The high-level TypeScript API (
olmdb.ts) for this library. - The low-level TypeScript API (
lowlevel.ts) that loads and exposes the API provided by the NAPI module. - The NAPI module (
napi.c) that provides a low-level JavaScript API for the OLMDB client library. - The OLMDB client library (
transaction_client.c) that provides optimistic read/write transactions on top of LMDB. It has no relation to JavaScript. Database reads are performed synchronously. Commits for read/write transactions are performed asyncronously by the commit worker daemon. - The commit worker daemon (
commit_worker.c), shared by all clients for a database and spawned automatically by the first client. It processes queued read/write transactions and commits them to LMDB.
The native module manages transactions (start, commit, abort), and all read (get, scan) and write (put, del) operations must happen within such a transaction. Multiple transactions can run simultaneously from the same JavaScript process, allowing work for different clients to be interleaved (using async/await or callbacks).
For each OLMDB transaction, a corresponding read-only LMDB transaction is created. That gives us a consistent snapshot view of the store, from which all reads (get, scan) are done. For every read from LMDB, we log into memory associated with the transaction which key was read and a checksum of its value. We'll use this for commits, as explained below.
When writes (put, del) are performed, they are initially only stored in-memory in a buffer local to this transaction. Any further reads will first search the buffer, before consulting the underlying LMDB store, such that a transaction can read back its own writes. The buffer is organized as a skiplist, so that searching the buffer is very fast even when a transaction contains many writes.
If a transaction is aborted, the write buffer is just discarded and nothing is saved to LMDB. In case of a read-only transaction commit, we do the same. This happens synchronously. For read/write commits, we queue the transaction, including its read and write buffers for processing by the commit worker daemon (explained below). Once a commit has been processed, its callback function is invoked with the commit status as an argument (from the main thread).
The commit worker daemon is a single-threaded process that runs in the background, processing queued read/write transactions. It is spawned automatically by the first OLMDB client that accesses the database, and it will run until 10s after the last client has disconnected. Clients connect to the daemon using a unix domain socket (in the abstract socket namespace). Clients store their transaction buffers in a shared memory region, which is also opened by the commit worker daemon. The socket is only used to communicate the address of each transaction to be committed to the daemon, and to signal "at least one transaction has been processed" back to the client.
Once one or more read/write commits have been queued, the write-commit thread will start a read/write LMDB transaction. Note that LMDB only allows for a single read/write transaction at a time, so that's why we do this from a single thread and we try to process transactions as quickly as we can.
Within a single LMDB transaction, we can run a bunch of OLMDB transactions as follows:
- First replay all of the reads the transaction has performed (and stored in the read buffer) in its initial phase, verifying that the results are still the same based on the stored checksums. If not, the transaction has been raced by another transaction. Writes for this transaction will not be performed, and the 'raced' status is communicated back to committing code.
- All of the writes are performed on LMDB. This should never fail, under normal circumstances. The 'success' status is communicated back to the committing code.
After a batch of OLMDB transactions has been processed, the LMDB transaction is committed, and work can be started on the next batch. Batching commits can improve write performance immensely, as writes to pages in the top regions of b-tree and file syncs can usually be shared between transactions.
The high-level API, written in TypeScript provides a transact(func) method that runs a function within the context of an OLMDB transaction. This transaction context is preserved in AsyncLocalStorage, so that you can just call functions like put and get without having to pass along a transaction object. This can be convenient when database accesses are deeply nested.
After the provided function is done running, transact() does an OLMDB commit, and (for read/write transactions) registers a callback function. In case it gets called with a 'raced' status, the function will be executed again within a new transaction context. This happens up to six times before giving up.
You can run as many JavaScript processes, and within each as many concurrent request handlers as you want. LMDB allows multiple processes (on the same machine) to safely run read-only transaction in the same database file simultaneously. All read/write operations are committed to LMDB by the single threaded commit worker daemon, which may be a bottleneck for write-heavy workloads, though it's highly efficient and sure therefore scale to thousands of transactions per second.
In the benchmark directory you can find the start of a benchmarking suite to get some feel for performance.
OLMDB can only scale vertically, on a single server. In case you eventually need to scale beyond a single server, that can only be done at the application level.
The high-level API provides a promise-based, type-safe interface with automatic transaction retries and convenient data type conversions.
The following is auto-generated from src/olmdb.ts:
setTransactionData · function
Attach some arbitrary user data to the current transaction context, which is attached to the currently running (async) task.
Signature: (key: symbol, value: any) => void
Parameters:
key: symbol- - A symbol key to store data in the current transaction context.value: any- - The value to store.
Throws:
- If called outside of a transaction context.
Examples:
const MY_SYMBOL = Symbol("myKey");
await transact(async () => {
setTransactionData(MY_SYMBOL, "myValue");
await somethingAsync(); // Can be interleaved with other transactions
const value = getTransactionData(MY_SYMBOL);
console.log(value); // "myValue"
});getTransactionData · function
Retrieves data from the current transaction context.
Signature: (key: symbol) => any
Parameters:
key: symbol- - A symbol key to retrieve data from the current transaction context.
Returns: - The value associated with the key, or undefined if not set.
Throws:
- If called outside of a transaction context.
get · function
Retrieves a value from the database by key within the current transaction.
Signature: (key: Data) => Uint8Array<ArrayBufferLike>
Parameters:
key: Data- - The key to look up as a Uint8Array, ArrayBuffer, or string.
Returns: The value associated with the key as a Uint8Array, or undefined if not found.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if key exceeds maximum allowed length.
- With code "LMDB-{code}" for LMDB-specific errors.
getBuffer · function
Retrieves a value from the database by key within the current transaction.
Signature: (key: Data) => ArrayBuffer
Parameters:
key: Data- - The key to look up as a Uint8Array, ArrayBuffer, or string.
Returns: The value associated with the key as an ArrayBuffer, or undefined if not found.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if key exceeds maximum allowed length.
- With code "LMDB-{code}" for LMDB-specific errors.
getString · function
Retrieves a value from the database by key within the current transaction and decodes it as a string.
Signature: (key: Data) => string
Parameters:
key: Data- - The key to look up as a Uint8Array, ArrayBuffer, or string.
Returns: The value associated with the key as a UTF-8 decoded string, or undefined if not found.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if key exceeds maximum allowed length.
- With code "LMDB-{code}" for LMDB-specific errors.
put · function
Stores a key-value pair in the database within the current transaction.
Signature: (key: Data, val: Data) => void
Parameters:
key: Data- - The key to store as a Uint8Array, ArrayBuffer, or string.val: Data- - The value to associate with the key as a Uint8Array, ArrayBuffer, or string.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if key exceeds maximum allowed length.
- With code "LMDB-{code}" for LMDB-specific errors.
del · function
Deletes a key-value pair from the database within the current transaction.
Signature: (key: Data) => void
Parameters:
key: Data- - The key to delete as a Uint8Array, ArrayBuffer, or string.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if key exceeds maximum allowed length.
- With code "LMDB-{code}" for LMDB-specific errors.
init · function
Initialize the database with the specified directory path. This function may be called multiple times with the same parameters. If it is not called before the first transact(), the database will be automatically initialized with the default directory.
Signature: (dbDir?: string) => void
Parameters:
dbDir?: string- - Optional directory path for the database (defaults to environment variable $OLMDB_DIR or "./.olmdb").
Throws:
- With code "INCONSISTENT_INIT" if database is already initialized with different parameters.
- With code "CREATE_DIR_FAILED" if directory creation fails.
- With code "LMDB-{code}" for LMDB-specific errors.
Examples:
init("./my-database");onRevert · function
Registers a callback to be executed when the current transaction is reverted (aborted due to error). The callback will be executed outside of transaction context.
Signature: (callback: (commitSeq: number) => void) => void
Parameters:
callback: (commitSeq: number) => void- - Function to execute when transaction is reverted. It receives the dummy (always 0) commit sequence indicating failure as an argument.
Throws:
- If called outside of a transaction context
onCommit · function
Registers a callback to be executed when the current transaction commits successfully. The callback will be executed outside of transaction context.
Signature: (callback: (commitSeq: number) => void) => void
Parameters:
callback: (commitSeq: number) => void- - Function to execute when transaction commits. It receives the commit sequence, which is an always-increasing number that provides a global ordering of commits, as an argument.
Throws:
- If called outside of a transaction context
transact · function
Executes a function within a database transaction context.
All database operations (get, put, del) must be performed within a transaction. Transactions are automatically committed if the function completes successfully, or aborted if an error occurs. Failed transactions may be automatically retried up to 6 times in case of validation conflicts.
Signature: { <T>(fn: () => Promise<unique symbol>): Promise<number>; <T>(fn: () => unique symbol): Promise<number>; <T>(fn: () => Promise<T>): Promise<T>; <T>(fn: () => T): Promise<...>; }
Type Parameters:
T- The return type of the transaction function.
Parameters:
fn: () => Promise<typeof RETURN_COMMIT_SEQ>- - The (optionally asynchronous) function to execute within the transaction context.
Returns: A promise that resolves with the function's return value. If the function returns the special symbol RETURN_COMMIT_SEQ, the promise resolves with the commit sequence number instead.
Throws:
- If nested transactions are attempted.
- With code "RACING_TRANSACTION" if the transaction fails after retries due to conflicts.
- With code "TRANSACTION_FAILED" if the transaction fails for other reasons.
- With code "TXN_LIMIT" if maximum number of transactions is reached.
- With code "LMDB-{code}" for LMDB-specific errors.
Examples:
const result = await transact(() => {
const value = get(keyBytes);
if (value) {
put(keyBytes, newValueBytes);
}
return value;
});scan · function
Creates an iterator to scan through database entries within the current transaction.
The iterator implements the standard TypeScript iterator protocol and can be used with for...of loops. Supports both forward and reverse iteration with optional start and end boundaries.
Signature: <K = Uint8Array<ArrayBufferLike>, V = Uint8Array<ArrayBufferLike>>(opts?: ScanOptions<K, V>) => DbIterator<K, V>
Type Parameters:
K = Uint8Array- The type to convert keys to (defaults to Uint8Array).V = Uint8Array- The type to convert values to (defaults to Uint8Array).
Parameters:
opts: ScanOptions<K,V>(optional) - - Configuration options for the scan operation.
Returns: A DbIterator instance.
Throws:
- If called outside of a transaction context.
- With code "INVALID_TRANSACTION" if transaction is invalid or already closed.
- With code "KEY_TOO_LONG" if start or end key exceeds maximum allowed length.
- With code "ITERATOR_LIMIT" if maximum number of iterators is reached.
- With code "OUT_OF_MEMORY" if memory allocation fails.
Examples:
await transact(() => {
// Iterate over all entries
for (const { key, value } of scan()) {
console.log('Key:', key, 'Value:', value);
}
// Iterate with string conversion
for (const { key, value } of scan({
keyConvert: asString,
valueConvert: asString
})) {
console.log('Key:', key, 'Value:', value);
}
// Iterate with boundaries
for (const { key, value } of scan({
start: "prefix_",
end: "prefix~"
})) {
console.log('Key:', key, 'Value:', value);
}
// Manual iteration control
const iter = scan({ reverse: true });
const first = iter.next();
iter.close(); // Always close when done early
});asArray · function
Converts an ArrayBuffer to a Uint8Array. Helper function for use with scan() keyConvert and valueConvert options.
Signature: (buffer: ArrayBuffer) => Uint8Array<ArrayBufferLike>
Parameters:
buffer: ArrayBuffer- - The ArrayBuffer to convert.
Returns: A new Uint8Array view of the buffer.
asBuffer · function
Returns the ArrayBuffer as-is. Helper function for use with scan() keyConvert and valueConvert options.
Signature: (buffer: ArrayBuffer) => ArrayBuffer
Parameters:
buffer: ArrayBuffer- - The ArrayBuffer to return.
Returns: The same ArrayBuffer.
asString · function
Converts an ArrayBuffer to a UTF-8 decoded string. Helper function for use with scan() keyConvert and valueConvert options.
Signature: (buffer: ArrayBuffer) => string
Parameters:
buffer: ArrayBuffer- - The ArrayBuffer to decode.
Returns: A UTF-8 decoded string.
DatabaseError · constant
The DatabaseError class is used to represent errors that occur during database operations. It extends the built-in Error class and has a machine readable error code string property.
The lowlevel API will throw DatabaseError instances for all database-related errors. Invalid function arguments will throw TypeError.
Value: DatabaseErrorConstructor
Data · type
Union type representing the supported data formats for keys and values. Can be a Uint8Array, ArrayBuffer, or string.
Type: Uint8Array | ArrayBuffer | string
RETURN_COMMIT_SEQ · constant
When returned from a transaction function, indicates that the caller wants to receive the commit sequence number as the resolved value of the transact() promise. This can be useful for applications that need a globally unique, monotonically increasing identifier for each committed transaction.
Value: unique symbol
DbEntry · interface
Represents a key-value pair returned by the iterator
Type Parameters:
KV
dbEntry.key · member
Type: K
dbEntry.value · member
Type: V
DbIterator · class
Database iterator that implements the standard TypeScript iterator protocol
Type Parameters:
KV
dbIterator.iteratorId · property
Type: number
dbIterator.convertKey · property
Type: (buffer: ArrayBuffer) => K
dbIterator.convertValue · property
Type: (buffer: ArrayBuffer) => V
dbIterator.[Symbol.iterator] · method
Signature: () => DbIterator<K, V>
Parameters:
dbIterator.next · method
Advances the iterator to the next key-value pair.
Signature: () => IteratorResult<DbEntry<K, V>, any>
Parameters:
Returns: An IteratorResult with the next DbEntry or done: true if no more entries.
Throws:
- With code "INVALID_ITERATOR" if iterator is invalid or already closed.
- With code "LMDB-{code}" for LMDB-specific errors.
dbIterator.close · method
Closes the iterator and frees its resources. Should be called when done iterating to prevent resource leaks.
Signature: () => void
Parameters:
Throws:
- With code "INVALID_ITERATOR" if iterator is invalid or already closed.
The low-level API is what's exposed by the native module. It's a somewhat less convenient than the high-level API, but it's a good starting point if you require a different abstraction.
The following is auto-generated from src/lowlevel.ts:
init · function
Initializes the database system with the specified directory.
Can be called multiple times if directory and commitWorkerBin are identical.
Signature: (directory?: string, commitWorkerBin?: string) => void
Parameters:
directory?: string- Optional path to the database directory. If not provided, defaults to the OLMDB_DIR environment variable or "./.olmdb".commitWorkerBin: string(optional) - Path to the commit worker binary. Defaults to<base_dir>/build/release/commit_worker.
Throws:
- DatabaseError if initialization fails
startTransaction · function
Starts a new transaction for database operations.
Signature: () => number
Returns: A transaction ID (positive integer) to be used in subsequent operations
Throws:
- DatabaseError if the transaction cannot be created
commitTransaction · function
Commits the transaction with the given ID.
If the transaction is read-only, returns the commit sequence number immediately. If the transaction has modifications, returns a Promise that resolves to the commit sequence when the commit completes.
Signature: (transactionId: number) => number | Promise<number>
Parameters:
transactionId- The ID of the transaction to commit
Returns: For read-only transactions: the commit sequence number (synchronous) For write transactions: a Promise that resolves to the commit sequence number (0 when the transaction failed due to conflicts)
Throws:
- DatabaseError if the transaction cannot be committed
abortTransaction · function
Aborts the transaction with the given ID, discarding all changes.
Signature: (transactionId: number) => void
Parameters:
transactionId- The ID of the transaction to abort
Throws:
- DatabaseError if the transaction cannot be aborted
get · function
Retrieves a value for the given key within a transaction.
Signature: (transactionId: number, key: ArrayBufferLike) => ArrayBuffer
Parameters:
transactionId- The ID of the transactionkey- Key to look up
Returns: The value if found, or undefined if the key doesn't exist
Throws:
- DatabaseError if the operation fails
put · function
Stores a key-value pair within a transaction.
Signature: (transactionId: number, key: ArrayBufferLike, value: ArrayBufferLike) => void
Parameters:
transactionId- The ID of the transactionkey- Key to storevalue- Value to store
Throws:
- DatabaseError if the operation fails
del · function
Deletes a key-value pair within a transaction.
Signature: (transactionId: number, key: ArrayBufferLike) => void
Parameters:
transactionId- The ID of the transactionkey- Key to delete
Throws:
- DatabaseError if the operation fails
createIterator · function
Creates an iterator for scanning a range of keys within a transaction.
Signature: (transactionId: number, startKey?: ArrayBufferLike, endKey?: ArrayBufferLike, reverse?: boolean) => number
Parameters:
transactionId- The ID of the transactionstartKey- Optional key to start iteration from (inclusive)endKey- Optional key to end iteration at (exclusive)reverse- If true, keys are returned in descending order
Returns: An iterator ID to be used with readIterator() and closeIterator()
Throws:
- DatabaseError if the operation fails
readIterator · function
Reads the next key-value pair from an iterator.
Signature: (iteratorId: number) => { key: ArrayBuffer; value: ArrayBuffer; }
Parameters:
iteratorId- The ID of the iterator
Returns: An object containing the key and value, or undefined if iteration is complete
Throws:
- DatabaseError if the operation fails
closeIterator · function
Closes an iterator when it's no longer needed.
Signature: (iteratorId: number) => void
Parameters:
iteratorId- The ID of the iterator to close
Throws:
- DatabaseError if the operation fails
DatabaseError · constant
The DatabaseError class is used to represent errors that occur during database operations. It extends the built-in Error class and has a machine readable error code string property.
The lowlevel API will throw DatabaseError instances for all database-related errors. Invalid function arguments will throw TypeError.
Value: DatabaseErrorConstructor
DatabaseErrorConstructor · interface
Constructor interface for DatabaseError.
databaseErrorConstructor.new · constructor
Creates a new DatabaseError with the specified message and code.
databaseErrorConstructor.prototype · member
Type: DatabaseError