KeyspacesStore — Amazon Keyspaces (for Apache Cassandra)
Read this page in the documentation
KeyspacesStore — Amazon Keyspaces (for Apache Cassandra) Overview Amazon Keyspaces is AWS's serverless, fully managed wide-column store that is compatible with Apache Cassandra: it speaks CQL (Cassandra Query Language) over the same native protocol, so the standard cassandra-driver (DataStax Node.js driver) connects to it unchanged. Like Cassandra, Keyspaces omits joins, arbitrary WHERE-clause filtering, and subqueries: queries are partition-scoped and data is modelled query-first around partition and clustering keys. That model does not fit the SQL-shaped Dialect interface, so KeyspacesStore implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — and exposes CQL execution directly rather than pretending to be a relational dialect. Identity: Property | Value | --------- | -------------------- | name | 'keyspaces' | library | 'cassandra-driver' | Deployment requirements (real clusters) For a real Keyspaces endpoint (not exercised by the mock tests): TLS is mandatory — Keyspaces only accepts encrypted connections, so pass SSL options (e.g. sslOptions with the Starfield / Amazon root CA) through clientOptions. Auth is either service-specific username/password credentials (via credentials) or, preferably, SigV4 request signing using AWS IAM credentials via the aws-sigv4-auth-cassandra-plugin AuthProvider (also passed through clientOptions). Default consistency is LOCALQUORUM; set it via query options / driver profiles as your workload requires. All of these are plain cassandra-driver Client options, so they flow through this store unchanged via clientOptions (or a pre-built client). Lazy loading — not a hard dependency cassandra-driver is an optional peer dependency, not a hard dependency of this package. It is loaded lazily via require('cassandra-driver') inside connect(), rather than a top-level import. Importing this module therefore never forces the driver to be installed — it is only needed when the store actually builds its own client. Injected client KeyspacesStoreOptions accepts a pre-built driver Client (or a compatible mock) via client. When provided, connect() uses it directly and skips require('cassandra-driver') entirely. This is how the test suite injects a mock client (no driver, no network) and how callers can supply a custom-configured Client. Connection Build a store from connection options and call connect(): All connection options are optional: Option | Type | Purpose | ----------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------- | contactPoints | string[] | Keyspaces service endpoint(s), e.g. ['cassandra.us-east-1.amazonaws.com:9142'] (TLS port 9142).| localDataCenter | string | Local data center — typically the AWS region, e.g. 'us-east-1'. | keyspace | string | Default keyspace to bind the session to. | credentials | { username: string; password: string } | Service-specific credentials (or use a SigV4 authProvider via clientOptions). | clientOptions | Record<string, unknown> | Escape hatch for any other Client option — where TLS (sslOptions) and the SigV4 authProvider live. | client | KeyspacesClientLike | A pre-built client (mock or custom config). When set, the driver is not required. | Injected-client form Supply your own client (or a mock) to bypass driver-based client construction: Methods Statements are prepared by default (prepare: true). Driver failures are wrapped in a DatabaseError; using any method before connect() (or after disconnect()) throws a ConnectionError. Lifecycle Method | Signature | Behavior | -------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | connect | connect(): Promise<void> | Uses an injected client if provided, otherwise lazy-requires cassandra-driver and builds a Client from the options, then calls client.connect(). Idempotent; wraps failures in ConnectionError. | disconnect | disconnect(): Promise<void> | Calls client.shutdown() and clears connection state. | isConnected | isConnected(): boolean | true only when connected and a client is present. | getClient | getClient(): KeyspacesClientLike | Returns the underlying Client for anything not wrapped here. Throws ConnectionError if not connected. | CQL execution & helpers Method | Signature | Behavior | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | execute | execute<T = Record<string, unknown>>(query: string, params?: unknown[], opts?: KeyspacesQueryOptions): Promise<KeyspacesResult<T>> | Executes one CQL statement with optional bound params (default []). Prepared by default; pass opts.prepare = false for a one-off. Other driver query options — including consistency (defaults to LOCALQUORUM on Keyspaces) — are forwarded via opts. Returns the full driver result (with .rows). | batch | batch(queries: KeyspacesBatchQuery[], opts?: KeyspacesQueryOptions): Promise<KeyspacesResult> | Executes multiple { query, params } statements as a single logged batch. Prepared by default; forward other batch options via opts. | insert | insert(table: string, obj: Record<string, unknown>, opts?: KeyspacesQueryOptions): Promise<KeyspacesResult> | Builds a parameterized INSERT INTO table (cols…) VALUES (?, ?, …) from obj's keys and executes it (prepared). Throws DatabaseError if obj has no columns. | selectAll | selectAll<T = Record<string, unknown>>(table: string, opts?: KeyspacesQueryOptions): Promise<KeyspacesResult<T>> | Convenience SELECT FROM table. Returns the full driver result (with .rows). | Supporting types Example Verification status Unit / mock-verified only. The tests in tests/nosql/keyspaces.test.ts are fully mock-driven: a fake Client (with connect/execute/batch/shutdown jest spies) is injected via KeyspacesStoreOptions.client. That option makes connect() skip require('cassandra-driver') entirely, so the tests exercise the real store code paths with no driver installed and no network. The real Keyspaces requirements — TLS plus SigV4/credentials auth — are plain driver options and are not exercised here. What this proves: name/library identity, and the connection lifecycle (injected client.connect(), idempotent second connect(), disconnect() calling shutdown(), isConnected() transitions). execute() passing prepare: true by default, defaulting params to [], and forwarding opts (including a LOCALQUORUM consistency) while letting them override; batch() forwarding the query array with prepare: true by default and honoring opts overrides. insert() building the correct parameterized INSERT and throwing for an empty object; selectAll() building SELECT FROM table. Error handling: driver failures wrapped in DatabaseError, and ConnectionError from getClient()/execute() before connect() and when client.connect() fails. What this does not prove: live execution against real Amazon Keyspaces, nor the TLS/SigV4 connection path. Command/parameter shapes are 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