Skip to main content

parse_fixture/
parse_fixture.rs

1//! Parse a captured `_panels` fact dump and report what came out.
2//!
3//! ```bash
4//! cargo run -p datagrout-panels --example parse_fixture -- path/to/facts.json
5//! ```
6//!
7//! The file holds one array of `logic.query` solution rows per goal, keyed
8//! `panels`, `props`, `data`, `sources`, `field_inputs`, `field_triggers`,
9//! `field_emits` (any may be absent). This is how the parser gets checked
10//! against facts a real gateway produced, rather than against fixtures written
11//! from reading the schema — the two differ in exactly the ways that matter.
12
13use std::collections::BTreeMap;
14
15use datagrout_panels::{Panel, PanelFacts};
16use serde_json::Value;
17
18fn main() {
19    let path = std::env::args()
20        .nth(1)
21        .expect("usage: parse_fixture <facts.json>");
22    let raw = std::fs::read_to_string(&path).expect("read fixture");
23    let doc: BTreeMap<String, Value> =
24        serde_json::from_str(&raw).expect("fixture is a JSON object");
25
26    let rows = |key: &str| -> Vec<Value> {
27        doc.get(key)
28            .and_then(Value::as_array)
29            .cloned()
30            .unwrap_or_default()
31    };
32
33    let facts = PanelFacts {
34        panels: rows("panels"),
35        props: rows("props"),
36        data: rows("data"),
37        sources: rows("sources"),
38        field_inputs: rows("field_inputs"),
39        field_triggers: rows("field_triggers"),
40        field_emits: rows("field_emits"),
41    };
42
43    println!(
44        "input rows: panels={} props={} data={} sources={} fields(in/trig/emit)={}/{}/{}",
45        facts.panels.len(),
46        facts.props.len(),
47        facts.data.len(),
48        facts.sources.len(),
49        facts.field_inputs.len(),
50        facts.field_triggers.len(),
51        facts.field_emits.len()
52    );
53
54    let panels = Panel::all_from_facts(&facts);
55    println!("parsed panels: {}\n", panels.len());
56
57    let mut unknown = 0;
58    for p in &panels {
59        let kind = p.kind.as_str().to_string();
60        if matches!(p.kind, datagrout_panels::PanelKind::Unknown(_)) {
61            unknown += 1;
62        }
63        println!(
64            "{:<24} {:<11} ns={:<20} props={:<2} rows={:<3} cols={:<2} source={} fields={} children={} published={}",
65            p.id,
66            kind,
67            p.namespace,
68            p.props.len(),
69            p.rows.len(),
70            p.rows.first().map(Vec::len).unwrap_or(0),
71            p.source.is_some(),
72            p.fields.len(),
73            p.children.len(),
74            p.published
75        );
76        for c in &p.children {
77            println!(
78                "    └ {:<20} {:<11} rows={:<3} columns={:?}",
79                c.id,
80                c.kind.as_str(),
81                c.rows.len(),
82                c.columns()
83            );
84        }
85    }
86
87    // Anything a renderer would fall back on is worth calling out by name.
88    println!("\nunknown kinds: {unknown}");
89    let titled = panels
90        .iter()
91        .filter(|p| p.props.contains_key("title"))
92        .count();
93    println!("panels with a title prop: {titled}/{}", panels.len());
94}