confql_data_resolver/
values.rs

1use itertools::Itertools;
2use serde_yaml::Value;
3use std::path::Path;
4
5use super::DataResolverError;
6
7pub fn take_sub_value_at_address(
8    value: &mut Value,
9    address: &[&str],
10) -> Result<Value, DataResolverError> {
11    use itertools::FoldWhile::{Continue, Done};
12    return address
13        .iter()
14        .fold_while(Ok(value), |acc, i| match acc.unwrap().get_mut(i) {
15            Some(v) => Continue(Ok(v)),
16            _ => Done(Err(DataResolverError::KeyNotFound(i.to_string()))),
17        })
18        .into_inner()
19        .map(|v| std::mem::replace(v, Value::Null));
20}
21
22pub fn value_from_file(path: &Path) -> Result<Value, DataResolverError> {
23    let file = std::fs::File::open(&path)?;
24    let value = serde_yaml::from_reader::<_, Value>(file)?;
25    Ok(value)
26}
27
28/// Define methods for
29/// * merging one instance of a type into another instance of the same type
30/// * doing the above but instead under a specified key within the target instance
31/// * taking value from a mutable ref
32pub trait Merge {
33    /// Merge another instance into self, mutating self
34    fn merge(&mut self, mergee: Self) -> Result<&mut Self, DataResolverError>;
35    /// Merge another instance into self at a specified key, mutating self
36    fn merge_at(&mut self, key: &str, mergee: Self) -> Result<&mut Self, DataResolverError>;
37    /// Take ownership via mutable reference
38    fn take(&mut self) -> Self;
39}
40
41macro_rules! merge_compat_err {
42    ($self:expr, $mergee:expr) => {
43        Err(DataResolverError::IncompatibleYamlMerge {
44            dst: $self.clone(),
45            src: $mergee,
46        })
47    };
48}
49
50impl Merge for serde_yaml::Value {
51    fn merge(&mut self, mut mergee: Self) -> Result<&mut Self, DataResolverError> {
52        use serde_yaml::Value::{Bool, Mapping, Null, Number, Sequence, String};
53        if let Null = mergee {
54            return Ok(self);
55        }
56        match self {
57            Null => {
58                *self = mergee;
59            }
60            Bool(_) => {
61                if !mergee.is_bool() {
62                    return merge_compat_err! {self, mergee};
63                }
64                *self = mergee;
65            }
66            Number(_) => {
67                if !mergee.is_number() {
68                    return merge_compat_err! {self, mergee};
69                }
70                *self = mergee;
71            }
72            String(_) => {
73                if !mergee.is_string() {
74                    return merge_compat_err! {self, mergee};
75                }
76                *self = mergee;
77            }
78            Sequence(list) => {
79                if let Sequence(ref mut appendee) = mergee {
80                    list.append(appendee);
81                } else {
82                    return merge_compat_err! {self, mergee};
83                }
84            }
85            Mapping(mapping) => {
86                if let Mapping(superimposee) = mergee {
87                    for (key, src) in superimposee {
88                        if let Some(dst) = mapping.get_mut(&key) {
89                            dst.merge(src)?;
90                        } else {
91                            mapping.insert(key, src);
92                        }
93                    }
94                } else {
95                    return merge_compat_err! {self, mergee};
96                }
97            }
98        };
99        Ok(self)
100    }
101    fn merge_at(&mut self, key: &str, mergee: Self) -> Result<&mut Self, DataResolverError> {
102        match self {
103            Self::Mapping(mapping) => {
104                let key: Self = key.into();
105                match mapping.get_mut(&key) {
106                    Some(value) => {
107                        value.merge(mergee)?;
108                    }
109                    None => {
110                        mapping.insert(key, mergee);
111                    }
112                }
113                Ok(self)
114            }
115            Self::Null => {
116                let mut mapping = serde_yaml::Mapping::new();
117                mapping.insert(key.into(), mergee);
118                *self = Self::Mapping(mapping);
119                Ok(self)
120            }
121            _ => Err(DataResolverError::CannotMergeIntoNonMapping(self.clone())),
122        }
123    }
124    /// Returns owned [serde_yaml::Value], leaving [serde_yaml::Value::Null] in
125    /// its place.
126    fn take(&mut self) -> Self {
127        std::mem::replace(self, serde_yaml::Value::Null)
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134    use color_eyre::Result;
135    use indoc::indoc;
136    use test_files::TestFiles;
137    use test_utils::yaml;
138
139    // TODO beyond just a couple of happy tests
140
141    #[test]
142    fn gets_value_from_file() -> Result<()> {
143        let filename = "index.yml";
144        let content = indoc! {"
145			---
146			ok: true
147			go: home
148		"};
149        let mocks = TestFiles::new();
150        mocks.file(filename, content);
151        let file_path = mocks.path().join(filename);
152
153        let read_value = value_from_file(&file_path)?;
154
155        assert_eq!(serde_yaml::to_string(&read_value)?, content);
156        Ok(())
157    }
158
159    #[test]
160    fn takes_sub_value_at_address() -> Result<()> {
161        let mut value = yaml! {"
162            ---
163            my:
164                yaml:
165                    is:
166                        - hella
167                        - deep
168        "};
169
170        let taken = take_sub_value_at_address(&mut value, &["my", "yaml"])?;
171
172        assert_eq!(
173            taken,
174            yaml! {"
175            ---
176            is:
177                - hella
178                - deep
179        "}
180        );
181
182        assert_eq!(
183            value,
184            yaml! {"
185            ---
186            my:
187                yaml:
188        "}
189        );
190
191        Ok(())
192    }
193}