surrealdb_core/sql/statements/define/
param.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::fmt::{is_pretty, pretty_indent};
7use crate::sql::statements::info::InfoStructure;
8use crate::sql::{Base, Ident, Permission, Strand, Value};
9use derive::Store;
10use reblessive::tree::Stk;
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::fmt::{self, Display, Write};
14
15#[revisioned(revision = 3)]
16#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18#[non_exhaustive]
19pub struct DefineParamStatement {
20	pub name: Ident,
21	pub value: Value,
22	pub comment: Option<Strand>,
23	pub permissions: Permission,
24	#[revision(start = 2)]
25	pub if_not_exists: bool,
26	#[revision(start = 3)]
27	pub overwrite: bool,
28}
29
30impl DefineParamStatement {
31	/// Process this type returning a computed simple Value
32	pub(crate) async fn compute(
33		&self,
34		stk: &mut Stk,
35		ctx: &Context,
36		opt: &Options,
37		doc: Option<&CursorDoc>,
38	) -> Result<Value, Error> {
39		// Allowed to run?
40		opt.is_allowed(Action::Edit, ResourceKind::Parameter, &Base::Db)?;
41		// Fetch the transaction
42		let txn = ctx.tx();
43		// Check if the definition exists
44		if txn.get_db_param(opt.ns()?, opt.db()?, &self.name).await.is_ok() {
45			if self.if_not_exists {
46				return Ok(Value::None);
47			} else if !self.overwrite {
48				return Err(Error::PaAlreadyExists {
49					value: self.name.to_string(),
50				});
51			}
52		}
53		// Process the statement
54		let key = crate::key::database::pa::new(opt.ns()?, opt.db()?, &self.name);
55		txn.get_or_add_ns(opt.ns()?, opt.strict).await?;
56		txn.get_or_add_db(opt.ns()?, opt.db()?, opt.strict).await?;
57		txn.set(
58			key,
59			DefineParamStatement {
60				// Compute the param
61				value: self.value.compute(stk, ctx, opt, doc).await?,
62				// Don't persist the `IF NOT EXISTS` clause to schema
63				if_not_exists: false,
64				overwrite: false,
65				..self.clone()
66			},
67			None,
68		)
69		.await?;
70		// Clear the cache
71		txn.clear();
72		// Ok all good
73		Ok(Value::None)
74	}
75}
76
77impl Display for DefineParamStatement {
78	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79		write!(f, "DEFINE PARAM")?;
80		if self.if_not_exists {
81			write!(f, " IF NOT EXISTS")?
82		}
83		if self.overwrite {
84			write!(f, " OVERWRITE")?
85		}
86		write!(f, " ${} VALUE {}", self.name, self.value)?;
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 DefineParamStatement {
102	fn structure(self) -> Value {
103		Value::from(map! {
104			"name".to_string() => self.name.structure(),
105			"value".to_string() => self.value.structure(),
106			"permissions".to_string() => self.permissions.structure(),
107			"comment".to_string(), if let Some(v) = self.comment => v.into(),
108		})
109	}
110}