pcm_engine/
versioning.rs

1//! Catalog Versioning System
2//!
3//! Manages catalog versions, allowing for version control, rollback, and A/B testing
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9/// Catalog version
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct CatalogVersion {
12    pub id: Uuid,
13    pub catalog_id: Uuid,
14    pub version: String,
15    pub description: Option<String>,
16    pub created_at: DateTime<Utc>,
17    pub created_by: Option<Uuid>,
18    pub is_active: bool,
19    pub is_published: bool,
20    pub published_at: Option<DateTime<Utc>>,
21    pub metadata: Option<serde_json::Value>,
22}
23
24/// Version manager for catalogs
25pub struct VersionManager {
26    versions: Vec<CatalogVersion>,
27}
28
29impl VersionManager {
30    /// Create a new version manager
31    pub fn new() -> Self {
32        Self {
33            versions: Vec::new(),
34        }
35    }
36
37    /// Create a new version
38    pub fn create_version(
39        &mut self,
40        catalog_id: Uuid,
41        version: String,
42        description: Option<String>,
43        created_by: Option<Uuid>,
44    ) -> CatalogVersion {
45        let catalog_version = CatalogVersion {
46            id: Uuid::new_v4(),
47            catalog_id,
48            version,
49            description,
50            created_at: Utc::now(),
51            created_by,
52            is_active: false,
53            is_published: false,
54            published_at: None,
55            metadata: None,
56        };
57        self.versions.push(catalog_version.clone());
58        catalog_version
59    }
60
61    /// Publish a version
62    pub fn publish_version(&mut self, version_id: Uuid) -> Result<(), String> {
63        let catalog_id = {
64            let version = self
65                .versions
66                .iter()
67                .find(|v| v.id == version_id)
68                .ok_or_else(|| "Version not found".to_string())?
69                .catalog_id;
70            version
71        };
72
73        // Deactivate all other versions of the same catalog
74        for v in self.versions.iter_mut() {
75            if v.catalog_id == catalog_id && v.id != version_id {
76                v.is_active = false;
77            }
78        }
79
80        // Activate the target version
81        if let Some(version) = self.versions.iter_mut().find(|v| v.id == version_id) {
82            version.is_active = true;
83            version.is_published = true;
84            version.published_at = Some(Utc::now());
85        }
86
87        Ok(())
88    }
89
90    /// Rollback to a previous version
91    pub fn rollback_to_version(&mut self, version_id: Uuid) -> Result<(), String> {
92        self.publish_version(version_id)
93    }
94
95    /// Get active version for a catalog
96    pub fn get_active_version(&self, catalog_id: Uuid) -> Option<&CatalogVersion> {
97        self.versions
98            .iter()
99            .find(|v| v.catalog_id == catalog_id && v.is_active)
100    }
101
102    /// Get all versions for a catalog
103    pub fn get_versions(&self, catalog_id: Uuid) -> Vec<&CatalogVersion> {
104        self.versions
105            .iter()
106            .filter(|v| v.catalog_id == catalog_id)
107            .collect()
108    }
109
110    /// Compare two versions
111    pub fn compare_versions(
112        &self,
113        version_id_1: Uuid,
114        version_id_2: Uuid,
115    ) -> Result<VersionDiff, String> {
116        let v1 = self
117            .versions
118            .iter()
119            .find(|v| v.id == version_id_1)
120            .ok_or_else(|| "Version 1 not found".to_string())?;
121        let v2 = self
122            .versions
123            .iter()
124            .find(|v| v.id == version_id_2)
125            .ok_or_else(|| "Version 2 not found".to_string())?;
126
127        Ok(VersionDiff {
128            version_1: v1.clone(),
129            version_2: v2.clone(),
130            differences: vec![], // Would contain actual diff in real implementation
131        })
132    }
133}
134
135impl Default for VersionManager {
136    fn default() -> Self {
137        Self::new()
138    }
139}
140
141/// Version comparison result
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct VersionDiff {
144    pub version_1: CatalogVersion,
145    pub version_2: CatalogVersion,
146    pub differences: Vec<String>,
147}