stac_types/
fields.rs

1use crate::{Error, Result};
2use serde::{de::DeserializeOwned, Serialize};
3use serde_json::{json, Map, Value};
4
5/// Trait for structures that have gettable and settable fields.
6///
7/// # Examples
8///
9/// ```
10/// use stac::{Catalog, Item, Fields};
11///
12/// let mut catalog = Catalog::new("an-id", "a description");
13/// catalog.set_field("foo", "bar");
14/// assert_eq!(catalog.additional_fields.get("foo").unwrap(), "bar");
15///
16/// let mut item = Item::new("an-id");
17/// item.set_field("foo", "bar");
18/// assert_eq!(item.properties.additional_fields.get("foo").unwrap(), "bar");
19/// assert!(item.additional_fields.is_empty());
20/// ```
21pub trait Fields {
22    /// Gets the fields value.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use stac::{Item, Fields};
28    /// let item = Item::new("an-id");
29    /// assert!(item.fields().is_empty());
30    /// ```
31    fn fields(&self) -> &Map<String, Value>;
32
33    /// Gets a mutable reference to the fields value.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use stac::{Item, Fields};
39    /// let mut item = Item::new("an-id");
40    /// item.fields_mut().insert("foo".to_string(), "bar".into());
41    /// ```
42    fn fields_mut(&mut self) -> &mut Map<String, Value>;
43
44    /// Gets the value of a field.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// use stac::{Item, Fields};
50    /// let mut item = Item::new("an-id");
51    /// item.set_field("foo", "bar").unwrap();
52    /// assert_eq!(item.properties.additional_fields.get("foo"), item.field("foo"));
53    /// ```
54    fn field(&self, key: &str) -> Option<&Value> {
55        self.fields().get(key)
56    }
57
58    /// Sets the value of a field.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// use stac::{Item, Fields};
64    /// let mut item = Item::new("an-id");
65    /// item.set_field("foo", "bar").unwrap();
66    /// assert_eq!(item.properties.additional_fields["foo"], "bar");
67    /// ```
68    fn set_field<S: Serialize>(&mut self, key: impl ToString, value: S) -> Result<Option<Value>> {
69        let value = serde_json::to_value(value)?;
70        Ok(self.fields_mut().insert(key.to_string(), value))
71    }
72
73    /// Gets values with a prefix.
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// use stac::{Fields, Item};
79    /// use serde_json::Value;
80    ///
81    /// let item: Item = stac::read("examples/extensions-collection/proj-example/proj-example.json").unwrap();
82    /// let projection: Value = item.fields_with_prefix("proj").unwrap();
83    /// ```
84    fn fields_with_prefix<D: DeserializeOwned>(&self, prefix: &str) -> Result<D> {
85        let mut map = Map::new();
86        let prefix = format!("{}:", prefix);
87        for (key, value) in self.fields().iter() {
88            if key.starts_with(&prefix) && key.len() > prefix.len() {
89                let _ = map.insert(key[prefix.len()..].to_string(), value.clone());
90            }
91        }
92        serde_json::from_value(json!(map)).map_err(Error::from)
93    }
94
95    /// Sets values with a prefix.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use stac::{Fields, Item};
101    /// use serde_json::json;
102    ///
103    /// let projection = json!({ "code": "EPSG:4326" });
104    /// let mut item = Item::new("an-id");
105    /// item.set_fields_with_prefix("proj", projection);
106    /// ```
107    fn set_fields_with_prefix<S: Serialize>(&mut self, prefix: &str, value: S) -> Result<()> {
108        let value = serde_json::to_value(value)?;
109        if let Value::Object(object) = value {
110            for (key, value) in object.into_iter() {
111                let _ = self.set_field(format!("{}:{}", prefix, key), value);
112            }
113            Ok(())
114        } else {
115            Err(Error::NotAnObject(value))
116        }
117    }
118
119    /// Removes values with a prefix.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use stac::{Fields, Item};
125    ///
126    /// let mut item: Item = stac::read("examples/extensions-collection/proj-example/proj-example.json").unwrap();
127    /// item.remove_fields_with_prefix("proj");
128    /// ```
129    fn remove_fields_with_prefix(&mut self, prefix: &str) {
130        let prefix = format!("{}:", prefix);
131        self.fields_mut()
132            .retain(|key, _| !(key.starts_with(&prefix) && key.len() > prefix.len()));
133    }
134}