ScyllaStore — ScyllaDB (CQL) wide-column store
Read this page in the documentation
ScyllaStore — ScyllaDB (CQL) wide-column store Overview ScyllaDB is a wide-column, partition-key-based distributed store that is wire- and query-compatible with Apache Cassandra: it speaks the same CQL (Cassandra Query Language) over the same native protocol, so the standard cassandra-driver (DataStax Node.js driver) connects to it unchanged. Its distinguishing trait is a C++, shard-per-core (seastar) architecture aimed at much higher throughput and lower, more predictable latency than the JVM-based Cassandra. Like Cassandra, ScyllaDB deliberately omits joins, arbitrary WHERE-clause filtering, and subqueries: every query must be answerable from a single partition (or an explicitly designed secondary index / materialized view), and data is modelled query-first around partition and clustering keys. That model does not fit the SQL-shaped Dialect interface, so ScyllaStore 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 | 'scylladb' | library | 'cassandra-driver'| 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 ScyllaStoreOptions 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[] | Seed node addresses, e.g. ['127.0.0.1'] or ['10.0.0.1:9042']. | localDataCenter | string | Local data center name (required by the driver's default load-balancing policy). | keyspace | string | Default keyspace to bind the session to. | credentials | { username: string; password: string } | Plain-text auth credentials passed to the driver. | clientOptions | Record<string, unknown> | Escape hatch for any other Client option (pooling, SSL, policies, socketOptions, …). | client | ScyllaClientLike | 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) so the driver can cache query metadata, infer parameter types, and route requests to the shard/replica that owns the partition. 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(): ScyllaClientLike | 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?: ScyllaQueryOptions): Promise<ScyllaResult<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 forwarded via opts. Returns the full driver result (with .rows). | batch | batch(queries: ScyllaBatchQuery[], opts?: ScyllaQueryOptions): Promise<ScyllaResult> | Executes multiple { query, params } statements as a single logged batch (atomic across statements, not isolated). Prepared by default; forward other batch options via opts. | insert | insert(table: string, obj: Record<string, unknown>, opts?: ScyllaQueryOptions): Promise<ScyllaResult> | 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?: ScyllaQueryOptions): Promise<ScyllaResult<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/scylladb.test.ts are fully mock-driven: a fake Client (with connect/execute/batch/shutdown jest spies) is injected via ScyllaStoreOptions.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. 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 letting opts 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 a real ScyllaDB cluster. 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