1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (c) 2018-2023, agnos.ai UK Ltd, all rights reserved.
//---------------------------------------------------------------

use {
    crate::{FactDomain, GraphConnection, Namespaces, Parameters, Statement, Transaction},
    indoc::formatdoc,
    rdf_store_rs::{consts::DEFAULT_GRAPH_RDFOX, Class},
    std::{ops::Deref, sync::Arc},
};

/// Some simple queries about a [`Class`](Class)
#[derive(Debug, Clone)]
pub struct ClassReport<'a>(pub &'a Class);

impl<'a> std::fmt::Display for ClassReport<'a> {
    /// TODO: Generate a decent looking set of class metrics
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) }
}

impl<'a> ClassReport<'a> {
    pub fn number_of_individuals(
        &self,
        tx: &Arc<Transaction>,
    ) -> Result<usize, rdf_store_rs::RDFStoreError> {
        let default_graph = DEFAULT_GRAPH_RDFOX.deref().as_display_iri();
        let prefixes = Namespaces::builder()
            .declare(self.0.namespace.clone())
            .build()?;
        let sparql = formatdoc! {r##"
            SELECT DISTINCT ?thing
            WHERE {{
                {{
                    GRAPH ?graph {{
                        ?thing a {self}
                    }}
                }} UNION {{
                        ?thing a {self}
                    BIND({default_graph} AS ?graph)
                }}
            }}
            "##
        };
        tracing::debug!(target: "sparql", "\n{sparql}");
        let count_result = Statement::new(&prefixes, sparql.into())?
            .cursor(
                &tx.connection,
                &Parameters::empty()?.fact_domain(FactDomain::ALL)?,
            )?
            .count(tx);
        #[allow(clippy::let_and_return)]
        count_result
    }

    pub fn number_of_individuals_in_graph(
        &self,
        tx: &Arc<Transaction>,
        graph_connection: &GraphConnection,
    ) -> Result<usize, rdf_store_rs::RDFStoreError> {
        let graph = graph_connection.graph.as_display_iri();
        let prefixes = Namespaces::builder()
            .declare(self.0.namespace.clone())
            .build()?;
        let sparql = formatdoc! {r##"
            SELECT DISTINCT ?thing
            WHERE {{
                GRAPH {graph} {{
                    ?thing a {self}
                }}
            }}
            "##
        };
        tracing::debug!(target: "sparql", "\n{sparql}");
        let count_result = Statement::new(&prefixes, sparql.into())?
            .cursor(
                &graph_connection.data_store_connection,
                &Parameters::empty()?.fact_domain(FactDomain::ALL)?,
            )?
            .count(tx);
        #[allow(clippy::let_and_return)]
        count_result
    }
}