1use crate::{Error, Result};
2use cql2::Expr;
3use serde::{Deserialize, Serialize};
4use serde_json::{Map, Value};
5use std::{convert::Infallible, str::FromStr};
6
7#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
9#[serde(tag = "filter-lang", content = "filter")]
10pub enum Filter {
11 #[serde(rename = "cql2-text")]
13 Cql2Text(String),
14
15 #[serde(rename = "cql2-json")]
17 Cql2Json(Map<String, Value>),
18}
19
20impl Filter {
21 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 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
59impl TryFrom<Filter> for Expr {
60 type Error = Error;
61 fn try_from(value: Filter) -> Result<Self> {
62 match value {
63 Filter::Cql2Json(json) => {
64 serde_json::from_value(Value::Object(json)).map_err(Error::from)
65 }
66 Filter::Cql2Text(text) => cql2::parse_text(&text).map_err(|e| Error::from(Box::new(e))),
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::Filter;
74 use cql2::Expr;
75 use serde_json::json;
76
77 #[test]
78 fn json() {
79 let filter = Filter::Cql2Json(json!({
80 "filter": {
81 "op" : "and",
82 "args": [
83 {
84 "op": "=",
85 "args": [ { "property": "id" }, "LC08_L1TP_060247_20180905_20180912_01_T1_L1TP" ]
86 },
87 {
88 "op": "=",
89 "args" : [ { "property": "collection" }, "landsat8_l1tp" ]
90 }
91 ]
92 }
93 }
94 ).as_object().unwrap().clone(),
95 );
96 let value = serde_json::to_value(filter).unwrap();
97 assert_eq!(value["filter-lang"], "cql2-json");
98 assert!(value.get("filter").is_some());
99 }
100
101 #[test]
102 fn text() {
103 let filter = Filter::Cql2Text(
104 "id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collection='landsat8_l1tp'"
105 .to_string(),
106 );
107 let value = serde_json::to_value(filter).unwrap();
108 assert_eq!(value["filter-lang"], "cql2-text");
109 assert!(value.get("filter").is_some());
110 }
111
112 #[test]
113 fn expr() {
114 let filter = Filter::Cql2Text(
115 "id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collection='landsat8_l1tp'"
116 .to_string(),
117 );
118 let _: Expr = filter.try_into().unwrap();
119 }
120}