History & diff
List every version of a table and compare two of them - like git log and git diff for your data.
Because every Eddytor table is a Delta Lake table, every mutation creates a new
numbered version: CREATE TABLE is version 0, then every
MERGE / UPDATE / DELETE / ADD COLUMN / domain change - and maintenance
(OPTIMIZE, VACUUM) too. That transaction log is what makes diffing,
time-travel, rollback, and restore
possible. One batched write of 1000 rows is one version -
batch your writes - and a
comment on significant writes makes good recovery points easy to find
(leave good breadcrumbs).
Before you start
- A table that already exists. The examples use the sample table
eddytor.sales.orders(the catalog is alwayseddytor). - Read access to that table - the
viewerrole is enough.
Read the history
Pass the catalog, schema, and table as separate arguments:
eddytor get history eddytor sales ordersAdd --json for machine-readable output you can pipe into jq:
eddytor get history eddytor sales orders --jsonGET /v1/tables/eddytor/sales/orders/history
Authorization: Bearer edd_live_…Returns a JSON array of version entries, newest first.
Call the get_table_history tool with the fully-qualified name:
{ "table": "eddytor.sales.orders" }In an MCP client (Claude, Cursor) just ask: "Show the history of
eddytor.sales.orders."
Open the table, then select the History tab. Each row is a version; click one to see its operation and metrics.
What you get back
Each entry describes one committed version:
| Field | Meaning |
|---|---|
version | The version number. 0 is the table's creation; it counts up by one per write. |
timestamp | When the commit landed (UTC). |
operation | What happened - CREATE TABLE, MERGE, UPDATE, DELETE, ADD COLUMN, UPDATE FIELD METADATA (a domain change), OPTIMIZE, VACUUM. |
userName / userId | Who made the change. |
comment | An optional commit message. |
operationParameters | The operation's inputs (e.g. the merge predicate). |
operationMetrics | Row counts and file stats (e.g. numOutputRows, numFiles). |
A typical --json response (newest version first). Row counts live inside
operationMetrics, not as a top-level column:
[
{
"version": 4,
"timestamp": "2026-06-22T14:03:11Z",
"operation": "MERGE",
"userName": "ada@acme.io",
"operationParameters": { "predicate": "target.id = source.id" },
"operationMetrics": { "numOutputRows": "120", "numTargetRowsUpdated": "8" }
},
{
"version": 0,
"timestamp": "2026-06-18T11:02:18Z",
"operation": "CREATE TABLE",
"userName": "ada@acme.io",
"operationMetrics": { "numOutputRows": "1000" }
}
]Diff two versions
diff_table_versions compares two versions row-by-row - git diff for table
data. Use it to see exactly what a write changed before deciding whether to
roll back:
eddytor diff table eddytor sales orders --from 2 --to 4POST /v1/tables/eddytor/sales/orders/diff
Authorization: Bearer edd_live_…
{ "versionFrom": 2, "versionTo": 4 }diff_table_versions(table="eddytor.cfg_xxx.<uuid>_orders", from_version=2, to_version=4)Returns, per changed row:
changeType-INSERT,DELETE, orUPDATE.current/previous- the row values on each side.changedColumns- for updates, which columns differ.
Heads up
Verify
The newest entry's version should match the table's current version (shown by
eddytor describe table eddytor sales orders). If you just ran a write, you'll
see a new top row with the matching operation.
Gotchas
- Vacuum truncates how far back you can go - you can still see an old version in the history, but not read, diff, or roll back to it once vacuum has pruned its files.
OPTIMIZEandVACUUMare versions too. Maintenance shows up in the history even though it doesn't change your data - don't mistake anOPTIMIZEcommit for a data write when picking a rollback target.- Timestamps are UTC.
restoretakes a UTC ISO-8601 timestamp; read it straight from this list rather than converting to local time.
Related
- Rollback & restore - reset to a version or timestamp you found here.