Skip to main content

qualia_client_core/wellfair/
graph_query.rs

1//! Bounded graph query — map journal record IDs to materialized quin counts.
2
3use qualia_core_db::NQuin;
4use wellfare_core::record::q_hash_str;
5
6use super::journal::JournalEntry;
7
8#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
9pub struct GraphCoverageRow {
10    pub record_id: String,
11    pub kind: String,
12    pub quin_count: usize,
13}
14
15/// Count quins whose subject field matches the FNV-1a hash of `record_id`.
16pub fn count_quins_for_record(quins: &[NQuin], record_id: &str) -> usize {
17    let subject = q_hash_str(record_id);
18    quins.iter().filter(|q| q.subject == subject).count()
19}
20
21/// For each journal row, report how many materialized quins reference that record id.
22pub fn coverage_for_journal(journal: &[JournalEntry], quins: &[NQuin]) -> Vec<GraphCoverageRow> {
23    journal
24        .iter()
25        .map(|entry| GraphCoverageRow {
26            record_id: entry.id.clone(),
27            kind: entry.kind.clone(),
28            quin_count: count_quins_for_record(quins, &entry.id),
29        })
30        .collect()
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use qualia_core_db::NQuin;
37
38    #[test]
39    fn count_quins_matches_subject_hash() {
40        let record_id = "urn:wellfair:weight:abc";
41        let subject = q_hash_str(record_id);
42        let quins = [
43            NQuin {
44                subject,
45                predicate: 1,
46                object: 2,
47                context: 3,
48                metadata: 0,
49                parity: 0,
50            },
51            NQuin {
52                subject: 99,
53                predicate: 1,
54                object: 2,
55                context: 3,
56                metadata: 0,
57                parity: 0,
58            },
59        ];
60        assert_eq!(count_quins_for_record(&quins, record_id), 1);
61    }
62}