Time travel
Nothing is overwritten, so the past is a query away. This page is for anyone who saw Reef’s time-travel slider and wants the same thing in their app.
See it in Reef
Section titled “See it in Reef”
src/app/screens/BoardScreen.tsx:448-454 The slider’s ceiling is the current version number t — the number every write gets, in order (glossary). Its value picks a view of the database:
const maxT = useBasis(db); const [scrubbed, setScrubbed] = useState<number | null>(null); const t = scrubbed ?? maxT; // Until the basis lands, read the live view — the same rows the board // already shows — so the hook order never varies. const past = useQuery(t === undefined ? db : db.asOf(t), boardQuery); const everything = useQuery(db.history, everyIssueEverQuery);boardQuery is the same value the live board uses. Nothing was copied or exported.
asOf(t): the database as it was
Section titled “asOf(t): the database as it was”db.asOf(t) is a read-only view of the database exactly as it was right after version t (glossary). Queries and pulls run over it unchanged. It takes a version number, not a date; and you cannot write into it — the view has no transact.
// …and the same query as of a past transaction. `asOf` is pure. const beforeRows = yield* db .asOf(report.t - 1) .q(Ramose.query(User).select({ name: User.name }));Calling asOf costs nothing; the read happens when you run the query.
Where t comes from
Section titled “Where t comes from”- From a write.
report.tis the version your write produced. - From the database.
db.basis()answers{ t }for the newest version; in React,useBasis(db)keeps it current, which is how Reef’s slider knows its ceiling. - From your own records. Store a
tyou care about and read at it later.
history: including what was deleted
Section titled “history: including what was deleted”db.history is a view that also returns facts later removed — one statement about one record’s field (glossary). Reef uses it for the “Deleted, still in history” strip: run a plain query over db.history, subtract what the live board shows, and what is left was deleted.
/** Over `db.history` this also returns issues that no longer exist. */export const everyIssueEverQuery = Ramose.query(Issue).select({ id: Issue.id, title: Issue.title,});Use it for audit trails, “who changed this”, and debugging state that no longer exists.
Live queries over the past
Section titled “Live queries over the past”A live query over asOf(t) or history emits once and stops — a pinned view has no news.
Rules still apply
Section titled “Rules still apply”Reads over asOf and history are filtered by the current policy: a field you may not read now is missing from the past too, and a removed permission cannot re-grant access to what it once allowed.
How far back?
Section titled “How far back?”History is kept as version numbers, not dates: asOf takes a t. Nothing prunes history — RAMOSE_RETAIN_ROOTS bounds how much storage the index costs, not how far back asOf reads. A read opens the current index and hides facts newer than your t, so asOf reaches the database’s very first version no matter how many snapshots have been swept — see Retention.