feat(ui): relationships sidebar panel + schema data (#21, ADR-0046 DB2/DB4)
The left column now stacks a Tables panel over a Relationships panel.
Each relationship renders as three narrow lines — its name, then the
endpoints broken at the arrow (Customers.id -> / indented
Orders.customer_id) — ellipsized past the inner width. The panel is
content-sized within [5 rows ("(none)" when empty), half the column];
the Tables panel keeps the rest (>=3 rows). Phase C adds focus+scroll
for content beyond the cap (clipped for now).
Data path: a new worker Request::ReadAllRelationships +
Database::read_all_relationships returns full RelationshipSchema
records; the runtime posts them via a RelationshipsRefreshed event
alongside the schema-cache refresh, and the App holds them in a new
`relationships` field.
ADR deviation (recorded in ADR-0046 DB2 + index): DB2 specified this
data on SchemaCache; it lives on the App instead — SchemaCache is
walker/completion-facing and needs only relationship names (untouched),
while the full records are UI-only, so App is the cleaner home and it
avoids editing ~23 SchemaCache literals. No behavioural difference.
Tests: panel-height bounds, the three-line render, the empty "(none)"
case, a snapshot, read_all_relationships end-to-end (real DB via the
m:n junction), and the event->field handler.
This commit is contained in:
@@ -416,3 +416,40 @@ fn pk_less_parent_is_refused() {
|
||||
assert!(format!("{err}").contains("no primary key"), "got: {err}");
|
||||
});
|
||||
}
|
||||
|
||||
/// ADR-0046 DB2: the worker's `read_all_relationships` returns full
|
||||
/// schema records (name, parent/child tables + columns, actions) — the
|
||||
/// data source for the sidebar relationships panel. Exercised through
|
||||
/// the real worker thread after an m:n junction creates two of them.
|
||||
#[test]
|
||||
fn read_all_relationships_returns_the_junction_relationships() {
|
||||
let (_project, db, _dir) = open();
|
||||
rt().block_on(async {
|
||||
serial_pk_table(&db, "Students").await;
|
||||
serial_pk_table(&db, "Courses").await;
|
||||
db.create_m2n_relationship("Students".to_string(), "Courses".to_string(), None, None)
|
||||
.await
|
||||
.expect("create m:n");
|
||||
|
||||
let rels = db
|
||||
.read_all_relationships()
|
||||
.await
|
||||
.expect("read all relationships");
|
||||
assert_eq!(
|
||||
rels.len(),
|
||||
2,
|
||||
"the m:n junction creates two relationships: {rels:?}"
|
||||
);
|
||||
// Both have the junction (Students_Courses) as their child.
|
||||
for r in &rels {
|
||||
assert_eq!(r.child_table, "Students_Courses", "child is the junction: {r:?}");
|
||||
}
|
||||
// One points back to each parent.
|
||||
let parents: std::collections::BTreeSet<&str> =
|
||||
rels.iter().map(|r| r.parent_table.as_str()).collect();
|
||||
assert!(
|
||||
parents.contains("Students") && parents.contains("Courses"),
|
||||
"one relationship per parent: {rels:?}"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user