Skip to main content

surrealdb_sql/
output.rs

1use surrealdb_types::{SqlFormat, ToSql, write_sql};
2
3use crate::field::{Fields, Selector};
4use crate::{CoverStmts, Field};
5
6#[derive(Clone, Debug, Default, PartialEq, Eq)]
7#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
8pub enum Output {
9	#[default]
10	None,
11	Null,
12	Diff,
13	After,
14	Before,
15	Fields(Fields),
16}
17
18impl ToSql for Output {
19	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
20		f.push_str("RETURN ");
21		match self {
22			// TODO: This none here is really annoying for parsing and formatting.
23			// it conflicts with value NONE. Ideally we should find some way to differentiate with
24			// `NONE` the clause and `NONE` the value.
25			Self::None => f.push_str("NONE"),
26			Self::Null => f.push_str("NULL"),
27			Self::Diff => f.push_str("DIFF"),
28			Self::After => f.push_str("AFTER"),
29			Self::Before => f.push_str("BEFORE"),
30			Self::Fields(v) => {
31				// We need to escape a possible `RETURN NONE` where `NONE` is a value
32				match v {
33					Fields::Select(fields) => {
34						let mut iter = fields.iter();
35						match iter.next() {
36							Some(Field::Single(Selector {
37								expr,
38								alias,
39							})) => {
40								// Check for a expression with none on the left like `NONE + 1`
41								// which will be mistaken for the `NONE` clause formatted above.
42								let has_left_none = expr.has_left_none_null();
43								if has_left_none {
44									f.push('(');
45									expr.fmt_sql(f, fmt);
46									f.push(')');
47								} else {
48									CoverStmts(expr).fmt_sql(f, fmt);
49								}
50								if let Some(alias) = alias {
51									write_sql!(f, fmt, " AS {alias}");
52								}
53							}
54							Some(x) => {
55								x.fmt_sql(f, fmt);
56							}
57							None => {}
58						}
59
60						for x in iter {
61							write_sql!(f, fmt, ", {x}")
62						}
63					}
64					x => x.fmt_sql(f, fmt),
65				}
66			}
67		}
68	}
69}