surrealdb_core/sql/statements/
relate.rsuse crate::ctx::{Context, MutableContext};
use crate::dbs::{Iterable, Iterator, Options, Statement};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::{Data, Output, Timeout, Value};
use derive::Store;
use reblessive::tree::Stk;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::fmt;
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct RelateStatement {
#[revision(start = 2)]
pub only: bool,
pub kind: Value,
pub from: Value,
pub with: Value,
pub uniq: bool,
pub data: Option<Data>,
pub output: Option<Output>,
pub timeout: Option<Timeout>,
pub parallel: bool,
}
impl RelateStatement {
pub(crate) fn writeable(&self) -> bool {
true
}
pub(crate) async fn compute(
&self,
stk: &mut Stk,
ctx: &Context,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<Value, Error> {
opt.valid_for_db()?;
let mut i = Iterator::new();
let opt = &opt.new_with_futures(false);
let ctx = match self.timeout.as_ref() {
Some(timeout) => {
let mut ctx = MutableContext::new(ctx);
ctx.add_timeout(*timeout.0)?;
ctx.freeze()
}
None => ctx.clone(),
};
let from = {
let mut out = Vec::new();
match self.from.compute(stk, &ctx, opt, doc).await? {
Value::Thing(v) => out.push(v),
Value::Array(v) => {
for v in v {
match v {
Value::Thing(v) => out.push(v),
Value::Object(v) => match v.rid() {
Some(v) => out.push(v),
_ => {
return Err(Error::RelateStatementIn {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatementIn {
value: v.to_string(),
})
}
}
}
}
Value::Object(v) => match v.rid() {
Some(v) => out.push(v),
None => {
return Err(Error::RelateStatementIn {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatementIn {
value: v.to_string(),
})
}
};
out
};
let with = {
let mut out = Vec::new();
match self.with.compute(stk, &ctx, opt, doc).await? {
Value::Thing(v) => out.push(v),
Value::Array(v) => {
for v in v {
match v {
Value::Thing(v) => out.push(v),
Value::Object(v) => match v.rid() {
Some(v) => out.push(v),
None => {
return Err(Error::RelateStatementId {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatementId {
value: v.to_string(),
})
}
}
}
}
Value::Object(v) => match v.rid() {
Some(v) => out.push(v),
None => {
return Err(Error::RelateStatementId {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatementId {
value: v.to_string(),
})
}
};
out
};
for f in from.iter() {
for w in with.iter() {
let f = f.clone();
let w = w.clone();
match &self.kind.compute(stk, &ctx, opt, doc).await? {
Value::Thing(id) => i.ingest(Iterable::Relatable(f, id.to_owned(), w, None)),
Value::Table(tb) => match &self.data {
Some(data) => {
let id = match data.rid(stk, &ctx, opt).await? {
Some(id) => id.generate(tb, false)?,
None => tb.generate(),
};
i.ingest(Iterable::Relatable(f, id, w, None))
}
None => i.ingest(Iterable::Relatable(f, tb.generate(), w, None)),
},
v => {
return Err(Error::RelateStatementOut {
value: v.to_string(),
})
}
};
}
}
let stm = Statement::from(self);
let res = i.output(stk, &ctx, opt, &stm).await?;
if ctx.is_timedout() {
return Err(Error::QueryTimedout);
}
match res {
Value::Array(mut a) if self.only => match a.len() {
1 => Ok(a.remove(0)),
_ => Err(Error::SingleOnlyOutput),
},
v => Ok(v),
}
}
}
impl fmt::Display for RelateStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RELATE")?;
if self.only {
f.write_str(" ONLY")?
}
write!(f, " {} -> {} -> {}", self.from, self.kind, self.with)?;
if self.uniq {
f.write_str(" UNIQUE")?
}
if let Some(ref v) = self.data {
write!(f, " {v}")?
}
if let Some(ref v) = self.output {
write!(f, " {v}")?
}
if let Some(ref v) = self.timeout {
write!(f, " {v}")?
}
if self.parallel {
f.write_str(" PARALLEL")?
}
Ok(())
}
}