surrealdb_core/sql/statements/
relate.rs1use crate::ctx::{Context, MutableContext};
2use crate::dbs::{Iterable, Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::idx::planner::RecordStrategy;
6use crate::sql::{Data, Output, Timeout, Value};
7
8use reblessive::tree::Stk;
9use revision::revisioned;
10use serde::{Deserialize, Serialize};
11use std::fmt;
12
13#[revisioned(revision = 2)]
14#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16#[non_exhaustive]
17pub struct RelateStatement {
18 #[revision(start = 2)]
19 pub only: bool,
20 pub kind: Value,
21 pub from: Value,
22 pub with: Value,
23 pub uniq: bool,
24 pub data: Option<Data>,
25 pub output: Option<Output>,
26 pub timeout: Option<Timeout>,
27 pub parallel: bool,
28}
29
30impl RelateStatement {
31 pub(crate) fn writeable(&self) -> bool {
33 true
34 }
35 pub(crate) async fn compute(
37 &self,
38 stk: &mut Stk,
39 ctx: &Context,
40 opt: &Options,
41 doc: Option<&CursorDoc>,
42 ) -> Result<Value, Error> {
43 opt.valid_for_db()?;
45 let mut i = Iterator::new();
47 let opt = &opt.new_with_futures(false);
49 let ctx = match self.timeout.as_ref() {
51 Some(timeout) => {
52 let mut ctx = MutableContext::new(ctx);
53 ctx.add_timeout(*timeout.0)?;
54 ctx.freeze()
55 }
56 None => ctx.clone(),
57 };
58 let from = {
60 let mut out = Vec::new();
61 match self.from.compute(stk, &ctx, opt, doc).await? {
62 Value::Thing(v) => out.push(v),
63 Value::Array(v) => {
64 for v in v {
65 match v {
66 Value::Thing(v) => out.push(v),
67 Value::Object(v) => match v.rid() {
68 Some(v) => out.push(v),
69 _ => {
70 return Err(Error::RelateStatementIn {
71 value: v.to_string(),
72 })
73 }
74 },
75 v => {
76 return Err(Error::RelateStatementIn {
77 value: v.to_string(),
78 })
79 }
80 }
81 }
82 }
83 Value::Object(v) => match v.rid() {
84 Some(v) => out.push(v),
85 None => {
86 return Err(Error::RelateStatementIn {
87 value: v.to_string(),
88 })
89 }
90 },
91 v => {
92 return Err(Error::RelateStatementIn {
93 value: v.to_string(),
94 })
95 }
96 };
97 out
99 };
100 let with = {
102 let mut out = Vec::new();
103 match self.with.compute(stk, &ctx, opt, doc).await? {
104 Value::Thing(v) => out.push(v),
105 Value::Array(v) => {
106 for v in v {
107 match v {
108 Value::Thing(v) => out.push(v),
109 Value::Object(v) => match v.rid() {
110 Some(v) => out.push(v),
111 None => {
112 return Err(Error::RelateStatementId {
113 value: v.to_string(),
114 })
115 }
116 },
117 v => {
118 return Err(Error::RelateStatementId {
119 value: v.to_string(),
120 })
121 }
122 }
123 }
124 }
125 Value::Object(v) => match v.rid() {
126 Some(v) => out.push(v),
127 None => {
128 return Err(Error::RelateStatementId {
129 value: v.to_string(),
130 })
131 }
132 },
133 v => {
134 return Err(Error::RelateStatementId {
135 value: v.to_string(),
136 })
137 }
138 };
139 out
140 };
141 for f in from.iter() {
143 for w in with.iter() {
144 let f = f.clone();
145 let w = w.clone();
146 match &self.kind.compute(stk, &ctx, opt, doc).await? {
147 Value::Thing(id) => i.ingest(Iterable::Relatable(f, id.to_owned(), w, None)),
149 Value::Table(tb) => match &self.data {
151 Some(data) => {
153 let id = match data.rid(stk, &ctx, opt).await? {
154 Some(id) => id.generate(tb, false)?,
155 None => tb.generate(),
156 };
157 i.ingest(Iterable::Relatable(f, id, w, None))
158 }
159 None => i.ingest(Iterable::Relatable(f, tb.generate(), w, None)),
161 },
162 v => {
164 return Err(Error::RelateStatementOut {
165 value: v.to_string(),
166 })
167 }
168 };
169 }
170 }
171 let stm = Statement::from(self);
173 let res = i.output(stk, &ctx, opt, &stm, RecordStrategy::KeysAndValues).await?;
175 if ctx.is_timedout() {
177 return Err(Error::QueryTimedout);
178 }
179 match res {
181 Value::Array(mut a) if self.only => match a.len() {
183 1 => Ok(a.remove(0)),
185 _ => Err(Error::SingleOnlyOutput),
187 },
188 v => Ok(v),
190 }
191 }
192}
193
194impl fmt::Display for RelateStatement {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 write!(f, "RELATE")?;
197 if self.only {
198 f.write_str(" ONLY")?
199 }
200 write!(f, " {} -> {} -> {}", self.from, self.kind, self.with)?;
201 if self.uniq {
202 f.write_str(" UNIQUE")?
203 }
204 if let Some(ref v) = self.data {
205 write!(f, " {v}")?
206 }
207 if let Some(ref v) = self.output {
208 write!(f, " {v}")?
209 }
210 if let Some(ref v) = self.timeout {
211 write!(f, " {v}")?
212 }
213 if self.parallel {
214 f.write_str(" PARALLEL")?
215 }
216 Ok(())
217 }
218}