surql_parser/upstream/sql/statements/
ifelse.rs1use crate::upstream::fmt::{CoverStmts, Fmt, fmt_separated_by};
2use crate::upstream::sql::Expr;
3use surrealdb_types::{SqlFormat, ToSql, write_sql};
4#[derive(Clone, Debug, Default, Eq, PartialEq)]
5#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
6pub struct IfelseStatement {
7 #[cfg_attr(
10 feature = "arbitrary",
11 arbitrary(with = crate::upstream::sql::arbitrary::atleast_one)
12 )]
13 pub exprs: Vec<(Expr, Expr)>,
14 pub close: Option<Expr>,
16}
17impl IfelseStatement {
18 pub fn bracketed(&self) -> bool {
20 self.exprs.iter().all(|(_, v)| matches!(v, Expr::Block(_)))
21 && self
22 .close
23 .as_ref()
24 .map(|v| matches!(v, Expr::Block(_)))
25 .unwrap_or(true)
26 }
27}
28impl ToSql for IfelseStatement {
29 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
30 if self.bracketed() {
31 let is_simple_block = |expr: &Expr| -> bool {
32 if let Expr::Block(block) = expr {
33 block.0.iter().all(|stmt| {
34 matches!(stmt, Expr::Literal(_) | Expr::Param(_) | Expr::Idiom(_))
35 })
36 } else {
37 false
38 }
39 };
40 let has_complex_multi = self.exprs.iter().any(|(_, expr)| {
41 matches!(
42 expr, Expr::Block(block) if block.0.len() > 1 && !
43 is_simple_block(expr)
44 )
45 }) || self
46 .close
47 .as_ref()
48 .map(|expr| {
49 matches!(
50 expr, Expr::Block(block) if block.0.len() > 1 && !
51 is_simple_block(expr)
52 )
53 })
54 .unwrap_or(false);
55 let fmt_block = |f: &mut String, fmt: SqlFormat, expr: &Expr, use_separated: bool| {
56 if let Expr::Block(block) = expr {
57 match block.0.len() {
58 0 => f.push_str("{;}"),
59 1 if !use_separated => {
60 f.push_str("{ ");
61 block.0[0].fmt_sql(f, SqlFormat::SingleLine);
62 f.push_str(" }");
63 }
64 1 => {
65 f.push('{');
66 f.push(' ');
67 block.0[0].fmt_sql(f, SqlFormat::SingleLine);
68 f.push(' ');
69 f.push('}');
70 }
71 _ => {
72 let needs_indent = is_simple_block(expr);
73 if fmt.is_pretty() && !needs_indent {
74 f.push_str("{\n\n");
75 let inner_fmt = fmt.increment();
76 for (i, stmt) in block.0.iter().enumerate() {
77 if i > 0 {
78 f.push('\n');
79 f.push('\n');
80 }
81 inner_fmt.write_indent(f);
82 stmt.fmt_sql(f, SqlFormat::SingleLine);
83 f.push(';');
84 }
85 f.push('\n');
86 fmt.write_indent(f);
87 f.push('\n');
88 f.push('}');
89 } else if fmt.is_pretty() {
90 f.push_str("{\n\n");
91 for (i, stmt) in block.0.iter().enumerate() {
92 if i > 0 {
93 f.push('\n');
94 }
95 f.push('\t');
96 stmt.fmt_sql(f, SqlFormat::SingleLine);
97 f.push(';');
98 }
99 f.push_str("\n}");
100 } else {
101 f.push_str("{\n");
102 for (i, stmt) in block.0.iter().enumerate() {
103 if i > 0 {
104 f.push('\n');
105 }
106 if needs_indent {
107 f.push('\t');
108 }
109 stmt.fmt_sql(f, SqlFormat::SingleLine);
110 f.push(';');
111 }
112 f.push_str("\n}");
113 }
114 }
115 }
116 } else {
117 expr.fmt_sql(f, fmt);
118 }
119 };
120 let is_nested = matches!(fmt, SqlFormat::Indented(level) if level > 0);
121 let use_separated = fmt.is_pretty() && (has_complex_multi || is_nested);
122 write_sql!(
123 f,
124 fmt,
125 "{}",
126 &Fmt::new(
127 self.exprs.iter().map(|args| {
128 Fmt::new(args, |(cond, then), f, fmt| {
129 if use_separated {
130 write_sql!(f, fmt, "IF {}", CoverStmts(cond));
131 f.push('\n');
132 if is_nested {
133 fmt.write_indent(f);
134 fmt_block(f, fmt, then, true);
135 } else {
136 let fmt = fmt.increment();
137 fmt.write_indent(f);
138 fmt_block(f, fmt, then, true);
139 }
140 } else {
141 write_sql!(f, fmt, "IF {} ", CoverStmts(cond));
142 fmt_block(f, fmt, then, false);
143 }
144 })
145 }),
146 if use_separated {
147 fmt_separated_by("\nELSE ")
148 } else {
149 fmt_separated_by(" ELSE ")
150 },
151 ),
152 );
153 if let Some(ref v) = self.close {
154 if use_separated {
155 f.push('\n');
156 write_sql!(f, fmt, "ELSE");
157 f.push('\n');
158 if is_nested {
159 fmt.write_indent(f);
160 fmt_block(f, fmt, v, true);
161 } else {
162 let fmt = fmt.increment();
163 fmt.write_indent(f);
164 fmt_block(f, fmt, v, true);
165 }
166 } else {
167 write_sql!(f, fmt, " ELSE ");
168 fmt_block(f, fmt, v, false);
169 }
170 }
171 } else {
172 write_sql!(
173 f,
174 fmt,
175 "{}",
176 &Fmt::new(
177 self.exprs.iter().map(|args| {
178 Fmt::new(args, |(cond, then), f, fmt| {
179 if fmt.is_pretty() {
180 write_sql!(f, fmt, "IF {} THEN", CoverStmts(cond));
181 f.push('\n');
182 let fmt = fmt.increment();
183 fmt.write_indent(f);
184 if let Expr::IfElse(then) = then
185 && then.bracketed()
186 {
187 write_sql!(f, fmt, "({then})");
188 } else {
189 write_sql!(f, fmt, "{then}");
190 }
191 } else {
192 write_sql!(f, fmt, "IF {} THEN ", CoverStmts(cond));
193 if let Expr::IfElse(then) = then
194 && then.bracketed()
195 {
196 write_sql!(f, fmt, "({then})");
197 } else {
198 write_sql!(f, fmt, "{then}");
199 }
200 }
201 })
202 }),
203 if fmt.is_pretty() {
204 fmt_separated_by("\nELSE ")
205 } else {
206 fmt_separated_by(" ELSE ")
207 },
208 ),
209 );
210 if let Some(ref v) = self.close {
211 if fmt.is_pretty() {
212 f.push('\n');
213 write_sql!(f, fmt, "ELSE");
214 f.push('\n');
215 let fmt = fmt.increment();
216 fmt.write_indent(f);
217 write_sql!(f, fmt, "{}", CoverStmts(v));
218 } else {
219 write_sql!(f, fmt, " ELSE {}", CoverStmts(v));
220 }
221 }
222 if fmt.is_pretty() {
223 write_sql!(f, fmt, "END");
224 } else {
225 write_sql!(f, fmt, " END");
226 }
227 }
228 }
229}