RethinkDBStore

Read this page in the documentation

RethinkDBStore Reference documentation for RethinkDBStore, the ORM's store for RethinkDB. Source: src/nosql/rethinkdb/index.ts · Tests: tests/nosql/rethinkdb.test.ts Overview RethinkDB is a document store whose queries are built by chaining methods on a term-builder (r) and executed with a trailing .run() — for example r.table('users').filter({ active: true }).run(conn). That fluent, function-composition query model is nothing like the SQL-shaped Dialect interface (no query(sql), no identifier escaping, no relational DDL). Because of this, RethinkDBStore implements only the minimal NoSqlStore marker interface (src/nosql/store.ts) for connection lifecycle, and otherwise exposes RethinkDB's real surface directly: document CRUD, ReQL filter predicates, table/database creation, and a run() escape hatch for arbitrary ReQL terms. Identity: The NoSqlStore interface it implements requires only name, library, connect(), disconnect(), isConnected(), and getClient(). Lazy driver loading The store uses the rethinkdb-ts driver, but it is not a hard dependency. The driver is lazily required inside connect(), so importing this module never forces rethinkdb-ts to be installed: Alternatively, an already-built term-builder (r) and/or an established connection can be injected via the constructor options. When r is injected, connect() uses it as-is and does not require('rethinkdb-ts') (this is how the tests inject a mock, and it is handy when a pool is managed elsewhere). Pool mode vs single-connection mode connect() chooses a mode based on the options: Pool mode (driver-managed): when no connection is injected and no r is injected, connect() stands up a driver-managed connection pool via r.connectPool({ servers: [{ host, port }], db }). Queries then execute with query.run() (no argument) and the pool routes them. Single-connection mode: when a connection is injected, queries execute with query.run(this.connection) against that one connection instead of a driver-managed pool. The choice is centralized in one private helper: Note: when r is injected without a connection (e.g. in the tests), connect() creates no pool of its own — queries run via the injected r's own pool, so connectPool is never called. Constructor options Defaults: host = 'localhost', port = 28015, db = 'test'. Connection Real driver (pool mode) connect() is idempotent: if already connected with a live r, it returns early without reconnecting. Injected term-builder Injected connection (single-connection mode) getClient() getClient() returns the underlying rethinkdb-ts term-builder (r). Use it to build ReQL terms to hand to run(): It throws a ConnectionError if called before connect(). Methods All query methods route through a private exec() helper that resolves the term-builder (throwing ConnectionError if not connected), builds the ReQL term, executes it via runQuery() (.run() in pool mode or .run(connection) in single-connection mode), and wraps any driver failure in a DatabaseError whose message keeps the action context and appends the underlying driver error text (e.g. RethinkDB insert failed: duplicate primary key). Connection lifecycle Resolves the term-builder (injected r, or lazily require('rethinkdb-ts')), sets up pool mode or single-connection mode, and marks the store connected. Idempotent when already connected. On any error it resets internal state and throws a ConnectionError (a message containing ECONNREFUSED becomes 'Connection refused'). If an injected connection with a close() method is present, closes it; otherwise, if r.getPoolMaster() yields a pool master with drain(), drains the pool. Errors are wrapped as DatabaseError (RethinkDB disconnect failed). Internal state (r, connection, connected) is always reset in a finally block, even on error. Returns true only when connected and the term-builder is present (this.connected && this.r !== null). Returns the underlying r term-builder. Throws ConnectionError if not connected. Document CRUD Builds r.table(table).insert(doc).run(). Accepts a single document or an array of documents. Resolves to the driver's write result (e.g. { inserted: 1, generatedkeys: [...] }). Builds r.table(table).get(id).run(). Fetches a single document by its primary key; resolves to null if not found. Builds r.table(table).get(id).update(patch).run(). Partially updates the document with primary key id, merging patch. Resolves to the write result (e.g. { replaced: 1 }). Builds r.table(table).get(id).delete().run(). Deletes the document with primary key id. Resolves to the write result (e.g. { deleted: 1 }). Builds r.table(table).filter(predicate).run() and returns the matches as an array. predicate is any ReQL filter argument — a match object ({ active: true }) or a predicate function (row => row('age').gt(18)). The result is materialized before returning: a private toArray() helper drains a ReQL cursor via result.toArray() when present, passes arrays through unchanged, and wraps a lone value (or returns [] for null/undefined). Schema / administration Creates a table. Called with one argument, builds r.tableCreate(dbOrName).run() in the connection's default database. Called with two arguments, builds r.db(dbOrName).tableCreate(name).run() in the specified database. Builds r.dbCreate(name).run(). Escape hatch Executes an arbitrary ReQL query term (built from getClient()) for operations not wrapped above. Throws ConnectionError if not connected. In single-connection mode the store's connection is supplied to .run() automatically (via the same runQuery() helper); in pool mode .run() is called with no argument. Driver failures are wrapped as DatabaseError (RethinkDB run failed). Example For anything not wrapped by the convenience methods, drop down to raw ReQL via getClient() and run(): Verification status Unit / mock-verified. The test suite (tests/nosql/rethinkdb.test.ts) is pure unit tests — no network is used and the real rethinkdb-ts driver is not installed in this environment. A mock r term-builder is injected via the constructor, so connect() never requires the real driver. The mock's table(), get(), insert(), update(), delete(), filter(), tableCreate(), dbCreate(), and db() return chainable terms ending in a .run() spy that resolves to canned results, which lets the tests assert both the ReQL chain that gets built and that .run() is called. Verified by the tests: Identity (name/library) and connection lifecycle: isConnected(), idempotent connect(), getClient() returns the injected r, pool drain on disconnect(), and closing an injected connection on disconnect(). That connectPool is not called when an r is injected. CRUD chains: insert → r.table(t).insert(doc).run(); get → .get(id).run(); update → .get(id).update(patch).run(); delete → .get(id).delete().run(). filter builds r.table(t).filter(predicate).run(), returns an array, and drains a cursor result via toArray(). createTable(name), createTable(db, name), and createDatabase(name) chains; the run() escape hatch executes an arbitrary term. Error handling: ConnectionError when operating before connecting or when the driver is not installed (the lazy require('rethinkdb-ts') failure is wrapped); driver errors wrapped as DatabaseError with the original error text preserved in the message. Not covered: connectivity against a live RethinkDB server and real rethinkdb-ts pool behavior have not been exercised. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories