relay-knowledge 1.1.17

Graph-database-based knowledge graph project.
Documentation
use rusqlite::{Connection, params};

use crate::{
    domain::{ConfidenceScore, ContextGraphFact, ContextGraphFactKind},
    storage::{GraphSearchRequest, StorageError},
};

use super::support::SupportContext;
use crate::storage::sqlite::retrieval::context::{parse_fact_status, version_range};

pub(super) struct EventRow {
    pub(super) id: String,
    pub(super) event_type: String,
    pub(super) occurred_at: Option<String>,
    pub(super) evidence_ids_json: String,
    confidence: u16,
    status: String,
    valid_from_graph_version: u64,
    valid_until_graph_version: Option<u64>,
    pub(super) labels: String,
}

impl EventRow {
    pub(super) fn graph_fact(
        &self,
        context: &SupportContext,
    ) -> Result<ContextGraphFact, StorageError> {
        Ok(ContextGraphFact {
            fact_id: self.id.clone(),
            kind: ContextGraphFactKind::Event,
            subject: self.labels.clone(),
            predicate: self.event_type.clone(),
            object: self.occurred_at.clone(),
            evidence_ids: context.evidence_ids.clone(),
            confidence: ConfidenceScore {
                basis_points: self.confidence,
            },
            status: parse_fact_status(&self.status)?,
            version_range: version_range(
                self.valid_from_graph_version,
                self.valid_until_graph_version,
            )?,
        })
    }
}

pub(super) fn load_events(
    connection: &Connection,
    request: &GraphSearchRequest,
) -> Result<Vec<EventRow>, StorageError> {
    let mut statement = connection.prepare(
        "
        SELECT ge.id, ge.event_type, ge.occurred_at, ge.evidence_ids_json,
               ge.confidence_basis_points, ge.status, ge.valid_from_graph_version,
               ge.valid_until_graph_version, group_concat(ent.label, ' ')
        FROM graph_events ge
        INNER JOIN graph_event_entities gee ON gee.event_id = ge.id
        INNER JOIN entities ent ON ent.id = gee.entity_id
        WHERE ge.status = 'accepted'
          AND ge.created_graph_version <= ?1
          AND ge.valid_from_graph_version <= ?1
          AND (ge.valid_until_graph_version IS NULL OR ge.valid_until_graph_version >= ?1)
        GROUP BY ge.id, ge.event_type, ge.occurred_at, ge.evidence_ids_json,
                 ge.confidence_basis_points, ge.status, ge.valid_from_graph_version,
                 ge.valid_until_graph_version
        ORDER BY ge.occurred_at DESC, ge.id ASC
        ",
    )?;
    let rows = statement.query_map(params![request.graph_version.get()], |row| {
        Ok(EventRow {
            id: row.get(0)?,
            event_type: row.get(1)?,
            occurred_at: row.get(2)?,
            evidence_ids_json: row.get(3)?,
            confidence: row.get(4)?,
            status: row.get(5)?,
            valid_from_graph_version: row.get(6)?,
            valid_until_graph_version: row.get(7)?,
            labels: row.get::<_, Option<String>>(8)?.unwrap_or_default(),
        })
    })?;

    rows.collect::<Result<Vec<_>, _>>()
        .map_err(StorageError::from)
}

pub(super) fn occurred_label(occurred_at: Option<&str>) -> String {
    occurred_at
        .map(|value| format!(" at {value}"))
        .unwrap_or_default()
}

#[cfg(test)]
#[path = "event_tests.rs"]
mod tests;