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