Skip to content

fix(cli): render history records in table/csv output#1378

Open
bplatz wants to merge 1 commit into
fix/cli-ledger-flag-1368from
fix/history-table-render-1367
Open

fix(cli): render history records in table/csv output#1378
bplatz wants to merge 1 commit into
fix/cli-ledger-flag-1368from
fix/history-table-render-1367

Conversation

@bplatz

@bplatz bplatz commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Stacked on #1377 (fix/cli-ledger-flag-1368) — base is that branch, not main. Review/merge #1377 first.

Summary

fluree history <entity> with the default (table) output rendered blank cells and ? placeholders instead of the history records, even though --format json returned correct data (#1367).

Root cause

History queries project a select list, so the engine returns each row as a positional JSON array:

  • no predicate filter: [?p, ?v, ?t, ?op]
  • --predicate filter: [?v, ?t, ?op]

The table and CSV formatters instead read each row as an object (row.get("?t"), row.get("?op"), …). On an array every lookup returns None, producing blank t/value cells, a ? op placeholder (the unwrap_or("?")), and a missing predicate column. --format json was unaffected because it prints the raw array verbatim. The gap slipped through because existing history tests only exercised --format json.

Fix

  • Add a HistoryRow accessor that reads rows positionally by array length (4 → [p,v,t,op], 3 → [v,t,op]), still tolerating object-keyed rows defensively.
  • Route both the table and CSV formatters through it.

Output after the fix

+---+----+-------------------------------------------------+-------------------------------------------+
| t | op | predicate                                       | value                                     |
+===========================================================================================...=======+
| 1 | +  | http://www.w3.org/1999/02/22-rdf-syntax-ns#type | ex:Article                                |
| 1 | +  | ex:author                                       | ex:alice                                  |
| 1 | +  | ex:content                                      | Step 1: Check the monitoring dashboard... |
| 1 | +  | ex:name                                         | Deployment Runbook                        |
| 2 | +  | ex:content                                      | ...verify all health checks pass...       |
| 2 | -  | ex:content                                      | Step 1: Check the monitoring dashboard... |
+---+----+-------------------------------------------------+-------------------------------------------+

Tests

  • Unit tests on both formatters covering both array shapes, CSV output, the object-row fallback, and the empty case.
  • Extended the history_shows_changes integration test to assert the default table renders populated cells (no ?), exercising the real local query path.
  • cargo fmt + clippy --all-features --all-targets -D warnings clean.

Closes #1367

The history query projects a select list, so the engine returns each row
as a positional JSON array ([?p, ?v, ?t, ?op], or [?v, ?t, ?op] when
filtered to a single predicate). The table and CSV formatters instead
read each row as an object (row.get("?t"), etc.), so every lookup
returned None: blank t/value cells, a '?' op placeholder, and a missing
predicate column. --format json was unaffected because it prints the raw
array.

Add a HistoryRow accessor that reads rows positionally by array length
(still tolerating object-keyed rows) and route both formatters through
it. Cover the formatters with unit tests for both array shapes plus an
integration assertion that the default table renders populated cells.

Closes #1367
@bplatz bplatz requested review from aaj3f and zonotope June 25, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant