Skip to main content

schema_sync/
cli.rs

1//! Developer: s4gor
2//! Github: https://github.com/s4gor
3//!
4//! CLI-related types and context
5//!
6//! This module contains types used by the CLI layer, particularly
7//! tenant context and operation modes.
8
9use serde::{Deserialize, Serialize};
10
11/// Tenant context for all operations
12///
13/// This ensures that every operation is explicitly scoped to a tenant,
14/// preventing accidental cross-tenant operations.
15#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16pub struct TenantContext {
17    /// The tenant identifier (e.g., schema name in PostgreSQL)
18    pub tenant_id: String,
19}
20
21impl TenantContext {
22    /// Create a new tenant context
23    pub fn new(tenant_id: impl Into<String>) -> Self {
24        Self {
25            tenant_id: tenant_id.into(),
26        }
27    }
28
29    /// Get the tenant identifier
30    pub fn id(&self) -> &str {
31        &self.tenant_id
32    }
33}
34
35/// Operation mode for schema synchronization
36///
37/// Different modes allow the same engine to be used for different purposes:
38/// - Dry-run: Preview changes without applying
39/// - Validation: Check if schemas match (CI mode)
40/// - Sync: Actually apply changes
41/// - Audit: Read-only inspection
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum OperationMode {
44    /// Dry-run mode: calculate and return diff without applying
45    DryRun,
46    /// Validation mode: check if schemas match, exit non-zero if not
47    Validation,
48    /// Sync mode: apply changes to bring schemas in sync
49    Sync,
50    /// Audit mode: read-only inspection, no changes allowed
51    Audit,
52}
53
54/// Output format for diffs and reports
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum OutputFormat {
57    /// Human-readable text output
58    Text,
59    /// Machine-readable JSON output
60    Json,
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_tenant_context() {
69        let tenant = TenantContext::new("tenant_123");
70        assert_eq!(tenant.id(), "tenant_123");
71        assert_eq!(tenant.tenant_id, "tenant_123");
72    }
73
74    #[test]
75    fn test_tenant_context_serialization() {
76        let tenant = TenantContext::new("tenant_123");
77        let json = serde_json::to_string(&tenant).unwrap();
78        let deserialized: TenantContext = serde_json::from_str(&json).unwrap();
79        assert_eq!(tenant, deserialized);
80    }
81
82    #[test]
83    fn test_tenant_context_hash() {
84        let tenant1 = TenantContext::new("tenant_123");
85        let tenant2 = TenantContext::new("tenant_123");
86        let tenant3 = TenantContext::new("tenant_456");
87
88        use std::collections::HashSet;
89        let mut set = HashSet::new();
90        set.insert(tenant1.clone());
91        set.insert(tenant2.clone());
92        assert_eq!(set.len(), 1); // Same tenant_id should hash to same value
93
94        set.insert(tenant3);
95        assert_eq!(set.len(), 2); // Different tenant_id should be different
96    }
97}