surrealdb_sql/
block.rs

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	/// Check if we require a writeable transaction
40	pub(crate) fn writeable(&self) -> bool {
41		self.iter().any(Entry::writeable)
42	}
43	/// Process this type returning a computed simple Value
44	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		// Duplicate context
52		let mut ctx = Context::new(ctx);
53		// Loop over the statements
54		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					// Always errors immediately
62					v.compute(&ctx, opt, txn, doc).await?;
63				}
64				Entry::Break(v) => {
65					// Always errors immediately
66					v.compute(&ctx, opt, txn, doc).await?;
67				}
68				Entry::Continue(v) => {
69					// Always errors immediately
70					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 the RETURN value
104					return v.compute(&ctx, opt, txn, doc).await;
105				}
106				Entry::Value(v) => {
107					if i == self.len() - 1 {
108						// If the last entry then return the value
109						return v.compute(&ctx, opt, txn, doc).await;
110					} else {
111						// Otherwise just process the value
112						v.compute(&ctx, opt, txn, doc).await?;
113					}
114				}
115			}
116		}
117		// Return nothing
118		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	/// Check if we require a writeable transaction
197	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}