Skip to main content

relay_knowledge/domain/core/
index.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use super::GraphVersion;
6
7/// Derived index families maintained from the graph mutation log.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum IndexKind {
11    Bm25,
12    Semantic,
13    Vector,
14}
15
16impl IndexKind {
17    /// All v1 index families required by the hybrid retrieval contract.
18    pub const ALL: [Self; 3] = [Self::Bm25, Self::Semantic, Self::Vector];
19
20    /// Stable storage and API representation.
21    pub const fn as_str(self) -> &'static str {
22        match self {
23            Self::Bm25 => "bm25",
24            Self::Semantic => "semantic",
25            Self::Vector => "vector",
26        }
27    }
28}
29
30impl fmt::Display for IndexKind {
31    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
32        formatter.write_str(self.as_str())
33    }
34}
35
36/// Source modality covered by a derived index cursor.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39pub enum IndexModality {
40    Text,
41    Image,
42    Layout,
43    Table,
44}
45
46impl IndexModality {
47    /// The v1 evidence modality refreshed by BM25, semantic, and vector indexes.
48    pub const TEXT: Self = Self::Text;
49
50    /// Stable storage and API representation.
51    pub const fn as_str(self) -> &'static str {
52        match self {
53            Self::Text => "text",
54            Self::Image => "image",
55            Self::Layout => "layout",
56            Self::Table => "table",
57        }
58    }
59}
60
61impl fmt::Display for IndexModality {
62    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
63        formatter.write_str(self.as_str())
64    }
65}
66
67/// Operational state of a derived index.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69#[serde(rename_all = "snake_case")]
70pub enum IndexState {
71    Fresh,
72    Stale,
73    Failed,
74    Paused,
75}
76
77impl IndexState {
78    /// Stable storage and API representation.
79    pub const fn as_str(self) -> &'static str {
80        match self {
81            Self::Fresh => "fresh",
82            Self::Stale => "stale",
83            Self::Failed => "failed",
84            Self::Paused => "paused",
85        }
86    }
87}
88
89/// Versioned status for a derived index.
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91pub struct IndexStatus {
92    pub kind: IndexKind,
93    pub index_version: u64,
94    pub indexed_graph_version: GraphVersion,
95    pub state: IndexState,
96    pub last_error: Option<String>,
97}
98
99impl IndexStatus {
100    /// Creates the initial stale status for an empty derived index.
101    pub const fn empty(kind: IndexKind) -> Self {
102        Self {
103            kind,
104            index_version: 0,
105            indexed_graph_version: GraphVersion::ZERO,
106            state: IndexState::Stale,
107            last_error: None,
108        }
109    }
110
111    /// Returns whether this index is behind the supplied graph version.
112    pub fn is_stale_for(&self, graph_version: GraphVersion) -> bool {
113        self.state != IndexState::Fresh || self.indexed_graph_version < graph_version
114    }
115}
116
117#[cfg(test)]
118#[path = "index_tests.rs"]
119mod tests;