stac_api/
filter.rs

1use crate::Result;
2use cql2::Expr;
3use serde::{Deserialize, Serialize};
4use serde_json::{Map, Value};
5use std::{convert::Infallible, str::FromStr};
6
7/// The language of the filter expression.
8#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
9#[serde(tag = "filter-lang", content = "filter")]
10pub enum Filter {
11    /// `cql2-text`
12    #[serde(rename = "cql2-text")]
13    Cql2Text(String),
14
15    /// `cql2-json`
16    #[serde(rename = "cql2-json")]
17    Cql2Json(Map<String, Value>),
18}
19
20impl Filter {
21    /// Converts this filter to cql2-json.
22    pub fn into_cql2_json(self) -> Result<Filter> {
23        match self {
24            Filter::Cql2Json(_) => Ok(self),
25            Filter::Cql2Text(text) => {
26                let expr = cql2::parse_text(&text).map_err(Box::new)?;
27                Ok(Filter::Cql2Json(serde_json::from_value(
28                    serde_json::to_value(expr)?,
29                )?))
30            }
31        }
32    }
33
34    /// Converts this filter to cql2-json.
35    pub fn into_cql2_text(self) -> Result<Filter> {
36        match self {
37            Filter::Cql2Text(_) => Ok(self),
38            Filter::Cql2Json(json) => {
39                let expr: Expr = serde_json::from_value(Value::Object(json))?;
40                Ok(Filter::Cql2Text(expr.to_text().map_err(Box::new)?))
41            }
42        }
43    }
44}
45
46impl Default for Filter {
47    fn default() -> Self {
48        Filter::Cql2Json(Default::default())
49    }
50}
51
52impl FromStr for Filter {
53    type Err = Infallible;
54    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
55        Ok(Filter::Cql2Text(s.to_string()))
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::Filter;
62    use serde_json::json;
63
64    #[test]
65    fn json() {
66        let filter = Filter::Cql2Json(json!({
67                  "filter": {
68                    "op" : "and",
69                    "args": [
70                      {
71                        "op": "=",
72                        "args": [ { "property": "id" }, "LC08_L1TP_060247_20180905_20180912_01_T1_L1TP" ]
73                      },
74                      {
75                        "op": "=",
76                        "args" : [ { "property": "collection" }, "landsat8_l1tp" ]
77                      }
78                    ]
79                  }
80                }
81            ).as_object().unwrap().clone(),
82        );
83        let value = serde_json::to_value(filter).unwrap();
84        assert_eq!(value["filter-lang"], "cql2-json");
85        assert!(value.get("filter").is_some());
86    }
87
88    #[test]
89    fn text() {
90        let filter = Filter::Cql2Text(
91            "id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collection='landsat8_l1tp'"
92                .to_string(),
93        );
94        let value = serde_json::to_value(filter).unwrap();
95        assert_eq!(value["filter-lang"], "cql2-text");
96        assert!(value.get("filter").is_some());
97    }
98}