Time Travel
Because every change is recorded as a engram, patinaDB can answer read queries against the graph as it was at any past engram. The state is reconstructed (nearest snapshot + forward delta replay) into a temporary view, and your query runs against that view. The live graph is never modified.
CLI
patinadb ./mygraph query \
"MATCH (n:Person) RETURN n.name" \
--at <engram-id>
Without --at, the query runs against the current (HEAD) state.
Embedded
Dataset::query takes an optional at: Option<Uuid>:
#![allow(unused)]
fn main() {
// HEAD
ds.query("MATCH (n) RETURN n", None)?;
// As of a specific engram
ds.query("MATCH (n) RETURN n", Some(engram_id))?;
}
Server (USE … AS OF)
In the server, prefix a read with USE <db> AS OF '<engram-id>' to travel
back in a specific database:
USE sales AS OF '<engram-id>'
MATCH (o:Order) RETURN count(o)
Over REST you can equivalently pass an at field in the request body; over Bolt
the USE … AS OF prefix is parsed per query.
Semantics & constraints
- Reads only. Time travel reconstructs a read-only past view. You cannot write to the past or “restore” the database to an old state through time travel (that’s a different operation — full snapshot import/export).
- Consistent point-in-time. A time-travel query sees the entire graph as it was at that engram — a coherent snapshot, not a mix of old and new.
- Cost. Reconstruction is bounded by the distance from the nearest snapshot to the target engram. Frequent snapshots (see Engrams) keep this cheap; querying a point far from any snapshot replays more deltas.
Tags — named, snapshotted points in history
A tag is a stable name for a engram (like a git tag), so you can time-travel to a meaningful point without tracking raw engram ids. Creating a tag also pins and snapshots its engram:
- Pinned — a tagged engram is protected from squash: compaction never collapses it, so the point-in-time it names stays reachable.
- Snapshotted — a full snapshot is taken at the tagged engram, so reading
AS OFthat tag is cheap (no long delta replay), however old it is.
CREATE TAG v1 -- tag the current HEAD
CREATE TAG release AS OF '<engram-uuid>' -- tag a specific engram
SHOW TAGS -- list name → engram
DROP TAG v1 -- remove (unpins if no other tag references it)
Read a database as it was at a tag:
USE default AS OF TAG 'v1' MATCH (n) RETURN n
On a cluster, CREATE TAG / DROP TAG replicate through Raft — every node
names, pins, and snapshots the same engram — so AS OF TAG and SHOW TAGS
work against any node (including followers). SHOW TAGS is a local read;
CREATE/DROP TAG need admin and go through the leader.