ADR-0016 + Iter 5/6 follow-up: pretty table rendering
Replaces the placeholder pipe-and-dash output with Unicode box-drawing tables for both data results and table-structure listings, per ADR-0016. * New `src/output_render.rs` module with `render_data_table` and `render_structure`. Hand-rolled to match the project's existing CSV/YAML pattern; ~300 lines. * Header-only outer-frame border style: outer ┌─┐│└─┘ box + ├─┤ header underline, no per-row separators. NULL renders as `(null)`; cell newlines/tabs/control chars become `↵`/`→`/`·` as display-only substitutions. * Type-aware column alignment: numeric types right-aligned, everything else left. `DataResult` gains a `column_types: Vec<Option<Type>>` field, populated from the existing metadata lookup at the two query sites in db.rs (no new query paths). * Structure view shows Name | Type | Constraints columns; References / Referenced-by sections retain plain-text format, leaving room for the future relationship-rendering ADR. * 18 new unit tests in output_render.rs (plus 4 insta snapshots for the canonical layouts). Existing assertions in app.rs and walking_skeleton.rs updated to match the new format. Total: 426 passing, 0 failing, 0 skipped (up from 408). Clippy clean.
This commit is contained in:
@@ -298,9 +298,12 @@ fn create_table_flow_updates_tables_list_and_structure_view() {
|
||||
rendered.contains("[ok] create table Customers"),
|
||||
"output should confirm success:\n{rendered}"
|
||||
);
|
||||
// The structure table renders one line per column; the
|
||||
// `id` row shows both the name and its `serial` type
|
||||
// separated by box-drawing characters.
|
||||
assert!(
|
||||
rendered.contains("id serial"),
|
||||
"output should show the structure with the user-facing type:\n{rendered}"
|
||||
rendered.lines().any(|l| l.contains("id") && l.contains("serial")),
|
||||
"output should show the id/serial column row:\n{rendered}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -339,7 +342,10 @@ fn add_column_flow_updates_structure_view() {
|
||||
});
|
||||
assert_eq!(app.current_table, Some(updated));
|
||||
let rendered = rendered_text(&mut app, &Theme::dark(), 80, 24);
|
||||
assert!(rendered.contains("Name text"));
|
||||
assert!(
|
||||
rendered.lines().any(|l| l.contains("Name") && l.contains("text")),
|
||||
"expected the Name/text column row:\n{rendered}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -497,6 +503,7 @@ fn insert_flow_emits_action_and_renders_data() {
|
||||
let data = DataResult {
|
||||
table_name: "Customers".to_string(),
|
||||
columns: vec!["id".to_string(), "Name".to_string()],
|
||||
column_types: vec![Some(Type::Serial), Some(Type::Text)],
|
||||
rows: vec![vec![Some("1".to_string()), Some("Alice".to_string())]],
|
||||
};
|
||||
app.update(AppEvent::DslInsertSucceeded {
|
||||
@@ -545,6 +552,7 @@ fn show_data_for_empty_table_renders_placeholder() {
|
||||
let data = DataResult {
|
||||
table_name: "Customers".to_string(),
|
||||
columns: vec!["id".to_string(), "Name".to_string()],
|
||||
column_types: vec![Some(Type::Serial), Some(Type::Text)],
|
||||
rows: Vec::new(),
|
||||
};
|
||||
app.update(AppEvent::DslDataSucceeded {
|
||||
|
||||
Reference in New Issue
Block a user