surrealdb_core/sql/
closure.rs1use super::{Ident, Kind};
2use crate::ctx::MutableContext;
3use crate::{ctx::Context, dbs::Options, doc::CursorDoc, err::Error, sql::value::Value};
4use reblessive::tree::Stk;
5use revision::revisioned;
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Closure";
10
11#[revisioned(revision = 1)]
12#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
13#[serde(rename = "$surrealdb::private::sql::Closure")]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15#[non_exhaustive]
16pub struct Closure {
17 pub args: Vec<(Ident, Kind)>,
18 pub returns: Option<Kind>,
19 pub body: Value,
20}
21
22impl Closure {
23 pub(crate) async fn compute(
24 &self,
25 stk: &mut Stk,
26 ctx: &Context,
27 opt: &Options,
28 doc: Option<&CursorDoc>,
29 args: Vec<Value>,
30 ) -> Result<Value, Error> {
31 let mut ctx = MutableContext::new_isolated(ctx);
32 for (i, (name, kind)) in self.args.iter().enumerate() {
33 match (kind, args.get(i)) {
34 (Kind::Option(_), None) => continue,
35 (_, None) => {
36 return Err(Error::InvalidArguments {
37 name: "ANONYMOUS".to_string(),
38 message: format!("Expected a value for ${}", name),
39 })
40 }
41 (kind, Some(val)) => {
42 if let Ok(val) = val.to_owned().coerce_to(kind) {
43 ctx.add_value(name.to_string(), val.into());
44 } else {
45 return Err(Error::InvalidArguments {
46 name: "ANONYMOUS".to_string(),
47 message: format!(
48 "Expected a value of type '{kind}' for argument ${}",
49 name
50 ),
51 });
52 }
53 }
54 }
55 }
56
57 let ctx = ctx.freeze();
58 let result = self.body.compute(stk, &ctx, opt, doc).await?;
59 if let Some(returns) = &self.returns {
60 result.coerce_to(returns).map_err(|e| e.function_check_from_coerce("ANONYMOUS"))
61 } else {
62 Ok(result)
63 }
64 }
65}
66
67impl fmt::Display for Closure {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.write_str("|")?;
70 for (i, (name, kind)) in self.args.iter().enumerate() {
71 if i > 0 {
72 f.write_str(", ")?;
73 }
74 write!(f, "${name}: ")?;
75 match kind {
76 k @ Kind::Either(_) => write!(f, "<{}>", k)?,
77 k => write!(f, "{}", k)?,
78 }
79 }
80 f.write_str("|")?;
81 if let Some(returns) = &self.returns {
82 write!(f, " -> {returns}")?;
83 }
84 write!(f, " {}", self.body)
85 }
86}