surrealdb_core/sql/
block.rs

1use crate::ctx::{Context, MutableContext};
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty};
6use crate::sql::statements::info::InfoStructure;
7use crate::sql::statements::rebuild::RebuildStatement;
8use crate::sql::statements::{
9	AlterStatement, BreakStatement, ContinueStatement, CreateStatement, DefineStatement,
10	DeleteStatement, ForeachStatement, IfelseStatement, InsertStatement, OutputStatement,
11	RelateStatement, RemoveStatement, SelectStatement, SetStatement, ThrowStatement,
12	UpdateStatement, UpsertStatement,
13};
14use crate::sql::value::Value;
15use reblessive::tree::Stk;
16use revision::revisioned;
17use serde::{Deserialize, Serialize};
18use std::cmp::Ordering;
19use std::fmt::{self, Display, Formatter, Write};
20use std::ops::Deref;
21
22pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Block";
23
24#[revisioned(revision = 1)]
25#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
26#[serde(rename = "$surrealdb::private::sql::Block")]
27#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
28#[non_exhaustive]
29pub struct Block(pub Vec<Entry>);
30
31impl Deref for Block {
32	type Target = Vec<Entry>;
33	fn deref(&self) -> &Self::Target {
34		&self.0
35	}
36}
37
38impl From<Value> for Block {
39	fn from(v: Value) -> Self {
40		Block(vec![Entry::Value(v)])
41	}
42}
43
44impl Block {
45	/// Check if we require a writeable transaction
46	pub(crate) fn writeable(&self) -> bool {
47		self.iter().any(Entry::writeable)
48	}
49	/// Process this type returning a computed simple Value
50	pub(crate) async fn compute(
51		&self,
52		stk: &mut Stk,
53		ctx: &Context,
54		opt: &Options,
55		doc: Option<&CursorDoc>,
56	) -> Result<Value, Error> {
57		// Duplicate context
58		let mut ctx = MutableContext::new(ctx).freeze();
59		// Loop over the statements
60		for (i, v) in self.iter().enumerate() {
61			match v {
62				Entry::Set(v) => {
63					let val = v.compute(stk, &ctx, opt, doc).await?;
64					let mut c = MutableContext::unfreeze(ctx)?;
65					c.add_value(v.name.to_owned(), val.into());
66					ctx = c.freeze();
67				}
68				Entry::Throw(v) => {
69					// Always errors immediately
70					v.compute(stk, &ctx, opt, doc).await?;
71				}
72				Entry::Break(v) => {
73					// Always errors immediately
74					v.compute(&ctx, opt, doc).await?;
75				}
76				Entry::Continue(v) => {
77					// Always errors immediately
78					v.compute(&ctx, opt, doc).await?;
79				}
80				Entry::Foreach(v) => {
81					v.compute(stk, &ctx, opt, doc).await?;
82				}
83				Entry::Ifelse(v) => {
84					v.compute(stk, &ctx, opt, doc).await?;
85				}
86				Entry::Select(v) => {
87					v.compute(stk, &ctx, opt, doc).await?;
88				}
89				Entry::Create(v) => {
90					v.compute(stk, &ctx, opt, doc).await?;
91				}
92				Entry::Upsert(v) => {
93					v.compute(stk, &ctx, opt, doc).await?;
94				}
95				Entry::Update(v) => {
96					v.compute(stk, &ctx, opt, doc).await?;
97				}
98				Entry::Delete(v) => {
99					v.compute(stk, &ctx, opt, doc).await?;
100				}
101				Entry::Relate(v) => {
102					v.compute(stk, &ctx, opt, doc).await?;
103				}
104				Entry::Insert(v) => {
105					v.compute(stk, &ctx, opt, doc).await?;
106				}
107				Entry::Define(v) => {
108					v.compute(stk, &ctx, opt, doc).await?;
109				}
110				Entry::Rebuild(v) => {
111					v.compute(stk, &ctx, opt, doc).await?;
112				}
113				Entry::Remove(v) => {
114					v.compute(&ctx, opt, doc).await?;
115				}
116				Entry::Output(v) => {
117					v.compute(stk, &ctx, opt, doc).await?;
118				}
119				Entry::Alter(v) => {
120					v.compute(stk, &ctx, opt, doc).await?;
121				}
122				Entry::Value(v) => {
123					if i == self.len() - 1 {
124						// If the last entry then return the value
125						return v.compute_unbordered(stk, &ctx, opt, doc).await;
126					} else {
127						// Otherwise just process the value
128						v.compute_unbordered(stk, &ctx, opt, doc).await?;
129					}
130				}
131			}
132		}
133		// Return nothing
134		Ok(Value::None)
135	}
136}
137
138impl Display for Block {
139	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
140		let mut f = Pretty::from(f);
141		match (self.len(), self.first()) {
142			(0, _) => f.write_str("{}"),
143			(1, Some(Entry::Value(v))) => {
144				write!(f, "{{ {v} }}")
145			}
146			(l, _) => {
147				f.write_char('{')?;
148				if l > 1 {
149					f.write_char('\n')?;
150				} else if !is_pretty() {
151					f.write_char(' ')?;
152				}
153				let indent = pretty_indent();
154				if is_pretty() {
155					write!(
156						f,
157						"{}",
158						&Fmt::two_line_separated(
159							self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))),
160						)
161					)?;
162				} else {
163					write!(
164						f,
165						"{}",
166						&Fmt::one_line_separated(
167							self.0.iter().map(|args| Fmt::new(args, |v, f| write!(f, "{};", v))),
168						)
169					)?;
170				}
171				drop(indent);
172				if l > 1 {
173					f.write_char('\n')?;
174				} else if !is_pretty() {
175					f.write_char(' ')?;
176				}
177				f.write_char('}')
178			}
179		}
180	}
181}
182
183impl InfoStructure for Block {
184	fn structure(self) -> Value {
185		self.to_string().into()
186	}
187}
188
189#[revisioned(revision = 4)]
190#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
191#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
192#[non_exhaustive]
193pub enum Entry {
194	Value(Value),
195	Set(SetStatement),
196	Ifelse(IfelseStatement),
197	Select(SelectStatement),
198	Create(CreateStatement),
199	Update(UpdateStatement),
200	Delete(DeleteStatement),
201	Relate(RelateStatement),
202	Insert(InsertStatement),
203	Output(OutputStatement),
204	Define(DefineStatement),
205	Remove(RemoveStatement),
206	Throw(ThrowStatement),
207	Break(BreakStatement),
208	Continue(ContinueStatement),
209	Foreach(ForeachStatement),
210	#[revision(start = 2)]
211	Rebuild(RebuildStatement),
212	#[revision(start = 3)]
213	Upsert(UpsertStatement),
214	#[revision(start = 4)]
215	Alter(AlterStatement),
216}
217
218impl PartialOrd for Entry {
219	#[inline]
220	fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
221		None
222	}
223}
224
225impl Entry {
226	/// Check if we require a writeable transaction
227	pub(crate) fn writeable(&self) -> bool {
228		match self {
229			Self::Set(v) => v.writeable(),
230			Self::Value(v) => v.writeable(),
231			Self::Ifelse(v) => v.writeable(),
232			Self::Select(v) => v.writeable(),
233			Self::Create(v) => v.writeable(),
234			Self::Upsert(v) => v.writeable(),
235			Self::Update(v) => v.writeable(),
236			Self::Delete(v) => v.writeable(),
237			Self::Relate(v) => v.writeable(),
238			Self::Insert(v) => v.writeable(),
239			Self::Output(v) => v.writeable(),
240			Self::Define(v) => v.writeable(),
241			Self::Rebuild(v) => v.writeable(),
242			Self::Remove(v) => v.writeable(),
243			Self::Throw(v) => v.writeable(),
244			Self::Break(v) => v.writeable(),
245			Self::Continue(v) => v.writeable(),
246			Self::Foreach(v) => v.writeable(),
247			Self::Alter(v) => v.writeable(),
248		}
249	}
250}
251
252impl Display for Entry {
253	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
254		match self {
255			Self::Set(v) => write!(f, "{v}"),
256			Self::Value(v) => Display::fmt(v, f),
257			Self::Ifelse(v) => write!(f, "{v}"),
258			Self::Select(v) => write!(f, "{v}"),
259			Self::Create(v) => write!(f, "{v}"),
260			Self::Upsert(v) => write!(f, "{v}"),
261			Self::Update(v) => write!(f, "{v}"),
262			Self::Delete(v) => write!(f, "{v}"),
263			Self::Relate(v) => write!(f, "{v}"),
264			Self::Insert(v) => write!(f, "{v}"),
265			Self::Output(v) => write!(f, "{v}"),
266			Self::Define(v) => write!(f, "{v}"),
267			Self::Rebuild(v) => write!(f, "{v}"),
268			Self::Remove(v) => write!(f, "{v}"),
269			Self::Throw(v) => write!(f, "{v}"),
270			Self::Break(v) => write!(f, "{v}"),
271			Self::Continue(v) => write!(f, "{v}"),
272			Self::Foreach(v) => write!(f, "{v}"),
273			Self::Alter(v) => write!(f, "{v}"),
274		}
275	}
276}