laminar_connectors/mongodb/
change_event.rs1use std::collections::HashMap;
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub enum OperationType {
25 Insert,
27 Update,
29 Replace,
31 Delete,
33 Drop,
35 Rename,
37 Invalidate,
39 DropDatabase,
41 Other(String),
43}
44
45impl OperationType {
46 #[must_use]
49 pub fn as_str(&self) -> &str {
50 match self {
51 Self::Insert => "I",
52 Self::Update => "U",
53 Self::Replace => "R",
54 Self::Delete => "D",
55 Self::Drop => "DROP",
56 Self::Rename => "RENAME",
57 Self::Invalidate => "INVALIDATE",
58 Self::DropDatabase => "DROP_DATABASE",
59 Self::Other(s) => s.as_str(),
60 }
61 }
62}
63
64impl std::fmt::Display for OperationType {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.write_str(self.as_str())
67 }
68}
69
70#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
76pub struct UpdateDescription {
77 pub updated_fields: HashMap<String, serde_json::Value>,
79
80 pub removed_fields: Vec<String>,
82
83 #[serde(default)]
85 pub truncated_arrays: Vec<TruncatedArray>,
86
87 #[serde(default)]
92 pub disambiguated_paths: HashMap<String, serde_json::Value>,
93}
94
95#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
97pub struct TruncatedArray {
98 pub field: String,
100 pub new_size: u32,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
106pub struct Namespace {
107 pub db: String,
109 pub coll: String,
111}
112
113impl Namespace {
114 #[must_use]
116 pub fn full_name(&self) -> String {
117 format!("{}.{}", self.db, self.coll)
118 }
119}
120
121impl std::fmt::Display for Namespace {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(f, "{}.{}", self.db, self.coll)
124 }
125}
126
127#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
133pub struct MongoDbChangeEvent {
134 pub operation_type: OperationType,
136
137 pub namespace: Namespace,
139
140 pub document_key: String,
143
144 pub full_document: Option<String>,
147
148 pub update_description: Option<UpdateDescription>,
150
151 pub cluster_time_secs: u32,
153
154 pub cluster_time_inc: u32,
156
157 pub resume_token: String,
159
160 pub wall_time_ms: i64,
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_operation_type_as_str() {
170 assert_eq!(OperationType::Insert.as_str(), "I");
171 assert_eq!(OperationType::Update.as_str(), "U");
172 assert_eq!(OperationType::Replace.as_str(), "R");
173 assert_eq!(OperationType::Delete.as_str(), "D");
174 assert_eq!(OperationType::Drop.as_str(), "DROP");
175 assert_eq!(OperationType::Rename.as_str(), "RENAME");
176 assert_eq!(OperationType::Invalidate.as_str(), "INVALIDATE");
177 }
178
179 #[test]
180 fn test_namespace_full_name() {
181 let ns = Namespace {
182 db: "mydb".to_string(),
183 coll: "users".to_string(),
184 };
185 assert_eq!(ns.full_name(), "mydb.users");
186 assert_eq!(ns.to_string(), "mydb.users");
187 }
188
189 #[test]
190 fn test_update_description_default() {
191 let ud = UpdateDescription::default();
192 assert!(ud.updated_fields.is_empty());
193 assert!(ud.removed_fields.is_empty());
194 assert!(ud.truncated_arrays.is_empty());
195 assert!(ud.disambiguated_paths.is_empty());
196 }
197
198 #[test]
199 fn test_change_event_serde_roundtrip() {
200 let event = MongoDbChangeEvent {
201 operation_type: OperationType::Insert,
202 namespace: Namespace {
203 db: "test".to_string(),
204 coll: "docs".to_string(),
205 },
206 document_key: r#"{"_id": "abc123"}"#.to_string(),
207 full_document: Some(r#"{"_id": "abc123", "name": "Alice"}"#.to_string()),
208 update_description: None,
209 cluster_time_secs: 1_700_000_000,
210 cluster_time_inc: 1,
211 resume_token: r#"{"_data": "token123"}"#.to_string(),
212 wall_time_ms: 1_700_000_000_000,
213 };
214
215 let json = serde_json::to_string(&event).unwrap();
216 let deserialized: MongoDbChangeEvent = serde_json::from_str(&json).unwrap();
217 assert_eq!(deserialized.operation_type, OperationType::Insert);
218 assert_eq!(deserialized.namespace.db, "test");
219 }
220}