Skip to main content

orbok_core/
status.rs

1//! Lifecycle status vocabulary shared by the catalog (RFC-002), the
2//! source boundary (RFC-003), and the scanner (RFC-004).
3//!
4//! Each enum maps 1-to-1 onto a CHECK-constrained catalog column. The
5//! `as_str`/`parse` pairs are the single conversion point; repositories
6//! must not hand-write these strings.
7
8use crate::error::OrbokError;
9use serde::{Deserialize, Serialize};
10
11macro_rules! catalog_enum {
12    ($(#[$doc:meta])* $name:ident, $column:literal, { $($variant:ident => $s:literal),+ $(,)? }) => {
13        $(#[$doc])*
14        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15        #[serde(rename_all = "snake_case")]
16        pub enum $name {
17            $($variant),+
18        }
19
20        impl $name {
21            /// Stable catalog string.
22            pub fn as_str(&self) -> &'static str {
23                match self {
24                    $(Self::$variant => $s),+
25                }
26            }
27
28            /// Parse the catalog string; invalid values are catalog
29            /// corruption and surface as a typed error.
30            pub fn parse(s: &str) -> Result<Self, OrbokError> {
31                match s {
32                    $($s => Ok(Self::$variant),)+
33                    other => Err(OrbokError::InvalidCatalogValue {
34                        column: $column,
35                        value: other.to_string(),
36                    }),
37                }
38            }
39        }
40    };
41}
42
43catalog_enum!(
44    /// `sources.source_type` (RFC-003 §5).
45    SourceType,
46    "sources.source_type",
47    { Directory => "directory", File => "file" }
48);
49
50catalog_enum!(
51    /// `sources.persistence_mode` (RFC-003 §5.1–5.2).
52    PersistenceMode,
53    "sources.persistence_mode",
54    { Persistent => "persistent", Temporary => "temporary" }
55);
56
57catalog_enum!(
58    /// `sources.status` (external design §11.2).
59    SourceStatus,
60    "sources.status",
61    {
62        Active => "active",
63        Paused => "paused",
64        Missing => "missing",
65        PermissionDenied => "permission_denied",
66        Removed => "removed",
67    }
68);
69
70catalog_enum!(
71    /// `sources.index_mode` (FR-120 quality modes).
72    IndexMode,
73    "sources.index_mode",
74    {
75        Balanced => "balanced",
76        HighAccuracy => "high_accuracy",
77        SpaceSaving => "space_saving",
78    }
79);
80
81catalog_enum!(
82    /// `sources.hidden_file_policy` (RFC-003 §6.1; default Exclude).
83    HiddenFilePolicy,
84    "sources.hidden_file_policy",
85    { Exclude => "exclude", Include => "include", Warn => "warn" }
86);
87
88catalog_enum!(
89    /// `sources.symlink_policy` (RFC-003 §6.2; default Ignore).
90    SymlinkPolicy,
91    "sources.symlink_policy",
92    {
93        Ignore => "ignore",
94        FollowWithinSource => "follow_within_source",
95        FollowAllWithWarning => "follow_all_with_warning",
96    }
97);
98
99catalog_enum!(
100    /// `files.file_status` (RFC-004 §7).
101    FileStatus,
102    "files.file_status",
103    {
104        Discovered => "discovered",
105        Indexed => "indexed",
106        Stale => "stale",
107        Missing => "missing",
108        Deleted => "deleted",
109        PermissionDenied => "permission_denied",
110        Unsupported => "unsupported",
111        Failed => "failed",
112    }
113);
114
115catalog_enum!(
116    /// `index_jobs.job_type` (RFC-002 §7.9).
117    JobType,
118    "index_jobs.job_type",
119    {
120        Scan => "scan",
121        Extract => "extract",
122        Chunk => "chunk",
123        KeywordIndex => "keyword_index",
124        Embedding => "embedding",
125        DeleteStale => "delete_stale",
126        Rebuild => "rebuild",
127    }
128);
129
130catalog_enum!(
131    /// `index_jobs.status` (RFC-002 §7.9).
132    JobStatus,
133    "index_jobs.status",
134    {
135        Queued => "queued",
136        Running => "running",
137        Succeeded => "succeeded",
138        Failed => "failed",
139        Canceled => "canceled",
140        Blocked => "blocked",
141    }
142);
143
144impl Default for HiddenFilePolicy {
145    fn default() -> Self {
146        HiddenFilePolicy::Exclude
147    }
148}
149
150impl Default for SymlinkPolicy {
151    fn default() -> Self {
152        SymlinkPolicy::Ignore
153    }
154}
155
156impl Default for IndexMode {
157    fn default() -> Self {
158        IndexMode::Balanced
159    }
160}