relay_knowledge/domain/core/
index.rs1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use super::GraphVersion;
6
7#[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 pub const ALL: [Self; 3] = [Self::Bm25, Self::Semantic, Self::Vector];
19
20 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#[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 pub const TEXT: Self = Self::Text;
49
50 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#[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 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#[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
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
101pub struct IndexCursor {
102 pub kind: IndexKind,
103 pub source_scope: String,
104 pub modality: IndexModality,
105 pub index_version: u64,
106 pub indexed_graph_version: GraphVersion,
107 pub state: IndexState,
108 pub last_error: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub source_hash: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub backend_cursor: Option<String>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub model_name: Option<String>,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub model_dimension: Option<u32>,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct IndexLag {
122 pub kind: IndexKind,
123 pub lag_versions: u64,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
128pub struct IndexStalenessReason {
129 pub kind: IndexKind,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub source_scope: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub modality: Option<IndexModality>,
134 pub reason: String,
135 pub lag_versions: u64,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub last_error: Option<String>,
138}
139
140#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
142pub struct IndexRefreshDiagnostics {
143 pub queue_depth: usize,
144 pub running_count: usize,
145 pub retrying_count: usize,
146 pub dead_letter_count: usize,
147 pub oldest_unfinished_age_ms: Option<u64>,
148 pub index_lag_by_kind: Vec<IndexLag>,
149 pub max_index_lag_versions: u64,
150 pub stale_index_count: usize,
151 pub stale_reasons: Vec<IndexStalenessReason>,
152}
153
154impl IndexStatus {
155 pub const fn empty(kind: IndexKind) -> Self {
157 Self {
158 kind,
159 index_version: 0,
160 indexed_graph_version: GraphVersion::ZERO,
161 state: IndexState::Stale,
162 last_error: None,
163 }
164 }
165
166 pub fn is_stale_for(&self, graph_version: GraphVersion) -> bool {
168 self.state != IndexState::Fresh || self.indexed_graph_version < graph_version
169 }
170}
171
172#[cfg(test)]
173#[path = "index_tests.rs"]
174mod tests;