Skip to main content

jlens_core/
document.rs

1//! Input documents converted once, for many evaluations.
2
3use std::collections::BTreeMap;
4use std::fmt;
5use std::marker::PhantomData;
6use std::rc::Rc;
7
8use serde::de::{DeserializeSeed, Deserializer, IgnoredAny, MapAccess, SeqAccess, Visitor};
9use serde_json::Value as JsonValue;
10
11use crate::reads::Read;
12use crate::value::{Keys, Map, Value};
13
14/// A JSON document in jlens's internal representation.
15///
16/// Every `evaluate` call converts the parts of its input document that the expression reads
17/// from `serde_json::Value`, one level at a time. An expression that reads most of a large
18/// document can spend more on that than on the evaluation itself. To evaluate several
19/// expressions (a set of rules, say) or the same one several times against one document,
20/// convert it once into a `Document` and use
21/// [`Expression::evaluate_document`](crate::Expression::evaluate_document).
22///
23/// ```
24/// use jlens_core::{Bindings, Document, Expression, Options};
25///
26/// let doc = Document::parse(r#"{"items": [{"price": 2}, {"price": 3}]}"#).unwrap();
27/// let rules = ["$sum(items.price) > 4", "$count(items) < 10"];
28/// for rule in rules {
29///     let expr = Expression::compile(rule).unwrap();
30///     let result = expr.evaluate_document(&doc, &Bindings::new(), &Options::default());
31///     assert_eq!(result.unwrap(), Some(serde_json::json!(true)));
32/// }
33/// ```
34///
35/// Evaluations never modify the document. The one exception is a transform (`|...|`) whose
36/// expression rebinds `$clone` to a function that does not copy its argument.
37///
38/// A `Document` is not `Send`. Convert it on the thread that evaluates against it.
39pub struct Document {
40    value: Value<'static>,
41}
42
43impl Document {
44    /// Converts a `serde_json` value.
45    pub fn new(json: &JsonValue) -> Self {
46        Document {
47            value: Value::from_json(json),
48        }
49    }
50
51    /// Parses JSON text straight into the internal representation. This is faster than parsing
52    /// into a `serde_json::Value` and converting it.
53    pub fn parse(text: &str) -> serde_json::Result<Self> {
54        Ok(Document {
55            value: parse_value(text, &mut Keys::default())?,
56        })
57    }
58
59    /// Parses JSON text cut by `read`, skipping the fields it leaves out, as
60    /// [`Read::cut`] would cut the whole document. Give it what the expressions to evaluate
61    /// read of their input (one expression's [`Reads::input`], or the union of several), and
62    /// the document serves each of them as the whole one would.
63    ///
64    /// The fields skipped are checked as JSON syntax but not converted, so two values that
65    /// [`parse`](Document::parse) rejects pass when skipped: a number too large for a float,
66    /// and a string with a lone surrogate escape.
67    ///
68    /// ```
69    /// use jlens_core::{Bindings, Document, Expression, Options};
70    ///
71    /// let text = r#"{"items": [{"price": 2, "notes": "…"}, {"price": 3, "notes": "…"}]}"#;
72    /// let rules = ["$sum(items.price) > 4", "$count(items) < 10"];
73    /// let exprs: Vec<_> = rules.iter().map(|r| Expression::compile(r).unwrap()).collect();
74    /// let reads = exprs.iter().map(|e| e.reads()).reduce(|a, b| a.union(&b)).unwrap();
75    /// let doc = Document::parse_cut(text, reads.input().unwrap()).unwrap();
76    /// assert_eq!(doc.to_json(), serde_json::json!({"items": [{"price": 2}, {"price": 3}]}));
77    /// for expr in &exprs {
78    ///     let result = expr.evaluate_document(&doc, &Bindings::new(), &Options::default());
79    ///     assert_eq!(result.unwrap(), Some(serde_json::json!(true)));
80    /// }
81    /// ```
82    ///
83    /// [`Reads::input`]: crate::reads::Reads::input
84    pub fn parse_cut(text: &str, read: &Read) -> serde_json::Result<Self> {
85        let mut keys = Keys::default();
86        let mut deserializer = serde_json::Deserializer::from_str(text);
87        let value = CutSeed(&mut keys, read, PhantomData).deserialize(&mut deserializer)?;
88        deserializer.end()?;
89        Ok(Document { value })
90    }
91
92    /// The document as JSON.
93    pub fn to_json(&self) -> JsonValue {
94        self.value.to_json().unwrap_or(JsonValue::Null)
95    }
96
97    pub(crate) fn value(&self) -> &Value<'static> {
98        &self.value
99    }
100}
101
102impl fmt::Debug for Document {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        f.debug_tuple("Document").field(&self.to_json()).finish()
105    }
106}
107
108impl From<&JsonValue> for Document {
109    fn from(json: &JsonValue) -> Self {
110        Document::new(json)
111    }
112}
113
114/// Parses JSON text into a value, sharing the keys of its objects through `keys`.
115pub(crate) fn parse_value<'a>(text: &str, keys: &mut Keys) -> serde_json::Result<Value<'a>> {
116    let mut deserializer = serde_json::Deserializer::from_str(text);
117    let value = ValueSeed(keys, PhantomData).deserialize(&mut deserializer)?;
118    deserializer.end()?;
119    Ok(value)
120}
121
122/// Deserializes a value, sharing the keys of its objects through one table.
123struct ValueSeed<'k, 'a>(&'k mut Keys, PhantomData<Value<'a>>);
124
125impl<'de, 'a> DeserializeSeed<'de> for ValueSeed<'_, 'a> {
126    type Value = Value<'a>;
127
128    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value<'a>, D::Error> {
129        deserializer.deserialize_any(self)
130    }
131}
132
133impl<'de, 'a> Visitor<'de> for ValueSeed<'_, 'a> {
134    type Value = Value<'a>;
135
136    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        f.write_str("a JSON value")
138    }
139
140    fn visit_bool<E>(self, b: bool) -> Result<Value<'a>, E> {
141        Ok(Value::Bool(b))
142    }
143
144    fn visit_i64<E>(self, n: i64) -> Result<Value<'a>, E> {
145        Ok(Value::Number(n as f64))
146    }
147
148    fn visit_u64<E>(self, n: u64) -> Result<Value<'a>, E> {
149        Ok(Value::Number(n as f64))
150    }
151
152    fn visit_f64<E>(self, n: f64) -> Result<Value<'a>, E> {
153        Ok(Value::Number(n))
154    }
155
156    fn visit_str<E>(self, s: &str) -> Result<Value<'a>, E> {
157        Ok(Value::string(s))
158    }
159
160    fn visit_unit<E>(self) -> Result<Value<'a>, E> {
161        Ok(Value::Null)
162    }
163
164    fn visit_none<E>(self) -> Result<Value<'a>, E> {
165        Ok(Value::Null)
166    }
167
168    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value<'a>, A::Error> {
169        let mut items = Vec::with_capacity(seq.size_hint().unwrap_or(0));
170        while let Some(item) = seq.next_element_seed(ValueSeed(&mut *self.0, PhantomData))? {
171            items.push(item);
172        }
173        Ok(Value::array(items, 0))
174    }
175
176    fn visit_map<A: MapAccess<'de>>(self, mut access: A) -> Result<Value<'a>, A::Error> {
177        let mut map =
178            Map::with_capacity_and_hasher(access.size_hint().unwrap_or(0), Default::default());
179        // A repeated key keeps its first position and takes the last value, as in `JSON.parse`.
180        while let Some(key) = access.next_key_seed(KeySeed(self.0))? {
181            let value = access.next_value_seed(ValueSeed(&mut *self.0, PhantomData))?;
182            map.insert(key, value);
183        }
184        Ok(Value::object(map))
185    }
186}
187
188/// Deserializes a value cut by a `Read`, skipping the fields it leaves out.
189struct CutSeed<'k, 'r, 'a>(&'k mut Keys, &'r Read, PhantomData<Value<'a>>);
190
191impl<'de, 'a> DeserializeSeed<'de> for CutSeed<'_, '_, 'a> {
192    type Value = Value<'a>;
193
194    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value<'a>, D::Error> {
195        match self.1 {
196            Read::Whole => ValueSeed(self.0, PhantomData).deserialize(deserializer),
197            Read::Fields(_) => deserializer.deserialize_any(self),
198        }
199    }
200}
201
202impl<'de, 'a> Visitor<'de> for CutSeed<'_, '_, 'a> {
203    type Value = Value<'a>;
204
205    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.write_str("a JSON value")
207    }
208
209    fn visit_bool<E>(self, b: bool) -> Result<Value<'a>, E> {
210        Ok(Value::Bool(b))
211    }
212
213    fn visit_i64<E>(self, n: i64) -> Result<Value<'a>, E> {
214        Ok(Value::Number(n as f64))
215    }
216
217    fn visit_u64<E>(self, n: u64) -> Result<Value<'a>, E> {
218        Ok(Value::Number(n as f64))
219    }
220
221    fn visit_f64<E>(self, n: f64) -> Result<Value<'a>, E> {
222        Ok(Value::Number(n))
223    }
224
225    fn visit_str<E>(self, s: &str) -> Result<Value<'a>, E> {
226        Ok(Value::string(s))
227    }
228
229    fn visit_unit<E>(self) -> Result<Value<'a>, E> {
230        Ok(Value::Null)
231    }
232
233    fn visit_none<E>(self) -> Result<Value<'a>, E> {
234        Ok(Value::Null)
235    }
236
237    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value<'a>, A::Error> {
238        // The items of an array are cut by the `Read` of the array.
239        let mut items = Vec::with_capacity(seq.size_hint().unwrap_or(0));
240        while let Some(item) = seq.next_element_seed(CutSeed(&mut *self.0, self.1, PhantomData))? {
241            items.push(item);
242        }
243        Ok(Value::array(items, 0))
244    }
245
246    fn visit_map<A: MapAccess<'de>>(self, mut access: A) -> Result<Value<'a>, A::Error> {
247        let Read::Fields(fields) = self.1 else {
248            return ValueSeed(self.0, PhantomData).visit_map(access);
249        };
250        let mut map = Map::with_capacity_and_hasher(fields.len(), Default::default());
251        while let Some(field) = access.next_key_seed(FieldSeed(&mut *self.0, fields))? {
252            match field {
253                Some((key, read)) => {
254                    let value = access.next_value_seed(CutSeed(&mut *self.0, read, PhantomData))?;
255                    map.insert(key, value);
256                }
257                None => {
258                    access.next_value::<IgnoredAny>()?;
259                }
260            }
261        }
262        Ok(Value::object(map))
263    }
264}
265
266/// Deserializes a key into the shared one of the table, with its `Read`, or into `None` when
267/// the field is not read.
268struct FieldSeed<'k, 'r>(&'k mut Keys, &'r BTreeMap<String, Read>);
269
270impl<'de, 'r> DeserializeSeed<'de> for FieldSeed<'_, 'r> {
271    type Value = Option<(Rc<str>, &'r Read)>;
272
273    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
274        deserializer.deserialize_str(self)
275    }
276}
277
278impl<'de, 'r> Visitor<'de> for FieldSeed<'_, 'r> {
279    type Value = Option<(Rc<str>, &'r Read)>;
280
281    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        f.write_str("a string")
283    }
284
285    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> {
286        Ok(self.1.get(s).map(|read| (self.0.get(s), read)))
287    }
288}
289
290/// Deserializes a key into the shared one of the table.
291struct KeySeed<'k>(&'k mut Keys);
292
293impl<'de> DeserializeSeed<'de> for KeySeed<'_> {
294    type Value = Rc<str>;
295
296    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Rc<str>, D::Error> {
297        deserializer.deserialize_str(self)
298    }
299}
300
301impl<'de> Visitor<'de> for KeySeed<'_> {
302    type Value = Rc<str>;
303
304    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        f.write_str("a string")
306    }
307
308    fn visit_str<E>(self, s: &str) -> Result<Rc<str>, E> {
309        Ok(self.0.get(s))
310    }
311}