surrealdb_core/sql/
graph.rs

1use crate::sql::cond::Cond;
2use crate::sql::dir::Dir;
3use crate::sql::field::Fields;
4use crate::sql::group::Groups;
5use crate::sql::idiom::Idiom;
6use crate::sql::limit::Limit;
7use crate::sql::order::{OldOrders, Order, OrderList, Ordering};
8use crate::sql::split::Splits;
9use crate::sql::start::Start;
10use crate::sql::table::Tables;
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::fmt::{self, Display, Formatter, Write};
14
15#[revisioned(revision = 3)]
16#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18#[non_exhaustive]
19pub struct Graph {
20	pub dir: Dir,
21	#[revision(end = 3, convert_fn = "convert_old_expr")]
22	pub old_expr: Fields,
23	#[revision(start = 3)]
24	pub expr: Option<Fields>,
25	pub what: Tables,
26	pub cond: Option<Cond>,
27	pub split: Option<Splits>,
28	pub group: Option<Groups>,
29	#[revision(end = 2, convert_fn = "convert_old_orders")]
30	pub old_order: Option<OldOrders>,
31	#[revision(start = 2)]
32	pub order: Option<Ordering>,
33	pub limit: Option<Limit>,
34	pub start: Option<Start>,
35	pub alias: Option<Idiom>,
36}
37
38impl Graph {
39	fn convert_old_orders(
40		&mut self,
41		_rev: u16,
42		old_value: Option<OldOrders>,
43	) -> Result<(), revision::Error> {
44		let Some(x) = old_value else {
45			// nothing to do.
46			return Ok(());
47		};
48
49		if x.0.iter().any(|x| x.random) {
50			self.order = Some(Ordering::Random);
51			return Ok(());
52		}
53
54		let new_ord =
55			x.0.into_iter()
56				.map(|x| Order {
57					value: x.order,
58					collate: x.collate,
59					numeric: x.numeric,
60					direction: x.direction,
61				})
62				.collect();
63
64		self.order = Some(Ordering::Order(OrderList(new_ord)));
65
66		Ok(())
67	}
68
69	fn convert_old_expr(&mut self, _rev: u16, _old_value: Fields) -> Result<(), revision::Error> {
70		// Before this change, users would not have been able to set the value of the `expr` field, it's always `Fields(vec![Field::All], false)`.
71		// None is the new default value, mimmicking that behaviour.
72		self.expr = None;
73		Ok(())
74	}
75
76	/// Convert the graph edge to a raw String
77	pub fn to_raw(&self) -> String {
78		self.to_string()
79	}
80}
81
82impl Display for Graph {
83	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
84		if self.what.0.len() <= 1 && self.cond.is_none() && self.alias.is_none() {
85			Display::fmt(&self.dir, f)?;
86			match self.what.len() {
87				0 => f.write_char('?'),
88				_ => Display::fmt(&self.what, f),
89			}
90		} else {
91			write!(f, "{}(", self.dir)?;
92			match self.what.len() {
93				0 => f.write_char('?'),
94				_ => Display::fmt(&self.what, f),
95			}?;
96			if let Some(ref v) = self.cond {
97				write!(f, " {v}")?
98			}
99			if let Some(ref v) = self.split {
100				write!(f, " {v}")?
101			}
102			if let Some(ref v) = self.group {
103				write!(f, " {v}")?
104			}
105			if let Some(ref v) = self.order {
106				write!(f, " {v}")?
107			}
108			if let Some(ref v) = self.limit {
109				write!(f, " {v}")?
110			}
111			if let Some(ref v) = self.start {
112				write!(f, " {v}")?
113			}
114			if let Some(ref v) = self.alias {
115				write!(f, " AS {v}")?
116			}
117			f.write_char(')')
118		}
119	}
120}