Core Concepts
R2D1
R2D1 is a framework-independent Java library that coordinates two storage contracts:
DocumentStoreis authoritative for complete serialized documents and logical existence.IndexStoreis a rebuildable projection containing document identifiers and explicitly indexed fields.
The split is deliberate. It lets an application pair R2 with D1, R2 with JDBC, the filesystem with D1, or the filesystem with JDBC without changing the collection API.
Documents and collections
A document type declares its collection name with @Document. One non-blank String member marked
with @Id supplies the document identifier. @Index marks fields that the index store must keep
for lookup and ordering.
The base library does not impose a serialization format. DocumentCodec is the boundary between a
domain object and the StoredDocument bytes held by the authoritative store.
DocumentStore
The document store exposes asynchronous SPI operations for listing, putting, reading, and deleting serialized documents. The public collection methods wait only at the synchronous facade. R2D1’s R2 and filesystem implementations are document stores; neither is a query engine.
get(id) reads this store directly. An index row does not make a missing document logically exist.
IndexStore
The index store receives one projection entry per document. Each entry contains the document key and
the values of the fields marked with @Index. D1 and JDBC implement this contract.
The index is disposable. rebuildIndex() scans authoritative documents, derives their index
entries, clears the collection’s rows, and writes the replacement projection. The operation is
explicit and non-atomic; run it while writes to the collection are paused.
Queries
R2D1Collection.query() returns an immutable query builder. A query can contain:
- zero or more comparisons against explicitly indexed fields;
- one indexed sort with
ASCorDESCdirection; - one positive result limit; and
- one opaque continuation cursor from a previous page.
Multiple comparisons use logical AND semantics. The public API does not provide joins, arbitrary SQL, OR predicates, full-text search, regular expressions, or client-side filtering.
Cursor pagination
fetch() returns a Page<T>. items() contains the documents for the current page and
nextCursor() is non-null when another page is available. Pass that value to after(...) on a new
query with the same filters and sort.
The cursor belongs to the adapter that created it. Applications should treat it as an opaque string, not decode or edit it. Adapter ordering includes a deterministic document identifier tie-breaker so equal sort values do not make the page boundary ambiguous.
