surrealdb_core/sql/statements/define/
function.rs1use 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 pub(crate) async fn compute(
33 &self,
34 ctx: &Context<'_>,
35 opt: &Options,
36 _doc: Option<&CursorDoc<'_>>,
37 ) -> Result<Value, Error> {
38 opt.is_allowed(Action::Edit, ResourceKind::Function, &Base::Db)?;
40 let mut run = ctx.tx_lock().await;
42 run.clear_cache();
44 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 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 if_not_exists: false,
63 ..self.clone()
64 },
65 )
66 .await?;
67 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}