Operate

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 always eddytor).
  • Read access to that table - the viewer role is enough.

Read the history

Pass the catalog, schema, and table as separate arguments:

eddytor get history eddytor sales orders

Add --json for machine-readable output you can pipe into jq:

eddytor get history eddytor sales orders --json
GET /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:

FieldMeaning
versionThe version number. 0 is the table's creation; it counts up by one per write.
timestampWhen the commit landed (UTC).
operationWhat happened - CREATE TABLE, MERGE, UPDATE, DELETE, ADD COLUMN, UPDATE FIELD METADATA (a domain change), OPTIMIZE, VACUUM.
userName / userIdWho made the change.
commentAn optional commit message.
operationParametersThe operation's inputs (e.g. the merge predicate).
operationMetricsRow 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 4
POST /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, or UPDATE.
  • current / previous - the row values on each side.
  • changedColumns - for updates, which columns differ.

Heads up

Diff requires at least one primary-key column - it's how rows are matched across versions. It handles schema evolution by comparing only the columns present in both versions.

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.
  • OPTIMIZE and VACUUM are versions too. Maintenance shows up in the history even though it doesn't change your data - don't mistake an OPTIMIZE commit for a data write when picking a rollback target.
  • Timestamps are UTC. restore takes a UTC ISO-8601 timestamp; read it straight from this list rather than converting to local time.

On this page