1use crate::ctx::Context;
2use crate::dbs::{Options, Transaction};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::fmt::{is_pretty, pretty_indent, Fmt, Pretty};
6use crate::statements::{
7 BreakStatement, ContinueStatement, CreateStatement, DefineStatement, DeleteStatement,
8 ForeachStatement, IfelseStatement, InsertStatement, OutputStatement, RelateStatement,
9 RemoveStatement, SelectStatement, SetStatement, ThrowStatement, UpdateStatement,
10};
11use crate::value::Value;
12use revision::revisioned;
13use serde::{Deserialize, Serialize};
14use std::cmp::Ordering;
15use std::fmt::{self, Display, Formatter, Write};
16use std::ops::Deref;
17
18pub(crate) const TOKEN: &str = "$surrealdb::private::crate::Block";
19
20#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
21#[serde(rename = "$surrealdb::private::crate::Block")]
22#[revisioned(revision = 1)]
23pub struct Block(pub Vec<Entry>);
24
25impl Deref for Block {
26 type Target = Vec<Entry>;
27 fn deref(&self) -> &Self::Target {
28 &self.0
29 }
30}
31
32impl From<Value> for Block {
33 fn from(v: Value) -> Self {
34 Block(vec![Entry::Value(v)])
35 }
36}
37
38impl Block {
39 pub(crate) fn writeable(&self) -> bool {
41 self.iter().any(Entry::writeable)
42 }
43 pub(crate) async fn compute(
45 &self,
46 ctx: &Context<'_>,
47 opt: &Options,
48 txn: &Transaction,
49 doc: Option<&CursorDoc<'_>>,
50 ) -> Result<Value, Error> {
51 let mut ctx = Context::new(ctx);
53 for (i, v) in self.iter().enumerate() {
55 match v {
56 Entry::Set(v) => {
57 let val = v.compute(&ctx, opt, txn, doc).await?;
58 ctx.add_value(v.name.to_owned(), val);
59 }
60 Entry::Throw(v) => {
61 v.compute(&ctx, opt, txn, doc).await?;
63 }
64 Entry::Break(v) => {
65 v.compute(&ctx, opt, txn, doc).await?;
67 }
68 Entry::Continue(v) => {
69 v.compute(&ctx, opt, txn, doc).await?;
71 }
72 Entry::Foreach(v) => {
73 v.compute(&ctx, opt, txn, doc).await?;
74 }
75 Entry::Ifelse(v) => {
76 v.compute(&ctx, opt, txn, doc).await?;
77 }
78 Entry::Select(v) => {
79 v.compute(&ctx, opt, txn, doc).await?;
80 }
81 Entry::Create(v) => {
82 v.compute(&ctx, opt, txn, doc).await?;
83 }
84 Entry::Update(v) => {
85 v.compute(&ctx, opt, txn, doc).await?;
86 }
87 Entry::Delete(v) => {
88 v.compute(&ctx, opt, txn, doc).await?;
89 }
90 Entry::Relate(v) => {
91 v.compute(&ctx, opt, txn, doc).await?;
92 }
93 Entry::Insert(v) => {
94 v.compute(&ctx, opt, txn, doc).await?;
95 }
96 Entry::Define(v) => {
97 v.compute(&ctx, opt, txn, doc).await?;
98 }
99 Entry::Remove(v) => {
100 v.compute(&ctx, opt, txn, doc).await?;
101 }
102 Entry::Output(v) => {
103 return v.compute(&ctx, opt, txn, doc).await;
105 }
106 Entry::Value(v) => {
107 if i == self.len() - 1 {
108 return v.compute(&ctx, opt, txn, doc).await;
110 } else {
111 v.compute(&ctx, opt, txn, doc).await?;
113 }
114 }
115 }
116 }
117 Ok(Value::None)
119 }
120}
121
122impl Display for Block {
123 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
124 let mut f = Pretty::from(f);
125 match (self.len(), self.first()) {
126 (0, _) => f.write_str("{}"),
127 (1, Some(Entry::Value(v))) => {
128 write!(f, "{{ {v} }}")
129 }
130 (l, _) => {
131 f.write_char('{')?;
132 if l > 1 {
133 f.write_char('\n')?;
134 } else if !is_pretty() {
135 f.write_char(' ')?;
136 }
137 let indent = pretty_indent();
138 if is_pretty() {
139 write!(
140 f,
141 "{}",
142 &Fmt::two_line_separated(
143 self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))),
144 )
145 )?;
146 } else {
147 write!(
148 f,
149 "{}",
150 &Fmt::one_line_separated(
151 self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))),
152 )
153 )?;
154 }
155 drop(indent);
156 if l > 1 {
157 f.write_char('\n')?;
158 } else if !is_pretty() {
159 f.write_char(' ')?;
160 }
161 f.write_char('}')
162 }
163 }
164 }
165}
166
167#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
168#[revisioned(revision = 1)]
169pub enum Entry {
170 Value(Value),
171 Set(SetStatement),
172 Ifelse(IfelseStatement),
173 Select(SelectStatement),
174 Create(CreateStatement),
175 Update(UpdateStatement),
176 Delete(DeleteStatement),
177 Relate(RelateStatement),
178 Insert(InsertStatement),
179 Output(OutputStatement),
180 Define(DefineStatement),
181 Remove(RemoveStatement),
182 Throw(ThrowStatement),
183 Break(BreakStatement),
184 Continue(ContinueStatement),
185 Foreach(ForeachStatement),
186}
187
188impl PartialOrd for Entry {
189 #[inline]
190 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
191 None
192 }
193}
194
195impl Entry {
196 pub(crate) fn writeable(&self) -> bool {
198 match self {
199 Self::Set(v) => v.writeable(),
200 Self::Value(v) => v.writeable(),
201 Self::Ifelse(v) => v.writeable(),
202 Self::Select(v) => v.writeable(),
203 Self::Create(v) => v.writeable(),
204 Self::Update(v) => v.writeable(),
205 Self::Delete(v) => v.writeable(),
206 Self::Relate(v) => v.writeable(),
207 Self::Insert(v) => v.writeable(),
208 Self::Output(v) => v.writeable(),
209 Self::Define(v) => v.writeable(),
210 Self::Remove(v) => v.writeable(),
211 Self::Throw(v) => v.writeable(),
212 Self::Break(v) => v.writeable(),
213 Self::Continue(v) => v.writeable(),
214 Self::Foreach(v) => v.writeable(),
215 }
216 }
217}
218
219impl Display for Entry {
220 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
221 match self {
222 Self::Set(v) => write!(f, "{v}"),
223 Self::Value(v) => Display::fmt(v, f),
224 Self::Ifelse(v) => write!(f, "{v}"),
225 Self::Select(v) => write!(f, "{v}"),
226 Self::Create(v) => write!(f, "{v}"),
227 Self::Update(v) => write!(f, "{v}"),
228 Self::Delete(v) => write!(f, "{v}"),
229 Self::Relate(v) => write!(f, "{v}"),
230 Self::Insert(v) => write!(f, "{v}"),
231 Self::Output(v) => write!(f, "{v}"),
232 Self::Define(v) => write!(f, "{v}"),
233 Self::Remove(v) => write!(f, "{v}"),
234 Self::Throw(v) => write!(f, "{v}"),
235 Self::Break(v) => write!(f, "{v}"),
236 Self::Continue(v) => write!(f, "{v}"),
237 Self::Foreach(v) => write!(f, "{v}"),
238 }
239 }
240}