Skip to main content

entrenar/storage/registry/
version.rs

1//! Model version metadata
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7use super::stage::ModelStage;
8
9/// Model version metadata
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ModelVersion {
12    /// Model name
13    pub name: String,
14    /// Version number (monotonically increasing)
15    pub version: u32,
16    /// Current stage
17    pub stage: ModelStage,
18    /// URI to model artifacts
19    pub artifact_uri: String,
20    /// Performance metrics
21    pub metrics: HashMap<String, f64>,
22    /// Tags for organization
23    pub tags: HashMap<String, String>,
24    /// Description
25    pub description: Option<String>,
26    /// Creation timestamp
27    pub created_at: DateTime<Utc>,
28    /// Last promotion timestamp
29    pub promoted_at: Option<DateTime<Utc>>,
30    /// User who last promoted
31    pub promoted_by: Option<String>,
32}
33
34impl ModelVersion {
35    /// Create a new model version
36    pub fn new(name: &str, version: u32, artifact_uri: &str) -> Self {
37        Self {
38            name: name.to_string(),
39            version,
40            stage: ModelStage::None,
41            artifact_uri: artifact_uri.to_string(),
42            metrics: HashMap::new(),
43            tags: HashMap::new(),
44            description: None,
45            created_at: Utc::now(),
46            promoted_at: None,
47            promoted_by: None,
48        }
49    }
50
51    /// Add a metric
52    pub fn with_metric(mut self, name: &str, value: f64) -> Self {
53        self.metrics.insert(name.to_string(), value);
54        self
55    }
56
57    /// Add a tag
58    pub fn with_tag(mut self, key: &str, value: &str) -> Self {
59        self.tags.insert(key.to_string(), value.to_string());
60        self
61    }
62
63    /// Set description
64    pub fn with_description(mut self, desc: &str) -> Self {
65        self.description = Some(desc.to_string());
66        self
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_model_version_new() {
76        let model = ModelVersion::new("test-model", 1, "/path/to/model");
77        assert_eq!(model.name, "test-model");
78        assert_eq!(model.version, 1);
79        assert_eq!(model.stage, ModelStage::None);
80    }
81
82    #[test]
83    fn test_model_version_with_metric() {
84        let model = ModelVersion::new("test", 1, "/path").with_metric("accuracy", 0.95);
85        assert_eq!(model.metrics.get("accuracy"), Some(&0.95));
86    }
87
88    #[test]
89    fn test_model_version_with_tag() {
90        let model = ModelVersion::new("test", 1, "/path").with_tag("framework", "pytorch");
91        assert_eq!(model.tags.get("framework"), Some(&"pytorch".to_string()));
92    }
93
94    #[test]
95    fn test_model_version_with_description() {
96        let model = ModelVersion::new("test", 1, "/path").with_description("A test model");
97        assert_eq!(model.description, Some("A test model".to_string()));
98    }
99}