Skip to main content

surrealdb_sql/
function.rs

1use common::fmt::{EscapeIdent, EscapeKwFreeIdent, Fmt};
2use surrealdb_types::{SqlFormat, ToSql, write_sql};
3
4use crate::{CoverStmts, Expr, Idiom, Model, Script};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum Function {
8	Normal(String),
9	Custom(String),
10	Script(Script),
11	Model(Model),
12	Module(String, Option<String>),
13	Silo {
14		org: String,
15		pkg: String,
16		major: u32,
17		minor: u32,
18		patch: u32,
19		sub: Option<String>,
20	},
21}
22
23impl Function {
24	// we explicitely dont want a display implementation but do need to print a function to a string
25	#[allow(clippy::inherent_to_string)]
26	pub fn to_string(&self) -> String {
27		match self {
28			// Safety: "function" does not contain null bytes"
29			Self::Script(_) => "function".to_owned(),
30			Self::Normal(f) => f.to_owned(),
31			Self::Custom(name) => format!("fn::{name}"),
32			Self::Model(m) => m.to_sql(),
33			Self::Module(m, s) => match s {
34				Some(s) => format!("mod::{m}::{s}"),
35				None => format!("mod::{m}"),
36			},
37			Self::Silo {
38				org,
39				pkg,
40				major,
41				minor,
42				patch,
43				sub,
44			} => match sub {
45				Some(s) => {
46					format!("silo::{org}::{pkg}::<{major}.{minor}.{patch}>::{s}")
47				}
48				None => format!("silo::{org}::{pkg}::<{major}.{minor}.{patch}>"),
49			},
50		}
51	}
52
53	pub fn to_idiom(&self) -> Idiom {
54		Idiom::field(self.to_string())
55	}
56}
57
58#[derive(Clone, Debug, PartialEq, Eq)]
59#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
60pub struct FunctionCall {
61	pub receiver: Function,
62	pub arguments: Vec<Expr>,
63}
64
65impl ToSql for FunctionCall {
66	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
67		match self.receiver {
68			Function::Normal(ref s) => {
69				for (idx, s) in s.split("::").enumerate() {
70					if idx != 0 {
71						f.push_str("::");
72					} else {
73						write_sql!(f, fmt, "{}", EscapeIdent(s));
74						continue;
75					}
76					s.fmt_sql(f, fmt);
77				}
78			}
79			Function::Custom(ref s) => {
80				f.push_str("fn");
81				for s in s.split("::") {
82					f.push_str("::");
83					write_sql!(f, fmt, "{}", EscapeKwFreeIdent(s));
84				}
85			}
86			Function::Script(ref s) => {
87				write_sql!(
88					f,
89					fmt,
90					"function({}) {{{s}}}",
91					Fmt::comma_separated(self.arguments.iter().map(CoverStmts))
92				);
93				return;
94			}
95			Function::Model(ref m) => {
96				write_sql!(f, fmt, "{m}");
97			}
98			Function::Module(ref m, ref s) => {
99				f.push_str("mod::");
100				write_sql!(f, fmt, " {}", EscapeKwFreeIdent(m));
101				if let Some(s) = s {
102					for segment in s.split("::") {
103						write_sql!(f, fmt, "::{}", EscapeKwFreeIdent(segment));
104					}
105				}
106			}
107			Function::Silo {
108				ref org,
109				ref pkg,
110				ref major,
111				ref minor,
112				ref patch,
113				ref sub,
114			} => {
115				write_sql!(
116					f,
117					fmt,
118					"silo::{}::{}::<{major}.{minor}.{patch}>",
119					EscapeKwFreeIdent(org),
120					EscapeKwFreeIdent(pkg),
121				);
122				if let Some(s) = sub {
123					for segment in s.split("::") {
124						write_sql!(f, fmt, "::{}", EscapeKwFreeIdent(segment));
125					}
126				}
127			}
128		}
129		write_sql!(f, fmt, "({})", Fmt::comma_separated(self.arguments.iter().map(CoverStmts)))
130	}
131}