surrealdb_core/sql/statements/
ifelse.rs1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::sql::fmt::{fmt_separated_by, is_pretty, pretty_indent, Fmt, Pretty};
6use crate::sql::Value;
7
8use reblessive::tree::Stk;
9use revision::revisioned;
10use serde::{Deserialize, Serialize};
11use std::fmt::{self, Display, Write};
12
13#[revisioned(revision = 1)]
14#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16#[non_exhaustive]
17pub struct IfelseStatement {
18 pub exprs: Vec<(Value, Value)>,
20 pub close: Option<Value>,
22}
23
24impl IfelseStatement {
25 pub(crate) fn writeable(&self) -> bool {
27 for (cond, then) in self.exprs.iter() {
28 if cond.writeable() || then.writeable() {
29 return true;
30 }
31 }
32 self.close.as_ref().is_some_and(Value::writeable)
33 }
34 pub(crate) fn bracketed(&self) -> bool {
36 self.exprs.iter().all(|(_, v)| matches!(v, Value::Block(_)))
37 && (self.close.as_ref().is_none()
38 || self.close.as_ref().is_some_and(|v| matches!(v, Value::Block(_))))
39 }
40 pub(crate) async fn compute(
42 &self,
43 stk: &mut Stk,
44 ctx: &Context,
45 opt: &Options,
46 doc: Option<&CursorDoc>,
47 ) -> Result<Value, Error> {
48 for (ref cond, ref then) in &self.exprs {
49 let v = cond.compute(stk, ctx, opt, doc).await?;
50 if v.is_truthy() {
51 return then.compute_unbordered(stk, ctx, opt, doc).await;
52 }
53 }
54 match self.close {
55 Some(ref v) => v.compute_unbordered(stk, ctx, opt, doc).await,
56 None => Ok(Value::None),
57 }
58 }
59}
60
61impl Display for IfelseStatement {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 let mut f = Pretty::from(f);
64 match self.bracketed() {
65 true => {
66 write!(
67 f,
68 "{}",
69 &Fmt::new(
70 self.exprs.iter().map(|args| {
71 Fmt::new(args, |(cond, then), f| {
72 if is_pretty() {
73 write!(f, "IF {cond}")?;
74 let indent = pretty_indent();
75 write!(f, "{then}")?;
76 drop(indent);
77 } else {
78 write!(f, "IF {cond} {then}")?;
79 }
80 Ok(())
81 })
82 }),
83 if is_pretty() {
84 fmt_separated_by("ELSE ")
85 } else {
86 fmt_separated_by(" ELSE ")
87 },
88 ),
89 )?;
90 if let Some(ref v) = self.close {
91 if is_pretty() {
92 write!(f, "ELSE")?;
93 let indent = pretty_indent();
94 write!(f, "{v}")?;
95 drop(indent);
96 } else {
97 write!(f, " ELSE {v}")?;
98 }
99 }
100 Ok(())
101 }
102 false => {
103 write!(
104 f,
105 "{}",
106 &Fmt::new(
107 self.exprs.iter().map(|args| {
108 Fmt::new(args, |(cond, then), f| {
109 if is_pretty() {
110 write!(f, "IF {cond} THEN")?;
111 let indent = pretty_indent();
112 write!(f, "{then}")?;
113 drop(indent);
114 } else {
115 write!(f, "IF {cond} THEN {then}")?;
116 }
117 Ok(())
118 })
119 }),
120 if is_pretty() {
121 fmt_separated_by("ELSE ")
122 } else {
123 fmt_separated_by(" ELSE ")
124 },
125 ),
126 )?;
127 if let Some(ref v) = self.close {
128 if is_pretty() {
129 write!(f, "ELSE")?;
130 let indent = pretty_indent();
131 write!(f, "{v}")?;
132 drop(indent);
133 } else {
134 write!(f, " ELSE {v}")?;
135 }
136 }
137 if is_pretty() {
138 f.write_str("END")?;
139 } else {
140 f.write_str(" END")?;
141 }
142 Ok(())
143 }
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use crate::syn::parse;
151
152 #[test]
153 fn format_pretty() {
154 let query = parse("IF 1 { 1 } ELSE IF 2 { 2 }").unwrap();
155 assert_eq!(format!("{}", query), "IF 1 { 1 } ELSE IF 2 { 2 };");
156 assert_eq!(format!("{:#}", query), "IF 1\n\t{ 1 }\nELSE IF 2\n\t{ 2 }\n;");
157 }
158}