surql_parser/upstream/sql/
part.rs1use crate::upstream::fmt::{CoverStmts, EscapeKwFreeIdent, Fmt};
2use crate::upstream::sql::{Expr, Idiom, Lookup};
3use surrealdb_types::{SqlFormat, ToSql, write_sql};
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub enum Part {
6 All,
7 Flatten,
8 Last,
9 First,
10 Field(String),
11 Where(Expr),
12 Graph(Lookup),
13 Value(Expr),
14 Start(Expr),
15 Method(String, Vec<Expr>),
16 Destructure(Vec<DestructurePart>),
17 Optional,
18 Recurse(Recurse, Option<Idiom>, Option<RecurseInstruction>),
19 Doc,
20 RepeatRecurse,
21}
22impl ToSql for Part {
23 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
24 match self {
25 Part::All => f.push_str(".*"),
26 Part::Last => f.push_str("[$]"),
27 Part::First => f.push_str("[0]"),
28 Part::Start(v) => v.fmt_sql(f, fmt),
29 Part::Field(v) => write_sql!(f, fmt, ".{}", EscapeKwFreeIdent(v)),
30 Part::Flatten => f.push('…'),
31 Part::Where(v) => write_sql!(f, fmt, "[WHERE {v}]"),
32 Part::Graph(v) => v.fmt_sql(f, fmt),
33 Part::Value(v) => write_sql!(f, fmt, "[{v}]"),
34 Part::Method(v, a) => {
35 write_sql!(
36 f,
37 fmt,
38 ".{}({})",
39 EscapeKwFreeIdent(v),
40 Fmt::comma_separated(a.iter().map(CoverStmts))
41 )
42 }
43 Part::Destructure(v) => {
44 f.push_str(".{");
45 if !fmt.is_pretty() {
46 f.push(' ');
47 }
48 if !v.is_empty() {
49 let fmt = fmt.increment();
50 write_sql!(f, fmt, "{}", Fmt::pretty_comma_separated(v));
51 }
52 if fmt.is_pretty() {
53 f.push('}');
54 } else {
55 f.push_str(" }");
56 }
57 }
58 Part::Optional => f.push_str(".?"),
59 Part::Recurse(v, nest, instruction) => {
60 write_sql!(f, fmt, ".{{{v}");
61 if let Some(instruction) = instruction {
62 write_sql!(f, fmt, "+{instruction}");
63 }
64 f.push('}');
65 if let Some(nest) = nest {
66 f.push('(');
67 for p in nest.0.iter() {
68 p.fmt_sql(f, fmt);
69 }
70 f.push(')');
71 }
72 }
73 Part::Doc => f.push('@'),
74 Part::RepeatRecurse => f.push_str(".@"),
75 }
76 }
77}
78#[derive(Clone, Debug, PartialEq, Eq)]
79#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
80pub enum DestructurePart {
81 All(String),
82 Field(String),
83 Aliased(String, Idiom),
84 Destructure(String, Vec<DestructurePart>),
85}
86impl ToSql for DestructurePart {
87 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
88 match self {
89 DestructurePart::All(fd) => write_sql!(f, fmt, "{}.*", EscapeKwFreeIdent(fd)),
90 DestructurePart::Field(fd) => write_sql!(f, fmt, "{}", EscapeKwFreeIdent(fd)),
91 DestructurePart::Aliased(fd, v) => {
92 write_sql!(f, fmt, "{}: {v}", EscapeKwFreeIdent(fd))
93 }
94 DestructurePart::Destructure(fd, d) => {
95 write_sql!(
96 f,
97 fmt,
98 "{}{}",
99 EscapeKwFreeIdent(fd),
100 Part::Destructure(d.clone())
101 )
102 }
103 }
104 }
105}
106#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
107#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
108pub enum Recurse {
109 Fixed(u32),
110 Range(Option<u32>, Option<u32>),
111}
112impl ToSql for Recurse {
113 fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
114 match self {
115 Recurse::Fixed(v) => f.push_str(&v.to_string()),
116 Recurse::Range(beg, end) => match (beg, end) {
117 (None, None) => f.push_str(".."),
118 (Some(beg), None) => {
119 f.push_str(&beg.to_string());
120 f.push_str("..");
121 }
122 (None, Some(end)) => {
123 f.push_str("..");
124 f.push_str(&end.to_string());
125 }
126 (Some(beg), Some(end)) => {
127 f.push_str(&beg.to_string());
128 f.push_str("..");
129 f.push_str(&end.to_string());
130 }
131 },
132 }
133 }
134}
135#[derive(Clone, Debug, PartialEq, Eq)]
136pub enum RecurseInstruction {
137 Path { inclusive: bool },
138 Collect { inclusive: bool },
139 Shortest { expects: Expr, inclusive: bool },
140}
141impl ToSql for RecurseInstruction {
142 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
143 match self {
144 Self::Path { inclusive } => {
145 f.push_str("path");
146 if *inclusive {
147 f.push_str("+inclusive");
148 }
149 }
150 Self::Collect { inclusive } => {
151 f.push_str("collect");
152 if *inclusive {
153 f.push_str("+inclusive");
154 }
155 }
156 Self::Shortest { expects, inclusive } => {
157 write_sql!(f, fmt, "shortest={expects}");
158 if *inclusive {
159 f.push_str("+inclusive");
160 }
161 }
162 }
163 }
164}