1use crate::any::AnyArrayIter;
2use crate::json_path::JsonPathToken;
3use crate::{Any, Array, JsonPath, JsonPathEval, Map, Out, ReadTxn, Xml, XmlFragment};
4
5impl<T> JsonPathEval for T
6where
7 T: ReadTxn,
8{
9 type Iter<'a>
10 = JsonPathIter<'a, T>
11 where
12 T: 'a;
13
14 fn json_path<'a>(&'a self, path: &'a JsonPath<'a>) -> Self::Iter<'a> {
44 JsonPathIter::new(self, path.as_ref())
45 }
46}
47
48fn slice_iter<'a, T: ReadTxn>(
49 txn: &'a T,
50 value: Option<Out>,
51 from: usize,
52 to: usize,
53 by: usize,
54) -> Option<Box<dyn Iterator<Item = Out> + 'a>> {
55 match value {
56 Some(Out::Any(Any::Array(array))) => {
57 let iter = AnyArrayIter::new(array);
58 Some(Box::new(
59 iter.skip(from).take(to - from).step_by(by).map(Out::Any),
60 ))
61 }
62 Some(Out::YArray(array)) => {
63 let iter = array.iter(txn);
64 Some(Box::new(iter.skip(from).take(to - from).step_by(by)))
65 }
66 Some(Out::YXmlElement(xml)) => {
67 let iter = xml.children(txn);
68 Some(Box::new(
69 iter.skip(from).take(to - from).step_by(by).map(Out::from),
70 ))
71 }
72 Some(Out::YXmlFragment(xml)) => {
73 let iter = xml.children(txn);
74 Some(Box::new(
75 iter.skip(from).take(to - from).step_by(by).map(Out::from),
76 ))
77 }
78 _ => None,
79 }
80}
81
82fn any_iter<'a, T: ReadTxn>(
83 txn: &'a T,
84 out: Option<Out>,
85) -> Option<Box<dyn Iterator<Item = Out> + 'a>> {
86 #[inline]
87 fn dyn_iter<'a, I: Iterator<Item = Out> + 'a>(iter: I) -> Box<dyn Iterator<Item = Out> + 'a> {
88 Box::new(iter)
89 }
90
91 match out {
92 None => Some(dyn_iter(txn.root_refs().map(|(_, out)| out))),
93 Some(Out::Any(any)) => {
94 let iter = any.try_into_iter();
95 iter.map(|iter| dyn_iter(iter.map(|(_, v)| Out::Any(v))))
96 }
97 Some(Out::YArray(array)) => Some(dyn_iter(array.iter(txn))),
98 Some(Out::YXmlElement(elem)) => Some(dyn_iter(elem.children(txn).map(Out::from))),
99 Some(Out::YXmlFragment(elem)) => Some(dyn_iter(elem.children(txn).map(Out::from))),
100 Some(Out::YMap(map)) => Some(dyn_iter(map.into_iter(txn).map(|(_, value)| value))),
101 Some(Out::UndefinedRef(branch)) => {
102 if branch.start.is_some() {
105 let array = crate::ArrayRef::from(branch);
107 Some(dyn_iter(array.iter(txn)))
108 } else {
109 let map = crate::MapRef::from(branch);
111 Some(dyn_iter(map.into_iter(txn).map(|(_, value)| value)))
112 }
113 }
114 _ => None,
115 }
116}
117
118fn member_union_iter<'a, T: ReadTxn>(
119 txn: &'a T,
120 value: Option<Out>,
121 members: &'a [&'a str],
122) -> Option<Box<dyn Iterator<Item = Out> + 'a>> {
123 match value {
124 Some(Out::Any(Any::Map(map))) => {
125 let iter = members
126 .into_iter()
127 .flat_map(move |key| map.get(*key).cloned().map(Out::Any));
128 Some(Box::new(iter))
129 }
130 Some(Out::YMap(map)) => {
131 let iter = members.into_iter().flat_map(move |key| map.get(txn, *key));
132 Some(Box::new(iter))
133 }
134 None => {
135 let iter = members.into_iter().flat_map(move |key| txn.get(key));
136 Some(Box::new(iter))
137 }
138 _ => None,
139 }
140}
141
142fn index_union_iter<'a, T: ReadTxn>(
143 txn: &'a T,
144 value: Option<Out>,
145 indices: &'a [i32],
146) -> Option<Box<dyn Iterator<Item = Out> + 'a>> {
147 match value {
148 Some(Out::Any(Any::Array(array))) => {
149 let iter = indices.into_iter().flat_map(move |i| {
150 let i = if *i < 0 {
151 (array.len() as i32 + *i) as usize
152 } else {
153 *i as usize
154 };
155 array.get(i).cloned().map(Out::Any)
156 });
157 Some(Box::new(iter))
158 }
159 Some(Out::YArray(array)) => {
160 let len = array.len(txn);
161 let iter = indices.into_iter().flat_map(move |i| {
162 let i = if *i < 0 {
163 (len as i32 + *i) as u32
164 } else {
165 *i as u32
166 };
167 array.get(txn, i)
168 });
169 Some(Box::new(iter))
170 }
171 Some(Out::YXmlFragment(xml)) => {
172 let len = xml.len(txn);
173 let iter = indices.into_iter().flat_map(move |i| {
174 let i = if *i < 0 {
175 (len as i32 + *i) as u32
176 } else {
177 *i as u32
178 };
179 xml.get(txn, i).map(Out::from)
180 });
181 Some(Box::new(iter))
182 }
183 Some(Out::YXmlElement(xml)) => {
184 let len = xml.len(txn);
185 let iter = indices.into_iter().flat_map(move |i| {
186 let i = if *i < 0 {
187 (len as i32 + *i) as u32
188 } else {
189 *i as u32
190 };
191 xml.get(txn, i).map(Out::from)
192 });
193 Some(Box::new(iter))
194 }
195 _ => None,
196 }
197}
198
199pub struct JsonPathIter<'a, T> {
200 txn: &'a T,
201 pattern: &'a [JsonPathToken<'a>],
202 frame: ExecutionFrame<'a>,
203}
204
205impl<'a, T> JsonPathIter<'a, T>
206where
207 T: ReadTxn,
208{
209 fn new(txn: &'a T, path: &'a [JsonPathToken<'a>]) -> Self {
210 Self {
211 txn,
212 pattern: path.as_ref(),
213 frame: ExecutionFrame::new(None, 0, None),
214 }
215 }
216}
217
218impl<'a, T> Iterator for JsonPathIter<'a, T>
219where
220 T: ReadTxn,
221{
222 type Item = Out;
223
224 fn next(&mut self) -> Option<Self::Item> {
225 if let Some(iter) = &mut self.frame.iter {
226 match iter.next() {
227 None => {
228 self.frame.iter = None;
229 return if self.frame.ascend() {
230 self.next()
231 } else {
232 None
233 };
234 }
235 Some(curr) => {
236 self.frame.descend(curr);
237 }
238 }
239 } else if self.frame.index == self.pattern.len() {
240 return if self.frame.ascend() {
241 self.next()
242 } else {
243 None
244 };
245 }
246 let mut early_return = false;
248 while self.frame.index < self.pattern.len() {
249 let segment = &self.pattern[self.frame.index];
250 self.frame.index += 1;
251 match segment {
252 JsonPathToken::Root => self.frame.current = None,
253 JsonPathToken::Current => { }
254 JsonPathToken::Member(key) => {
255 if let Some(value) = get_member(self.txn, self.frame.current.as_ref(), *key) {
256 self.frame.current = Some(value);
257 } else {
258 early_return = true;
259 }
260 }
261 JsonPathToken::Index(idx) => {
262 if let Some(value) = get_index(self.txn, self.frame.current.as_ref(), *idx) {
263 self.frame.current = Some(value);
264 } else {
265 early_return = true;
266 }
267 }
268 JsonPathToken::Wildcard => {
269 if let Some(iter) = any_iter(self.txn, self.frame.current.clone()) {
270 self.frame.iter = Some(iter);
271 return self.next();
272 }
273 early_return = true;
274 }
275 JsonPathToken::RecursiveDescend => {
276 if let Some(iter) = any_iter(self.txn, self.frame.current.clone()) {
277 self.frame.iter = Some(iter);
278 self.frame.is_descending = true;
279 return self.next();
280 }
281 early_return = true;
282 }
283 JsonPathToken::Slice(from, to, by) => {
284 if let Some(iter) = slice_iter(
285 self.txn,
286 self.frame.current.clone(),
287 *from as usize,
288 *to as usize,
289 *by as usize,
290 ) {
291 self.frame.iter = Some(iter);
292 return self.next();
293 }
294 early_return = true;
295 }
296 JsonPathToken::MemberUnion(members) => {
297 if let Some(iter) =
298 member_union_iter(self.txn, self.frame.current.clone(), &members)
299 {
300 self.frame.iter = Some(iter);
301 return self.next();
302 }
303 early_return = true;
304 }
305 JsonPathToken::IndexUnion(indices) => {
306 if let Some(iter) =
307 index_union_iter(self.txn, self.frame.current.clone(), &indices)
308 {
309 self.frame.iter = Some(iter);
310 return self.next();
311 }
312 early_return = true;
313 }
314 }
315
316 if early_return {
317 break;
318 }
319 }
320
321 if !early_return {
322 return self.frame.current.clone();
323 } else if self.frame.is_descending {
324 if let Some(iter) = any_iter(self.txn, self.frame.current.clone()) {
325 self.frame.iter = Some(iter);
326 self.frame.is_descending = true;
327 self.frame.index -= 1; return self.next();
329 }
330 }
331
332 if self.frame.iter.is_none() && !self.frame.ascend() {
333 None } else {
335 self.next()
336 }
337 }
338}
339
340fn get_member<T: ReadTxn>(txn: &T, out: Option<&Out>, key: &str) -> Option<Out> {
341 match out {
342 None => txn.get(key),
343 Some(Out::YMap(map)) => map.get(txn, key),
344 Some(Out::Any(Any::Map(map))) => map.get(key).map(|any| Out::Any(any.clone())),
345 Some(Out::YXmlElement(elem)) => elem.get_attribute(txn, key),
346 Some(Out::YXmlText(elem)) => elem.get_attribute(txn, key),
347 Some(Out::UndefinedRef(branch)) => {
348 let map = crate::MapRef::from(*branch);
350 map.get(txn, key)
351 }
352 _ => None,
353 }
354}
355
356fn get_index<T: ReadTxn>(txn: &T, out: Option<&Out>, idx: i32) -> Option<Out> {
357 match out {
358 Some(Out::YArray(array)) => {
359 let idx = if idx < 0 {
360 array.len(txn) as i32 + idx
361 } else {
362 idx
363 } as u32;
364 array.get(txn, idx)
365 }
366 Some(Out::Any(Any::Array(array))) => {
367 let idx = if idx < 0 {
368 array.len() as i32 + idx
369 } else {
370 idx
371 } as usize;
372 array.get(idx).cloned().map(Out::Any)
373 }
374 Some(Out::YXmlFragment(elem)) => {
375 let idx = if idx < 0 {
376 elem.len(txn) as i32 + idx
377 } else {
378 idx
379 } as u32;
380 elem.get(txn, idx).map(Out::from)
381 }
382 Some(Out::YXmlElement(elem)) => {
383 let idx = if idx < 0 {
384 elem.len(txn) as i32 + idx
385 } else {
386 idx
387 } as u32;
388 elem.get(txn, idx).map(Out::from)
389 }
390 Some(Out::UndefinedRef(array)) => {
391 let array = crate::ArrayRef::from(*array);
393 let idx = if idx < 0 {
394 array.len(txn) as i32 + idx
395 } else {
396 idx
397 } as u32;
398 array.get(txn, idx)
399 }
400 _ => None,
401 }
402}
403
404struct ExecutionFrame<'a> {
406 index: usize,
408 is_descending: bool,
410 current: Option<Out>,
412 iter: Option<ScopeIterator<'a>>,
414 next: Option<Box<ExecutionFrame<'a>>>,
417}
418
419impl<'a> ExecutionFrame<'a> {
420 fn new(current: Option<Out>, index: usize, iter: Option<ScopeIterator<'a>>) -> Self {
421 Self {
422 index,
423 is_descending: false,
424 current,
425 iter,
426 next: None,
427 }
428 }
429
430 fn descend(&mut self, current: Out) {
433 let new_self = ExecutionFrame {
434 index: self.index,
435 is_descending: self.is_descending,
436 current: Some(current),
437 iter: None,
438 next: None,
439 };
440 let old_frame = std::mem::replace(self, new_self);
441 self.next = Some(Box::new(old_frame));
442 }
443
444 fn ascend(&mut self) -> bool {
447 match self.next.take() {
448 None => false,
449 Some(next) => {
450 *self = *next;
451 true
452 }
453 }
454 }
455}
456
457type ScopeIterator<'a> = Box<dyn Iterator<Item = Out> + 'a>;
458
459#[cfg(test)]
460mod test {
461 use crate::updates::decoder::Decode;
462 use crate::{
463 any, Array, ArrayPrelim, Doc, In, JsonPath, JsonPathEval, MapPrelim, Out, ReadTxn,
464 Transact, Update, WriteTxn,
465 };
466
467 fn mixed_sample() -> Doc {
468 let doc = Doc::new();
469 let mut tx = doc.transact_mut();
470 let users = tx.get_or_insert_array("users");
471 users.insert(
472 &mut tx,
473 0,
474 MapPrelim::from([
475 ("name".to_string(), In::Any(any!("Alice"))),
476 ("surname".into(), In::Any(any!("Smith"))),
477 ("age".into(), In::Any(any!(25))),
478 (
479 "friends".into(),
480 In::from(ArrayPrelim::from([
481 any!({ "name": "Bob", "nick": "boreas" }),
482 any!({ "nick": "crocodile91" }),
483 ])),
484 ),
485 ]),
486 );
487 users.insert(
488 &mut tx,
489 1,
490 MapPrelim::from([
491 ("name".to_string(), In::Any(any!("Bob"))),
492 ("nick".into(), In::Any(any!("boreas"))),
493 ("age".into(), In::Any(any!(30))),
494 ]),
495 );
496 users.insert(
497 &mut tx,
498 2,
499 MapPrelim::from([
500 ("nick".to_string(), In::Any(any!("crocodile91"))),
501 ("age".into(), In::Any(any!(35))),
502 ]),
503 );
504 users.insert(
505 &mut tx,
506 3,
507 MapPrelim::from([
508 ("name".to_string(), In::Any(any!("Damian"))),
509 ("surname".into(), In::Any(any!("Smith"))),
510 ("age".into(), In::Any(any!(30))),
511 ]),
512 );
513 users.insert(
514 &mut tx,
515 4,
516 MapPrelim::from([
517 ("name".to_string(), In::Any(any!("Elise"))),
518 ("age".into(), In::Any(any!(35))),
519 ]),
520 );
521 drop(tx);
522 doc
523 }
524
525 #[test]
526 fn eval_member_partial() {
527 let doc = mixed_sample();
528 let path = JsonPath::parse("$.users").unwrap();
529 let tx = doc.transact();
530 let values: Vec<_> = tx.json_path(&path).collect();
531 let expected = tx.get("users").unwrap();
532 assert_eq!(values, vec![expected]);
533 }
534
535 #[test]
536 fn eval_member_full() {
537 let doc = mixed_sample();
538 let path = JsonPath::parse("$.users[0].name").unwrap();
539 let tx = doc.transact();
540 let values: Vec<_> = tx.json_path(&path).collect();
541 assert_eq!(values, vec![Out::Any(any!("Alice"))]);
542 }
543
544 #[test]
545 fn eval_member_negative_index() {
546 let doc = mixed_sample();
547 let path = JsonPath::parse("$.users[-1].name").unwrap();
548 let tx = doc.transact();
549 let values: Vec<_> = tx.json_path(&path).collect();
550 assert_eq!(values, vec![Out::Any(any!("Elise"))]);
551 }
552
553 #[test]
554 fn eval_member_wildcard_array() {
555 let doc = mixed_sample();
556 let path = JsonPath::parse("$.users[*].name").unwrap();
557 let tx = doc.transact();
558 let values: Vec<_> = tx.json_path(&path).collect();
559 assert_eq!(
560 values,
561 vec![
562 Out::Any(any!("Alice")),
563 Out::Any(any!("Bob")),
564 Out::Any(any!("Damian")),
565 Out::Any(any!("Elise"))
566 ]
567 );
568 }
569
570 #[test]
571 fn eval_member_slice() {
572 let doc = mixed_sample();
573 let path = JsonPath::parse("$.users[1:3].nick").unwrap();
574 let tx = doc.transact();
575 let values: Vec<_> = tx.json_path(&path).collect();
576 assert_eq!(
577 values,
578 vec![Out::Any(any!("boreas")), Out::Any(any!("crocodile91"))]
579 );
580 }
581
582 #[test]
583 fn eval_index_union() {
584 let doc = mixed_sample();
585 let path = JsonPath::parse("$.users[1,3].name").unwrap();
586 let tx = doc.transact();
587 let values: Vec<_> = tx.json_path(&path).collect();
588 assert_eq!(
589 values,
590 vec![Out::Any(any!("Bob")), Out::Any(any!("Damian"))]
591 );
592 }
593
594 #[test]
595 fn eval_member_union() {
596 let doc = mixed_sample();
597 let path = JsonPath::parse("$.users[0]['name','surname']").unwrap();
598 let tx = doc.transact();
599 let values: Vec<_> = tx.json_path(&path).collect();
600 assert_eq!(
601 values,
602 vec![Out::Any(any!("Alice")), Out::Any(any!("Smith"))]
603 );
604 }
605
606 #[test]
607 fn eval_descent_flat() {
608 let doc = mixed_sample();
609 let path = JsonPath::parse("$.users..name").unwrap();
610 let tx = doc.transact();
611 let values: Vec<_> = tx.json_path(&path).collect();
612 assert_eq!(
613 values,
614 vec![
615 Out::Any(any!("Alice")),
616 Out::Any(any!("Bob")),
617 Out::Any(any!("Damian")),
618 Out::Any(any!("Elise"))
619 ]
620 );
621 }
622 #[test]
623 fn eval_on_fresh_document() {
624 let doc_state = mixed_sample()
625 .transact()
626 .encode_state_as_update_v1(&Default::default());
627 let doc = Doc::new();
628 doc.transact_mut()
629 .apply_update(Update::decode_v1(&doc_state).unwrap())
630 .unwrap();
631 let path = JsonPath::parse("$.users[*].name").unwrap();
632 let tx = doc.transact();
633 let values: Vec<_> = tx.json_path(&path).collect();
634 assert_eq!(
635 values,
636 vec![
637 Out::Any(any!("Alice")),
638 Out::Any(any!("Bob")),
639 Out::Any(any!("Damian")),
640 Out::Any(any!("Elise"))
641 ]
642 );
643 }
644}