QldbStore — Amazon QLDB ledger
Read this page in the documentation
QldbStore — Amazon QLDB ledger Overview Amazon QLDB (Quantum Ledger Database) is a fully managed, append-only, cryptographically verifiable ledger database. Data is written as documents into ledger tables and queried with PartiQL (a SQL-compatible query language). Every revision of every document is retained in an immutable journal; the built-in history(<table>) PartiQL function exposes prior revisions, and each revision carries metadata (document id, version, transaction time, and a content hash) that forms the basis of QLDB's tamper-evidence. QLDB is not a SQL Dialect (no client-side DDL escaping, no row-level UPDATE/DELETE semantics beyond PartiQL), so QldbStore implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — plus the ledger surface shared by this family of stores: append/get/history/verify/query. Identity: Property | Value | --------- | ------------------------------ | name | 'qldb' | library | 'amazon-qldb-driver-nodejs' | The store is built on the official amazon-qldb-driver-nodejs driver, which runs statements inside implicitly-managed, auto-retried transactions via driver.executeLambda(fn). Lazy loading — not a hard dependency amazon-qldb-driver-nodejs is not a hard dependency of this package. The driver is loaded lazily via require() inside connect(), rather than a top-level import. Importing this module therefore does not require the driver to be installed — it is only needed when a QLDB store is actually connected and driving real statements. On construction, the module resolves the QldbDriver constructor from mod.QldbDriver ?? mod.default?.QldbDriver ?? mod.default. Injected client QldbStoreOptions accepts a pre-built client (a QldbDriverLike — anything exposing executeLambda, and optionally getTableNames/close). When provided, connect() uses it verbatim and never loads the driver. This is how the test suite injects a mock driver (no SDK, no network). Connection Build a store from connection options and call connect(). A ledgerName is required — the constructor throws a DatabaseError (code: 'INVALIDCONNECTION') without one. Option | Type | Purpose | ------------ | --------------- | ------------------------------------------------------------------- | ledgerName | string | Required. The QLDB ledger name, e.g. 'my-ledger'. | region | string | AWS region hosting the ledger. Passed through to the driver. | client | QldbDriverLike| A pre-built driver to use directly. When set, the driver is not required. | Injected-client form Methods Every ledger method runs its PartiQL statement inside driver.executeLambda(txn => txn.execute(...).getResultList()). Driver failures are wrapped in a DatabaseError (via DatabaseError.from, preserving the original error and prefixing the message with the failing action); using any method before connect() (or after disconnect()) throws a ConnectionError. Table names are validated against /^[A-Za-z][A-Za-z0-9]$/ before interpolation (QLDB cannot parameterize table names) — an invalid name throws a DatabaseError with code: 'VALIDATIONERROR'. Lifecycle Method | Signature | Behavior | -------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | connect | connect(): Promise<void> | Uses an injected client if provided, otherwise lazy-requires amazon-qldb-driver-nodejs and builds a QldbDriver(ledgerName, region ? { region } : undefined). Idempotent. Wraps failures in ConnectionError. | disconnect | disconnect(): Promise<void> | Calls the driver's optional close() (best-effort) and clears connection state. | isConnected | isConnected(): boolean | true only when connected and a driver is present. | getClient | getClient(): QldbDriverLike | Returns the underlying driver for operations not wrapped here. Throws ConnectionError if not connected. | Ledger surface Method | Signature | PartiQL / driver call | Behavior | ------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | append | append(table: string, data: unknown): Promise<string> | INSERT INTO <table> ? | Inserts data as a new document. Returns the new QLDB documentId (or '' if absent). | get | get(table: string, id: string): Promise<unknown \| null> | SELECT FROM <table> BY docId WHERE docId = ? | Reads the current revision by document id. Returns the first row or null. | history | history(table: string, id: string): Promise<unknown[]> | SELECT FROM history(<table>) AS h WHERE h.metadata.id = ? | Returns every prior revision (including deletions); each entry carries data/metadata/blockAddress/hash. | verify | verify(table: string, id: string): Promise<{ documentId: string; revisions: unknown[] }> | SELECT metadata, blockAddress, hash FROM history(<table>) AS h WHERE h.metadata.id = ? | Returns the tamper-evidence proof material (content hash + version + journal block address). | query | query(statement: string, params?: unknown[]): Promise<unknown[]> | raw PartiQL | Raw PartiQL escape hatch with optional positional params (defaults to []). | tableNames | tableNames(): Promise<string[]> | driver.getTableNames() | Lists active table names. Throws a DatabaseError (code: 'QUERYERROR') if the driver has no getTableNames. | Note: verify returns proof material pulled from history() — it is the data QLDB's server-side digest/proof APIs cryptographically verify a revision against. This store does not itself perform the cryptographic verification. Example Verification status Unit / mock-verified only. The tests in tests/nosql/qldb.test.ts inject a mock QldbDriverLike via QldbStoreOptions.client, so connect() never loads amazon-qldb-driver-nodejs and no AWS call is made. The mock records every PartiQL statement + params (via its executeLambda/execute) and returns canned result lists. What this proves: Each ledger method builds the correct PartiQL statement (INSERT INTO People ?, ... BY docId WHERE docId = ?, history(People), the metadata proof projection) with the expected params. append extracts documentId; get returns the first row or null; history/verify return the full result list. Lifecycle: connecting via an injected driver, idempotent double-connect, disconnect() calling close(), and ConnectionError from getClient() / reads before connect(). Error handling: driver failures wrapped in DatabaseError; invalid table identifiers rejected; tableNames delegating to getTableNames(). What this does not prove: live execution against a real Amazon QLDB ledger, or the server-side cryptographic digest/proof verification. The statement/response shape is verified against the driver's documented contract, but end-to-end execution over the wire has not been exercised here. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories