surrealdb_core/sql/statements/define/
function.rs

1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::iam::{Action, ResourceKind};
6use crate::sql::statements::info::InfoStructure;
7use crate::sql::{
8	fmt::{is_pretty, pretty_indent},
9	Base, Block, Ident, Kind, Object, Permission, Strand, Value,
10};
11use derive::Store;
12use revision::revisioned;
13use serde::{Deserialize, Serialize};
14use std::fmt::{self, Display, Write};
15
16#[revisioned(revision = 2)]
17#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
18#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
19#[non_exhaustive]
20pub struct DefineFunctionStatement {
21	pub name: Ident,
22	pub args: Vec<(Ident, Kind)>,
23	pub block: Block,
24	pub comment: Option<Strand>,
25	pub permissions: Permission,
26	#[revision(start = 2)]
27	pub if_not_exists: bool,
28}
29
30impl DefineFunctionStatement {
31	/// Process this type returning a computed simple Value
32	pub(crate) async fn compute(
33		&self,
34		ctx: &Context<'_>,
35		opt: &Options,
36		_doc: Option<&CursorDoc<'_>>,
37	) -> Result<Value, Error> {
38		// Allowed to run?
39		opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
40		// Claim transaction
41		let mut run = ctx.tx_lock().await;
42		// Clear the cache
43		run.clear_cache();
44		// Check if function already exists
45		if run.get_db_function(opt.ns()?, opt.db()?, &self.name).await.is_ok() {
46			if self.if_not_exists {
47				return Ok(Value::None);
48			} else {
49				return Err(Error::FcAlreadyExists {
50					value: self.name.to_string(),
51				});
52			}
53		}
54		// Process the statement
55		let key = crate::key::database::fc::new(opt.ns()?, opt.db()?, &self.name);
56		run.add_ns(opt.ns()?, opt.strict).await?;
57		run.add_db(opt.ns()?, opt.db()?, opt.strict).await?;
58		run.set(
59			key,
60			DefineFunctionStatement {
61				// Don't persist the "IF NOT EXISTS" clause to schema
62				if_not_exists: false,
63				..self.clone()
64			},
65		)
66		.await?;
67		// Ok all good
68		Ok(Value::None)
69	}
70}
71
72impl fmt::Display for DefineFunctionStatement {
73	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74		write!(f, "DEFINE FUNCTION")?;
75		if self.if_not_exists {
76			write!(f, " IF NOT EXISTS")?
77		}
78		write!(f, " fn::{}(", self.name.0)?;
79		for (i, (name, kind)) in self.args.iter().enumerate() {
80			if i > 0 {
81				f.write_str(", ")?;
82			}
83			write!(f, "${name}: {kind}")?;
84		}
85		f.write_str(") ")?;
86		Display::fmt(&self.block, f)?;
87		if let Some(ref v) = self.comment {
88			write!(f, " COMMENT {v}")?
89		}
90		let _indent = if is_pretty() {
91			Some(pretty_indent())
92		} else {
93			f.write_char(' ')?;
94			None
95		};
96		write!(f, "PERMISSIONS {}", self.permissions)?;
97		Ok(())
98	}
99}
100
101impl InfoStructure for DefineFunctionStatement {
102	fn structure(self) -> Value {
103		let Self {
104			name,
105			args,
106			block,
107			comment,
108			permissions,
109			..
110		} = self;
111		let mut acc = Object::default();
112
113		acc.insert("name".to_string(), name.structure());
114
115		acc.insert(
116			"args".to_string(),
117			Value::Array(
118				args.into_iter()
119					.map(|(n, k)| Value::Array(vec![n.structure(), k.structure()].into()))
120					.collect::<Vec<Value>>()
121					.into(),
122			),
123		);
124
125		acc.insert("block".to_string(), block.structure());
126
127		acc.insert("permissions".to_string(), permissions.structure());
128
129		if let Some(comment) = comment {
130			acc.insert("comment".to_string(), comment.into());
131		}
132
133		Value::Object(acc)
134	}
135}