json_predicate/predicate/first_order/
in.rs

1use derive_builder::Builder;
2use serde_json::Value;
3use std::marker::PhantomData;
4
5use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
6use serde::{ser::SerializeStruct, Serialize};
7
8use crate::json_path::JSONPath;
9use crate::predicate::context::PredicateContext;
10use crate::predicate::error::PredicateError;
11use crate::predicate::PredicateImpl;
12
13use super::FirstOrder;
14
15/// The "in" predicate evaluates as true if the referenced element specifies a
16/// value exactly equal to one of the members of a JSON array provided by the
17/// predicate's "value" member.  Equality is determined following the sames
18/// rules specified for the JSON Patch "test" operation in [RFC6901](https://datatracker.ietf.org/doc/html/rfc6901),
19/// Section 4.6, with one exception given for optional case-insensitive
20/// comparisons.
21#[derive(Debug, Clone, PartialEq, Eq, Builder)]
22#[builder(pattern = "owned", setter(into, strip_option))]
23pub struct In {
24    /// Must be a [JSON Pointer](https://tools.ietf.org/html/rfc6901)
25    /// If the "path" member is not specified within the predicate object, it's value is assumed to be an empty string.
26    pub path: Option<JSONPath>,
27    #[builder(default)]
28    pub ignore_case: bool,
29    pub value: Vec<serde_json::Value>,
30}
31
32impl Serialize for In {
33    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34    where
35        S: serde::Serializer,
36    {
37        let mut state = serializer.serialize_struct("In", 3)?;
38        if self.ignore_case {
39            state.serialize_field("op", "in-")?;
40        } else {
41            state.serialize_field("op", "in")?;
42        }
43        state.serialize_field("path", &self.path)?;
44        state.serialize_field("value", &self.value)?;
45        state.end()
46    }
47}
48
49impl<'de> Deserialize<'de> for In {
50    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51    where
52        D: Deserializer<'de>,
53    {
54        #[allow(non_camel_case_types)]
55        enum Field {
56            op,
57            path,
58            value,
59            __ignore,
60        }
61        struct FieldVisitor;
62
63        impl<'de> Visitor<'de> for FieldVisitor {
64            type Value = Field;
65            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
66                formatter.write_str("field identifier")
67            }
68
69            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
70            where
71                E: de::Error,
72            {
73                match value {
74                    "op" => Ok(Field::op),
75                    "path" => Ok(Field::path),
76                    "value" => Ok(Field::value),
77                    _ => Ok(Field::__ignore),
78                }
79            }
80        }
81
82        impl<'de> Deserialize<'de> for Field {
83            #[inline]
84            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
85            where
86                D: Deserializer<'de>,
87            {
88                Deserializer::deserialize_identifier(deserializer, FieldVisitor)
89            }
90        }
91
92        struct VisitorIn<'de> {
93            marker: PhantomData<In>,
94            lifetime: PhantomData<&'de ()>,
95        }
96
97        impl<'de> Visitor<'de> for VisitorIn<'de> {
98            type Value = In;
99            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
100                formatter.write_str("In")
101            }
102
103            #[inline]
104            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
105            where
106                A: MapAccess<'de>,
107            {
108                let mut path: Option<Option<JSONPath>> = None;
109                let mut value: Option<Vec<serde_json::Value>> = None;
110                let mut op: Option<String> = None;
111
112                while let Some(key) = MapAccess::next_key::<Field>(&mut map)? {
113                    match key {
114                        Field::op => {
115                            if op.is_some() {
116                                return Err(serde::de::Error::duplicate_field("op"));
117                            }
118                            op = Some(MapAccess::next_value::<String>(&mut map)?);
119                        }
120                        Field::path => {
121                            if path.is_some() {
122                                return Err(serde::de::Error::duplicate_field("path"));
123                            }
124                            path = Some(MapAccess::next_value::<Option<JSONPath>>(&mut map)?);
125                        }
126                        Field::value => {
127                            if value.is_some() {
128                                return Err(serde::de::Error::duplicate_field("value"));
129                            }
130                            value =
131                                Some(MapAccess::next_value::<Vec<serde_json::Value>>(&mut map)?);
132                        }
133                        Field::__ignore => {}
134                    }
135                }
136
137                let path = path.ok_or(serde::de::Error::missing_field("path"))?;
138                let value = value.ok_or(serde::de::Error::missing_field("value"))?;
139                let op = op.ok_or(serde::de::Error::missing_field("op"))?;
140
141                let ignore_case = match op.as_str() {
142                    "in" => false,
143                    "in-" => true,
144                    _ => {
145                        return Err(serde::de::Error::custom(
146                            "`op` should be either `in` or `in-`",
147                        ));
148                    }
149                };
150
151                Ok(In {
152                    path,
153                    ignore_case,
154                    value,
155                })
156            }
157        }
158
159        const FIELDS: &[&str] = &["path", "op", "value"];
160        Deserializer::deserialize_struct(
161            deserializer,
162            "In",
163            FIELDS,
164            VisitorIn {
165                marker: PhantomData::<In>,
166                lifetime: PhantomData,
167            },
168        )
169    }
170}
171
172impl From<In> for FirstOrder {
173    fn from(value: In) -> Self {
174        FirstOrder::In(value)
175    }
176}
177
178impl PredicateImpl for In {
179    fn evaluate(&self, data: &Value, ctx: PredicateContext) -> Result<bool, PredicateError> {
180        let path = ctx.final_path(&self.path).unwrap_or(JSONPath::empty());
181        let ptr = path.take();
182
183        let value = &self.value;
184        let context_value = ptr.get(data)?;
185
186        let result = if self.ignore_case {
187            let context_value = context_value.to_string().to_lowercase();
188            value
189                .iter()
190                .find(|x| x.to_string().to_lowercase() == context_value)
191        } else {
192            value.iter().find(|x| *x == context_value)
193        };
194        Ok(result.is_some())
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use serde::Deserialize;
201
202    use crate::{json_path::JSONPath, predicate::first_order::r#in::In};
203
204    #[test]
205    fn snapshot_test() {
206        let end_expect = serde_json::json!({
207             "op": "in",
208             "path": "/a/b",
209             "value": ["a"],
210        });
211
212        let end = In {
213            path: Some(JSONPath::new("/a/b").unwrap()),
214            ignore_case: false,
215            value: vec![serde_json::Value::String("a".to_string())],
216        };
217
218        assert_eq!(serde_json::to_value(end).unwrap(), end_expect);
219    }
220
221    #[test]
222    fn deser_test() {
223        let end_expect = serde_json::json!({
224             "op": "in",
225             "path": "/a/b",
226             "value": ["a"],
227        });
228
229        let end = In {
230            path: Some(JSONPath::new("/a/b").unwrap()),
231            ignore_case: false,
232            value: vec![serde_json::Value::String("a".to_string())],
233        };
234
235        let deser = In::deserialize(end_expect).unwrap();
236
237        assert_eq!(end, deser);
238    }
239}