Skip to main content

pacha/model/
mod.rs

1//! Model registry types and operations.
2//!
3//! Provides model versioning, model cards, and lifecycle management.
4
5mod card;
6mod stage;
7mod version;
8
9pub use card::ModelCard;
10pub use stage::ModelStage;
11pub use version::ModelVersion;
12
13use crate::storage::ContentAddress;
14use chrono::{DateTime, Utc};
15use serde::{Deserialize, Serialize};
16use uuid::Uuid;
17
18/// Unique identifier for a registered model.
19#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub struct ModelId(Uuid);
21
22impl ModelId {
23    /// Create a new random model ID.
24    #[must_use]
25    pub fn new() -> Self {
26        Self(Uuid::new_v4())
27    }
28
29    /// Create from a UUID.
30    #[must_use]
31    pub fn from_uuid(uuid: Uuid) -> Self {
32        Self(uuid)
33    }
34
35    /// Get the underlying UUID.
36    #[must_use]
37    pub fn as_uuid(&self) -> &Uuid {
38        &self.0
39    }
40}
41
42impl Default for ModelId {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl std::fmt::Display for ModelId {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(f, "{}", self.0)
51    }
52}
53
54impl std::str::FromStr for ModelId {
55    type Err = uuid::Error;
56
57    fn from_str(s: &str) -> Result<Self, Self::Err> {
58        Ok(Self(Uuid::parse_str(s)?))
59    }
60}
61
62/// Reference to a model (name + version).
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
64pub struct ModelReference {
65    /// Model name.
66    pub name: String,
67    /// Model version.
68    pub version: ModelVersion,
69}
70
71impl ModelReference {
72    /// Create a new model reference.
73    #[must_use]
74    pub fn new(name: impl Into<String>, version: ModelVersion) -> Self {
75        Self { name: name.into(), version }
76    }
77}
78
79impl std::fmt::Display for ModelReference {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        write!(f, "{}:{}", self.name, self.version)
82    }
83}
84
85/// A registered model in the registry.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct Model {
88    /// Unique identifier.
89    pub id: ModelId,
90    /// Model name.
91    pub name: String,
92    /// Model version.
93    pub version: ModelVersion,
94    /// Content address of the artifact.
95    pub content_address: ContentAddress,
96    /// Model card with metadata.
97    pub card: ModelCard,
98    /// Current lifecycle stage.
99    pub stage: ModelStage,
100    /// Registration timestamp.
101    pub created_at: DateTime<Utc>,
102    /// Last updated timestamp.
103    pub updated_at: DateTime<Utc>,
104}
105
106impl Model {
107    /// Create a reference to this model.
108    #[must_use]
109    pub fn reference(&self) -> ModelReference {
110        ModelReference::new(&self.name, self.version.clone())
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_model_id_generation() {
120        let id1 = ModelId::new();
121        let id2 = ModelId::new();
122        assert_ne!(id1, id2);
123    }
124
125    #[test]
126    fn test_model_id_from_str() {
127        let id = ModelId::new();
128        let s = id.to_string();
129        let parsed: ModelId = s.parse().unwrap();
130        assert_eq!(id, parsed);
131    }
132
133    #[test]
134    fn test_model_reference_display() {
135        let reference = ModelReference::new("fraud-detector", ModelVersion::new(1, 2, 3));
136        assert_eq!(reference.to_string(), "fraud-detector:1.2.3");
137    }
138}