database_replicator/remote/
models.rs1use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct JobSpec {
9 #[serde(rename = "schema_version")]
10 pub version: String,
11 pub command: String, pub source_url: String,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub target_url: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub target_project_id: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub target_branch_id: Option<String>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub target_databases: Option<Vec<String>>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub seren_api_key: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub filter: Option<FilterSpec>,
25 pub options: HashMap<String, serde_json::Value>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct FilterSpec {
30 pub include_databases: Option<Vec<String>>,
31 pub exclude_databases: Option<Vec<String>>,
32 pub include_tables: Option<Vec<String>>,
33 pub exclude_tables: Option<Vec<String>>,
34}
35
36#[derive(Debug, Clone, Deserialize)]
37pub struct JobResponse {
38 pub job_id: String,
39 pub status: String,
40}
41
42#[derive(Debug, Clone, Deserialize)]
43pub struct JobStatus {
44 pub job_id: String,
45 pub status: String, pub created_at: Option<String>,
47 pub started_at: Option<String>,
48 pub completed_at: Option<String>,
49 pub progress: Option<ProgressInfo>,
50 pub error: Option<String>,
51}
52
53#[derive(Debug, Clone, Deserialize)]
54pub struct ProgressInfo {
55 pub current_database: Option<String>,
56 pub databases_completed: usize,
57 pub databases_total: usize,
58 pub message: Option<String>,
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn test_job_spec_serialization() {
67 let mut options = HashMap::new();
68 options.insert("drop_existing".to_string(), serde_json::Value::Bool(true));
69
70 let job_spec = JobSpec {
72 version: "1.0".to_string(),
73 command: "init".to_string(),
74 source_url: "postgresql://source".to_string(),
75 target_url: Some("postgresql://target".to_string()),
76 target_project_id: Some("proj123".to_string()),
77 target_branch_id: Some("brnch456".to_string()),
78 target_databases: Some(vec!["db1".to_string()]),
79 seren_api_key: Some("seren_key".to_string()),
80 filter: Some(FilterSpec {
81 include_databases: Some(vec!["db1".to_string()]),
82 exclude_databases: None,
83 include_tables: None,
84 exclude_tables: None,
85 }),
86 options: options.clone(),
87 };
88
89 let parsed: serde_json::Value = serde_json::to_value(&job_spec).unwrap();
90 assert_eq!(parsed["target_url"], "postgresql://target");
91 assert_eq!(parsed["target_project_id"], "proj123");
92 assert_eq!(parsed["target_branch_id"], "brnch456");
93 assert_eq!(parsed["target_databases"], serde_json::json!(["db1"]));
94 assert_eq!(parsed["seren_api_key"], "seren_key");
95 assert_eq!(
96 parsed["filter"],
97 serde_json::json!({"include_databases": ["db1"], "exclude_databases": null, "include_tables": null, "exclude_tables": null})
98 );
99 assert_eq!(parsed["schema_version"], "1.0");
100
101 let job_spec_none = JobSpec {
103 version: "1.0".to_string(),
104 command: "init".to_string(),
105 source_url: "postgresql://source".to_string(),
106 target_url: Some("postgresql://target".to_string()),
107 target_project_id: None,
108 target_branch_id: None,
109 target_databases: None,
110 seren_api_key: None,
111 filter: None,
112 options,
113 };
114
115 let parsed_none: serde_json::Value = serde_json::to_value(&job_spec_none).unwrap();
116 assert_eq!(parsed_none["target_url"], "postgresql://target");
117 assert!(parsed_none.get("target_project_id").is_none());
118 assert!(parsed_none.get("target_branch_id").is_none());
119 assert!(parsed_none.get("target_databases").is_none());
120 assert!(parsed_none.get("seren_api_key").is_none());
121 assert!(parsed_none.get("filter").is_none());
122 }
123}