Skip to main content

kibana_object_manager/transform/
field_dropper.rs

1//! Field dropper transformer
2//!
3//! Removes specified fields from JSON objects, typically metadata fields
4//! that should not be version controlled.
5
6use crate::etl::Transformer;
7use eyre::Result;
8use serde_json::Value;
9
10/// Transformer that drops specified fields from objects
11///
12/// This is used during export to remove Kibana metadata fields like:
13/// - created_at, updated_at
14/// - created_by, updated_by
15/// - version, count
16/// - managed
17///
18/// # Example
19/// ```
20/// use kibana_object_manager::transform::FieldDropper;
21/// use kibana_object_manager::etl::Transformer;
22/// use serde_json::json;
23///
24/// let dropper = FieldDropper::new(vec!["created_at", "version"]);
25/// let input = json!({
26///     "id": "test",
27///     "created_at": "2024-01-01",
28///     "version": "1.0",
29///     "title": "My Object"
30/// });
31///
32/// let output = dropper.transform(input).unwrap();
33/// assert!(!output.as_object().unwrap().contains_key("created_at"));
34/// assert!(!output.as_object().unwrap().contains_key("version"));
35/// assert_eq!(output["title"], "My Object");
36/// ```
37pub struct FieldDropper {
38    fields: Vec<String>,
39}
40
41impl FieldDropper {
42    /// Create a new field dropper with the specified fields to remove
43    pub fn new(fields: Vec<&str>) -> Self {
44        Self {
45            fields: fields.iter().map(|s| s.to_string()).collect(),
46        }
47    }
48
49    /// Create a field dropper with default Kibana metadata fields
50    ///
51    /// Drops: created_at, created_by, updated_at, updated_by, version, count, managed
52    pub fn default_kibana_fields() -> Self {
53        Self::new(vec![
54            "created_at",
55            "created_by",
56            "updated_at",
57            "updated_by",
58            "version",
59            "count",
60            "managed",
61        ])
62    }
63}
64
65impl Transformer for FieldDropper {
66    type Input = Value;
67    type Output = Value;
68
69    fn transform(&self, mut input: Self::Input) -> Result<Self::Output> {
70        if let Some(obj) = input.as_object_mut() {
71            for field in &self.fields {
72                obj.remove(field);
73            }
74        }
75        Ok(input)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use serde_json::json;
83
84    #[test]
85    fn test_drop_fields() {
86        let dropper = FieldDropper::new(vec!["created_at", "version"]);
87        let input = json!({
88            "id": "test",
89            "created_at": "2024-01-01",
90            "version": "1.0",
91            "title": "My Object"
92        });
93
94        let output = dropper.transform(input).unwrap();
95        let obj = output.as_object().unwrap();
96
97        assert!(!obj.contains_key("created_at"));
98        assert!(!obj.contains_key("version"));
99        assert_eq!(output["id"], "test");
100        assert_eq!(output["title"], "My Object");
101    }
102
103    #[test]
104    fn test_default_kibana_fields() {
105        let dropper = FieldDropper::default_kibana_fields();
106        let input = json!({
107            "id": "test",
108            "created_at": "2024-01-01",
109            "created_by": "user",
110            "updated_at": "2024-01-02",
111            "updated_by": "admin",
112            "version": "1.0",
113            "count": 5,
114            "managed": true,
115            "title": "My Object"
116        });
117
118        let output = dropper.transform(input).unwrap();
119        let obj = output.as_object().unwrap();
120
121        assert!(!obj.contains_key("created_at"));
122        assert!(!obj.contains_key("created_by"));
123        assert!(!obj.contains_key("updated_at"));
124        assert!(!obj.contains_key("updated_by"));
125        assert!(!obj.contains_key("version"));
126        assert!(!obj.contains_key("count"));
127        assert!(!obj.contains_key("managed"));
128        assert_eq!(output["id"], "test");
129        assert_eq!(output["title"], "My Object");
130    }
131
132    #[test]
133    fn test_transform_many() {
134        let dropper = FieldDropper::new(vec!["temp"]);
135        let inputs = vec![
136            json!({"id": "1", "temp": "remove"}),
137            json!({"id": "2", "temp": "remove"}),
138        ];
139
140        let outputs = dropper.transform_many(inputs).unwrap();
141
142        assert_eq!(outputs.len(), 2);
143        assert!(!outputs[0].as_object().unwrap().contains_key("temp"));
144        assert!(!outputs[1].as_object().unwrap().contains_key("temp"));
145    }
146}