1use crate::{
2 cnf::IDIOM_RECURSION_LIMIT,
3 ctx::Context,
4 dbs::Options,
5 doc::CursorDoc,
6 err::Error,
7 exe::try_join_all_buffered,
8 sql::{fmt::Fmt, strand::no_nul_bytes, Graph, Ident, Idiom, Number, Value},
9};
10use reblessive::tree::Stk;
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::fmt;
14use std::fmt::Write;
15use std::str;
16
17use super::{
18 fmt::{is_pretty, pretty_indent},
19 value::idiom_recursion::{clean_iteration, compute_idiom_recursion, is_final, Recursion},
20};
21
22#[revisioned(revision = 4)]
23#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[non_exhaustive]
26pub enum Part {
27 All,
28 Flatten,
29 Last,
30 First,
31 Field(Ident),
32 Index(Number),
33 Where(Value),
34 Graph(Graph),
35 Value(Value),
36 Start(Value),
37 Method(#[serde(with = "no_nul_bytes")] String, Vec<Value>),
38 #[revision(start = 2)]
39 Destructure(Vec<DestructurePart>),
40 Optional,
41 #[revision(
42 start = 3,
43 end = 4,
44 convert_fn = "convert_recurse_add_instruction",
45 fields_name = "OldRecurseFields"
46 )]
47 Recurse(Recurse, Option<Idiom>),
48 #[revision(start = 4)]
49 Recurse(Recurse, Option<Idiom>, Option<RecurseInstruction>),
50 #[revision(start = 3)]
51 Doc,
52 #[revision(start = 3)]
53 RepeatRecurse,
54}
55
56impl Part {
57 fn convert_recurse_add_instruction(
58 fields: OldRecurseFields,
59 _revision: u16,
60 ) -> Result<Self, revision::Error> {
61 Ok(Part::Recurse(fields.0, fields.1, None))
62 }
63}
64
65impl From<i32> for Part {
66 fn from(v: i32) -> Self {
67 Self::Index(v.into())
68 }
69}
70
71impl From<isize> for Part {
72 fn from(v: isize) -> Self {
73 Self::Index(v.into())
74 }
75}
76
77impl From<usize> for Part {
78 fn from(v: usize) -> Self {
79 Self::Index(v.into())
80 }
81}
82
83impl From<String> for Part {
84 fn from(v: String) -> Self {
85 Self::Field(v.into())
86 }
87}
88
89impl From<Number> for Part {
90 fn from(v: Number) -> Self {
91 Self::Index(v)
92 }
93}
94
95impl From<Ident> for Part {
96 fn from(v: Ident) -> Self {
97 Self::Field(v)
98 }
99}
100
101impl From<Graph> for Part {
102 fn from(v: Graph) -> Self {
103 Self::Graph(v)
104 }
105}
106
107impl From<&str> for Part {
108 fn from(v: &str) -> Self {
109 match v.parse::<isize>() {
110 Ok(v) => Self::from(v),
111 _ => Self::from(v.to_owned()),
112 }
113 }
114}
115
116impl Part {
117 pub(crate) fn writeable(&self) -> bool {
119 match self {
120 Part::Start(v) => v.writeable(),
121 Part::Where(v) => v.writeable(),
122 Part::Value(v) => v.writeable(),
123 Part::Method(_, v) => v.iter().any(Value::writeable),
124 _ => false,
125 }
126 }
127 pub(crate) fn alias(&self) -> Option<&Idiom> {
129 match self {
130 Part::Graph(v) => v.alias.as_ref(),
131 _ => None,
132 }
133 }
134
135 fn recursion_plan(&self) -> Option<RecursionPlan> {
136 match self {
137 Part::RepeatRecurse => Some(RecursionPlan::Repeat),
138 Part::Destructure(parts) => {
139 for (j, p) in parts.iter().enumerate() {
140 let plan = match p {
141 DestructurePart::Aliased(field, v) => v.find_recursion_plan().map(|plan| {
142 (
143 field.to_owned(),
144 plan.0.to_vec(),
145 Box::new(plan.1.to_owned()),
146 plan.2.to_vec(),
147 )
148 }),
149 DestructurePart::Destructure(field, parts) => {
150 Part::Destructure(parts.to_owned()).recursion_plan().map(|plan| {
151 (
152 field.to_owned(),
153 vec![Part::Field(field.to_owned())],
154 Box::new(plan),
155 vec![],
156 )
157 })
158 }
159 _ => None,
160 };
161
162 if let Some((field, before, plan, after)) = plan {
163 let mut parts = parts.clone();
164 parts.remove(j);
165 return Some(RecursionPlan::Destructure {
166 parts,
167 field,
168 before,
169 plan,
170 after,
171 });
172 }
173 }
174
175 None
176 }
177 _ => None,
178 }
179 }
180}
181
182impl fmt::Display for Part {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 match self {
185 Part::All => f.write_str("[*]"),
186 Part::Last => f.write_str("[$]"),
187 Part::First => f.write_str("[0]"),
188 Part::Start(v) => write!(f, "{v}"),
189 Part::Field(v) => write!(f, ".{v}"),
190 Part::Flatten => f.write_str("…"),
191 Part::Index(v) => write!(f, "[{v}]"),
192 Part::Where(v) => write!(f, "[WHERE {v}]"),
193 Part::Graph(v) => write!(f, "{v}"),
194 Part::Value(v) => write!(f, "[{v}]"),
195 Part::Method(v, a) => write!(f, ".{v}({})", Fmt::comma_separated(a)),
196 Part::Destructure(v) => {
197 f.write_str(".{")?;
198 if !is_pretty() {
199 f.write_char(' ')?;
200 }
201 if !v.is_empty() {
202 let indent = pretty_indent();
203 write!(f, "{}", Fmt::pretty_comma_separated(v))?;
204 drop(indent);
205 }
206 if is_pretty() {
207 f.write_char('}')
208 } else {
209 f.write_str(" }")
210 }
211 }
212 Part::Optional => write!(f, "?"),
213 Part::Recurse(v, nest, instruction) => {
214 write!(f, ".{{{v}")?;
215 if let Some(instruction) = instruction {
216 write!(f, "+{instruction}")?;
217 }
218 write!(f, "}}")?;
219
220 if let Some(nest) = nest {
221 write!(f, "({nest})")?;
222 }
223
224 Ok(())
225 }
226 Part::Doc => write!(f, "@"),
227 Part::RepeatRecurse => write!(f, ".@"),
228 }
229 }
230}
231
232#[derive(Clone, Debug)]
235pub enum RecursionPlan {
236 Repeat,
237 Destructure {
238 parts: Vec<DestructurePart>,
240 field: Ident,
242 before: Vec<Part>,
244 plan: Box<RecursionPlan>,
246 after: Vec<Part>,
248 },
249}
250
251impl<'a> RecursionPlan {
252 pub async fn compute(
253 &self,
254 stk: &mut Stk,
255 ctx: &Context,
256 opt: &Options,
257 doc: Option<&CursorDoc>,
258 rec: Recursion<'a>,
259 ) -> Result<Value, Error> {
260 match rec.current {
261 Value::Array(value) => stk
262 .scope(|scope| {
263 let futs = value.iter().map(|value| {
264 scope.run(|stk| {
265 let rec = rec.with_current(value);
266 self.compute_inner(stk, ctx, opt, doc, rec)
267 })
268 });
269 try_join_all_buffered(futs)
270 })
271 .await
272 .map(Into::into),
273 _ => stk.run(|stk| self.compute_inner(stk, ctx, opt, doc, rec)).await,
274 }
275 }
276
277 pub async fn compute_inner(
278 &self,
279 stk: &mut Stk,
280 ctx: &Context,
281 opt: &Options,
282 doc: Option<&CursorDoc>,
283 rec: Recursion<'a>,
284 ) -> Result<Value, Error> {
285 match self {
286 Self::Repeat => compute_idiom_recursion(stk, ctx, opt, doc, rec).await,
287 Self::Destructure {
288 parts,
289 field,
290 before,
291 plan,
292 after,
293 } => {
294 let v = stk.run(|stk| rec.current.get(stk, ctx, opt, doc, before)).await?;
295 let v = plan.compute(stk, ctx, opt, doc, rec.with_current(&v)).await?;
296 let v = stk.run(|stk| v.get(stk, ctx, opt, doc, after)).await?;
297 let v = clean_iteration(v);
298
299 if rec.iterated < rec.min && is_final(&v) {
300 return Ok(Value::None);
305 }
306
307 let path = &[Part::Destructure(parts.to_owned())];
308 match stk.run(|stk| rec.current.get(stk, ctx, opt, doc, path)).await? {
309 Value::Object(mut obj) => {
310 obj.insert(field.to_raw(), v);
311 Ok(Value::Object(obj))
312 }
313 Value::None => Ok(Value::None),
314 v => Err(Error::Unreachable(format!(
315 "Expected an object or none, found {}.",
316 v.kindof()
317 ))),
318 }
319 }
320 }
321 }
322}
323
324pub trait FindRecursionPlan<'a> {
325 fn find_recursion_plan(&'a self) -> Option<(&'a [Part], RecursionPlan, &'a [Part])>;
326}
327
328impl<'a> FindRecursionPlan<'a> for &'a [Part] {
329 fn find_recursion_plan(&'a self) -> Option<(&'a [Part], RecursionPlan, &'a [Part])> {
330 for (i, p) in self.iter().enumerate() {
331 if let Some(plan) = p.recursion_plan() {
332 return Some((&self[..i], plan, &self[(i + 1)..]));
333 }
334 }
335
336 None
337 }
338}
339
340impl<'a> FindRecursionPlan<'a> for &'a Idiom {
341 fn find_recursion_plan(&'a self) -> Option<(&'a [Part], RecursionPlan, &'a [Part])> {
342 for (i, p) in self.iter().enumerate() {
343 if let Some(plan) = p.recursion_plan() {
344 return Some((&self[..i], plan, &self[(i + 1)..]));
345 }
346 }
347
348 None
349 }
350}
351
352pub trait SplitByRepeatRecurse<'a> {
355 fn split_by_repeat_recurse(&'a self) -> Option<(&'a [Part], &'a [Part])>;
356}
357
358impl<'a> SplitByRepeatRecurse<'a> for &'a [Part] {
359 fn split_by_repeat_recurse(&'a self) -> Option<(&'a [Part], &'a [Part])> {
360 self.iter()
361 .position(|p| matches!(p, Part::RepeatRecurse))
362 .map(|i| (&self[..i], &self[(i + 1)..]))
366 }
367}
368
369impl<'a> SplitByRepeatRecurse<'a> for &'a Idiom {
370 fn split_by_repeat_recurse(&'a self) -> Option<(&'a [Part], &'a [Part])> {
371 self.iter()
372 .position(|p| matches!(p, Part::RepeatRecurse))
373 .map(|i| (&self[..i], &self[(i + 1)..]))
377 }
378}
379
380pub trait Next<'a> {
383 fn next(&'a self) -> &'a [Part];
384}
385
386impl<'a> Next<'a> for &'a [Part] {
387 fn next(&'a self) -> &'a [Part] {
388 match self.len() {
389 0 => &[],
390 _ => &self[1..],
391 }
392 }
393}
394
395pub trait Skip<'a> {
398 fn skip(&'a self, amount: usize) -> &'a [Part];
399}
400
401impl<'a> Skip<'a> for &'a [Part] {
402 fn skip(&'a self, amount: usize) -> &'a [Part] {
403 match self.len() {
404 0 => &[],
405 _ => &self[amount..],
406 }
407 }
408}
409
410pub trait NextMethod<'a> {
413 fn next_method(&'a self) -> &'a [Part];
414}
415
416impl<'a> NextMethod<'a> for &'a [Part] {
417 fn next_method(&'a self) -> &'a [Part] {
418 match self.iter().position(|p| matches!(p, Part::Method(_, _))) {
419 None => &[],
420 Some(i) => &self[i..],
421 }
422 }
423}
424
425impl<'a> NextMethod<'a> for &'a Idiom {
426 fn next_method(&'a self) -> &'a [Part] {
427 match self.iter().position(|p| matches!(p, Part::Method(_, _))) {
428 None => &[],
429 Some(i) => &self[i..],
430 }
431 }
432}
433
434#[revisioned(revision = 1)]
437#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
438#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
439#[non_exhaustive]
440pub enum DestructurePart {
441 All(Ident),
442 Field(Ident),
443 Aliased(Ident, Idiom),
444 Destructure(Ident, Vec<DestructurePart>),
445}
446
447impl DestructurePart {
448 pub fn field(&self) -> &Ident {
449 match self {
450 DestructurePart::All(v) => v,
451 DestructurePart::Field(v) => v,
452 DestructurePart::Aliased(v, _) => v,
453 DestructurePart::Destructure(v, _) => v,
454 }
455 }
456
457 pub fn path(&self) -> Vec<Part> {
458 match self {
459 DestructurePart::All(v) => vec![Part::Field(v.clone()), Part::All],
460 DestructurePart::Field(v) => vec![Part::Field(v.clone())],
461 DestructurePart::Aliased(_, v) => v.0.clone(),
462 DestructurePart::Destructure(f, d) => {
463 vec![Part::Field(f.clone()), Part::Destructure(d.clone())]
464 }
465 }
466 }
467}
468
469impl fmt::Display for DestructurePart {
470 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471 match self {
472 DestructurePart::All(fd) => write!(f, "{fd}.*"),
473 DestructurePart::Field(fd) => write!(f, "{fd}"),
474 DestructurePart::Aliased(fd, v) => write!(f, "{fd}: {v}"),
475 DestructurePart::Destructure(fd, d) => {
476 write!(f, "{fd}{}", Part::Destructure(d.clone()))
477 }
478 }
479 }
480}
481
482#[revisioned(revision = 1)]
485#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
486#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
487#[non_exhaustive]
488pub enum Recurse {
489 Fixed(u32),
490 Range(Option<u32>, Option<u32>),
491}
492
493impl TryInto<(u32, Option<u32>)> for Recurse {
494 type Error = Error;
495 fn try_into(self) -> Result<(u32, Option<u32>), Error> {
496 let v = match self {
497 Recurse::Fixed(v) => (v, Some(v)),
498 Recurse::Range(min, max) => {
499 let min = min.unwrap_or(1);
500 (min, max)
501 }
502 };
503
504 match v {
505 (min, _) if min < 1 => Err(Error::InvalidBound {
506 found: min.to_string(),
507 expected: "at least 1".into(),
508 }),
509 (_, Some(max)) if max > (*IDIOM_RECURSION_LIMIT as u32) => Err(Error::InvalidBound {
510 found: max.to_string(),
511 expected: format!("{} at most", *IDIOM_RECURSION_LIMIT),
512 }),
513 v => Ok(v),
514 }
515 }
516}
517
518impl fmt::Display for Recurse {
519 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
520 match self {
521 Recurse::Fixed(v) => write!(f, "{v}"),
522 Recurse::Range(beg, end) => match (beg, end) {
523 (None, None) => write!(f, ".."),
524 (Some(beg), None) => write!(f, "{beg}.."),
525 (None, Some(end)) => write!(f, "..{end}"),
526 (Some(beg), Some(end)) => write!(f, "{beg}..{end}"),
527 },
528 }
529 }
530}
531
532#[revisioned(revision = 1)]
535#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
536#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
537#[non_exhaustive]
538pub enum RecurseInstruction {
539 Path {
540 inclusive: bool,
542 },
543 Collect {
544 inclusive: bool,
546 },
547 Shortest {
548 expects: Value,
550 inclusive: bool,
552 },
553}
554
555macro_rules! to_vec_value {
556 (&$v: expr) => {
557 match $v {
558 Value::Array(v) => &v.0,
559 v => &vec![v.to_owned()],
560 }
561 };
562 ($v: expr) => {
563 match $v {
564 Value::Array(v) => v.0,
565 v => vec![v],
566 }
567 };
568}
569
570macro_rules! walk_paths {
571 (
572 $stk: ident,
573 $ctx: ident,
574 $opt: ident,
575 $doc: ident,
576 $rec: ident,
577 $finished: ident,
578 $inclusive: ident,
579 $expects: expr
580 ) => {{
581 let mut open: Vec<Value> = vec![];
584
585 let paths = to_vec_value!(&$rec.current);
587
588 for path in paths.iter() {
590 let path = to_vec_value!(&path);
592
593 let Some(last) = path.last() else {
596 continue;
597 };
598
599 let res = $stk.run(|stk| last.get(stk, $ctx, $opt, $doc, $rec.path)).await?;
601
602 if is_final(&res) || &res == last {
609 if $expects.is_none()
610 && ($rec.iterated > 1 || *$inclusive)
611 && $rec.iterated >= $rec.min
612 {
613 $finished.push(path.to_owned().into());
614 }
615
616 continue;
617 }
618
619 let steps = to_vec_value!(res);
621
622 let reached_max = $rec.max.is_some_and(|max| $rec.iterated >= max);
624
625 for step in steps.iter() {
627 let val = if $rec.iterated == 1 && !*$inclusive {
630 Value::from(vec![step.to_owned()])
631 } else {
632 let mut path = path.to_owned();
633 path.push(step.to_owned());
634 Value::from(path)
635 };
636
637 if let Some(expects) = $expects {
641 if step == expects {
642 let steps = to_vec_value!(val);
643
644 for step in steps {
645 $finished.push(step);
646 }
647
648 return Ok(Value::None);
649 }
650 }
651
652 if reached_max {
655 if $expects.is_none() {
656 $finished.push(val);
657 }
658 } else {
659 open.push(val);
660 }
661 }
662 }
663
664 Ok(open.into())
665 }};
666}
667
668impl RecurseInstruction {
669 pub(crate) async fn compute(
670 &self,
671 stk: &mut Stk,
672 ctx: &Context,
673 opt: &Options,
674 doc: Option<&CursorDoc>,
675 rec: Recursion<'_>,
676 finished: &mut Vec<Value>,
677 ) -> Result<Value, Error> {
678 match self {
679 Self::Path {
680 inclusive,
681 } => {
682 walk_paths!(stk, ctx, opt, doc, rec, finished, inclusive, Option::<&Value>::None)
683 }
684 Self::Shortest {
685 expects,
686 inclusive,
687 } => {
688 let expects =
689 Value::from(expects.compute(stk, ctx, opt, doc).await?.coerce_to_record()?);
690 walk_paths!(stk, ctx, opt, doc, rec, finished, inclusive, Some(&expects))
691 }
692 Self::Collect {
693 inclusive,
694 } => {
695 macro_rules! persist {
696 ($finished:ident, $subject:expr) => {
697 match $subject {
698 Value::Array(v) => {
699 for v in v.iter() {
700 if !$finished.contains(v) {
702 $finished.push(v.to_owned());
703 }
704 }
705 }
706 v => {
707 if !$finished.contains(v) {
708 $finished.push(v.to_owned());
710 }
711 }
712 }
713 };
714 }
715
716 if rec.iterated == 1 && *inclusive {
718 persist!(finished, rec.current);
719 }
720
721 let res = stk.run(|stk| rec.current.get(stk, ctx, opt, doc, rec.path)).await?;
723 let res = clean_iteration(res);
725
726 persist!(finished, &res);
728
729 Ok(res)
731 }
732 }
733 }
734}
735
736impl fmt::Display for RecurseInstruction {
737 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
738 match self {
739 Self::Path {
740 inclusive,
741 } => {
742 write!(f, "path")?;
743
744 if *inclusive {
745 write!(f, "+inclusive")?;
746 }
747
748 Ok(())
749 }
750 Self::Collect {
751 inclusive,
752 } => {
753 write!(f, "collect")?;
754
755 if *inclusive {
756 write!(f, "+inclusive")?;
757 }
758
759 Ok(())
760 }
761 Self::Shortest {
762 expects,
763 inclusive,
764 } => {
765 write!(f, "shortest={expects}")?;
766
767 if *inclusive {
768 write!(f, "+inclusive")?;
769 }
770
771 Ok(())
772 }
773 }
774 }
775}