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}