Skip to main content

curriculum/
curriculum.rs

1//! Schema-aware n-ary relations for simple curriculum records.
2
3use std::collections::BTreeMap;
4
5use relmath::NaryRelation;
6
7fn main() -> Result<(), relmath::NaryRelationError> {
8    let progress = NaryRelation::from_named_rows(
9        ["student", "course", "status"],
10        [
11            BTreeMap::from([
12                ("course", "Math"),
13                ("status", "passed"),
14                ("student", "Alice"),
15            ]),
16            BTreeMap::from([
17                ("course", "Physics"),
18                ("status", "passed"),
19                ("student", "Alice"),
20            ]),
21            BTreeMap::from([("course", "Math"), ("status", "passed"), ("student", "Bob")]),
22            BTreeMap::from([
23                ("course", "Physics"),
24                ("status", "in_progress"),
25                ("student", "Bob"),
26            ]),
27            BTreeMap::from([
28                ("course", "Math"),
29                ("status", "passed"),
30                ("student", "Cara"),
31            ]),
32        ],
33    )?;
34    let course_rooms = NaryRelation::from_named_rows(
35        ["course", "room"],
36        [
37            BTreeMap::from([("course", "Math"), ("room", "R101")]),
38            BTreeMap::from([("course", "Physics"), ("room", "R201")]),
39            BTreeMap::from([("course", "History"), ("room", "R301")]),
40        ],
41    )?;
42
43    let completed = progress
44        .select(|row| row[2] == "passed")
45        .project(["student", "course"])?;
46    let scheduled = completed.natural_join(&course_rooms);
47    let by_room = scheduled.group_by(["room"])?;
48    let room_r101 = by_room.group(&["R101"]).expect("expected R101 group");
49    let room_assignments = scheduled.project(["room", "student"])?;
50    let exported_assignments = room_assignments.to_named_rows();
51
52    assert!(completed.contains_row(&["Alice", "Math"]));
53    assert_eq!(
54        scheduled.schema(),
55        &[
56            "student".to_string(),
57            "course".to_string(),
58            "room".to_string(),
59        ]
60    );
61    assert_eq!(
62        scheduled.to_rows(),
63        vec![
64            vec!["Alice", "Math", "R101"],
65            vec!["Alice", "Physics", "R201"],
66            vec!["Bob", "Math", "R101"],
67            vec!["Cara", "Math", "R101"],
68        ]
69    );
70    assert_eq!(by_room.key_schema(), &["room".to_string()]);
71    assert_eq!(by_room.member_schema(), scheduled.schema());
72    assert_eq!(by_room.counts(), vec![(vec!["R101"], 3), (vec!["R201"], 1)]);
73    assert_eq!(
74        room_r101.to_rows(),
75        vec![
76            vec!["Alice", "Math", "R101"],
77            vec!["Bob", "Math", "R101"],
78            vec!["Cara", "Math", "R101"],
79        ]
80    );
81    assert_eq!(
82        room_assignments.to_rows(),
83        vec![
84            vec!["R101", "Alice"],
85            vec!["R101", "Bob"],
86            vec!["R101", "Cara"],
87            vec!["R201", "Alice"],
88        ]
89    );
90    assert_eq!(
91        exported_assignments[0],
92        BTreeMap::from([
93            ("room".to_string(), "R101"),
94            ("student".to_string(), "Alice"),
95        ])
96    );
97
98    println!("scheduled course completions: {:?}", scheduled.to_rows());
99
100    Ok(())
101}