Skip to main content

surrealdb_sql/statements/
relate.rs

1use surrealdb_types::{SqlFormat, ToSql, write_sql};
2
3use crate::{CoverStmts, Data, Expr, Literal, Output, RecordIdKeyLit, RecordIdLit};
4
5#[derive(Clone, Debug, PartialEq, Eq)]
6#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7pub struct RelateStatement {
8	pub only: bool,
9	/// When true, update an existing edge record with the same explicit id.
10	pub or_update: bool,
11	/// The expression through which we create a relation
12	pub through: Expr,
13	/// The expression the relation is from
14	pub from: Expr,
15	/// The expression the relation targets.
16	pub to: Expr,
17	/// The data associated with the relation being created
18	pub data: Option<Data>,
19	/// What the result of the statement should resemble (i.e. Diff or no result etc).
20	pub output: Option<Output>,
21	/// The timeout for the statement
22	pub timeout: Expr,
23}
24
25impl ToSql for RelateStatement {
26	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
27		write_sql!(f, fmt, "RELATE");
28		if self.only {
29			write_sql!(f, fmt, " ONLY");
30		}
31		if self.or_update {
32			write_sql!(f, fmt, " OR UPDATE");
33		}
34		write_sql!(f, fmt, " ");
35
36		// Only array's, params, and record-id's that are not a range can be expressed without
37		// surrounding parens
38		if matches!(
39			self.from,
40			Expr::Literal(
41				Literal::Array(_)
42					| Literal::RecordId(RecordIdLit {
43						key: RecordIdKeyLit::Number(_)
44							| RecordIdKeyLit::String(_)
45							| RecordIdKeyLit::Generate(_)
46							| RecordIdKeyLit::Array(_)
47							| RecordIdKeyLit::Object(_)
48							| RecordIdKeyLit::Uuid(_),
49						..
50					})
51			) | Expr::Param(_)
52		) {
53			self.from.fmt_sql(f, fmt);
54		} else {
55			write_sql!(f, fmt, "(");
56			self.from.fmt_sql(f, fmt);
57			write_sql!(f, fmt, ")");
58		}
59		write_sql!(f, fmt, " -> ");
60
61		if matches!(self.through, Expr::Param(_) | Expr::Table(_)) {
62			self.through.fmt_sql(f, fmt);
63		} else {
64			write_sql!(f, fmt, "(");
65			self.through.fmt_sql(f, fmt);
66			write_sql!(f, fmt, ")");
67		}
68
69		write_sql!(f, fmt, " -> ");
70
71		// Only array's, params, and record-id's that are not a range can be expressed without
72		// surrounding parens
73		if matches!(
74			self.to,
75			Expr::Literal(
76				Literal::Array(_)
77					| Literal::RecordId(RecordIdLit {
78						key: RecordIdKeyLit::Number(_)
79							| RecordIdKeyLit::String(_)
80							| RecordIdKeyLit::Generate(_)
81							| RecordIdKeyLit::Array(_)
82							| RecordIdKeyLit::Object(_)
83							| RecordIdKeyLit::Uuid(_),
84						..
85					})
86			) | Expr::Param(_)
87		) {
88			self.to.fmt_sql(f, fmt);
89		} else {
90			write_sql!(f, fmt, "(");
91			self.to.fmt_sql(f, fmt);
92			write_sql!(f, fmt, ")");
93		}
94
95		if let Some(ref v) = self.data {
96			write_sql!(f, fmt, " {v}");
97		}
98		if let Some(ref v) = self.output {
99			write_sql!(f, fmt, " {v}");
100		}
101		if !matches!(self.timeout, Expr::Literal(Literal::None)) {
102			write_sql!(f, fmt, " TIMEOUT {}", CoverStmts(&self.timeout));
103		}
104	}
105}