Skip to main content

surql_parser/upstream/sql/
function.rs

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