Skip to main content

oxibrain_cli/cmd/
predicate.rs

1//! `oxibrain predicate list` — print the core/v1 predicate registry (DESIGN §5.5, P4).
2//!
3//! No store access needed: the registry is the in-process core ontology.
4
5use oxibrain_core::registry::{CORE_V1_MAJOR, CORE_V1_MINOR, LiteralType, ObjectKind, core_v1};
6
7pub fn run() -> anyhow::Result<()> {
8    let preds = core_v1();
9    println!(
10        "core/v1 registry — {} predicates (major={}, minor={})",
11        preds.len(),
12        CORE_V1_MAJOR,
13        CORE_V1_MINOR
14    );
15    for p in preds {
16        println!("  {}", p.name);
17        println!(
18            "    object={} | cardinality={} | temporality={} | invalidation={} | symmetric={}",
19            format_object_kind(&p.object_kind),
20            p.cardinality.as_db(),
21            p.temporality.as_db(),
22            p.invalidation.as_db(),
23            p.symmetric,
24        );
25        if !p.subject_types.is_empty() {
26            println!("    subjects: {}", p.subject_types.join(", "));
27        }
28        if let Some(inv) = &p.inverse_of {
29            println!("    inverse_of: {inv}");
30        }
31        if !p.description.is_empty() {
32            println!("    {}", p.description);
33        }
34    }
35    Ok(())
36}
37
38fn format_object_kind(k: &ObjectKind) -> String {
39    match k {
40        ObjectKind::Entity(types) => format!("entity:{{{}}}", types.0.join("|")),
41        ObjectKind::Literal(LiteralType::Text) => "literal:text".into(),
42        ObjectKind::Literal(LiteralType::Date) => "literal:date".into(),
43        ObjectKind::Literal(LiteralType::DateTime) => "literal:datetime".into(),
44        ObjectKind::Literal(LiteralType::Number) => "literal:number".into(),
45        ObjectKind::Literal(LiteralType::Bool) => "literal:bool".into(),
46        ObjectKind::Literal(LiteralType::Quantity { unit }) => format!("literal:quantity[{unit}]"),
47        ObjectKind::Enum { variants: vals } => format!("enum:{{{}}}", vals.join("|")),
48    }
49}