surrealdb_sql/
param.rs

1use crate::{
2	ctx::Context,
3	dbs::{Options, Transaction},
4	doc::CursorDoc,
5	err::Error,
6	iam::Action,
7	ident::Ident,
8	value::Value,
9	Permission,
10};
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::{fmt, ops::Deref, str};
14
15pub(crate) const TOKEN: &str = "$surrealdb::private::crate::Param";
16
17#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
18#[serde(rename = "$surrealdb::private::crate::Param")]
19#[revisioned(revision = 1)]
20pub struct Param(pub Ident);
21
22impl From<Ident> for Param {
23	fn from(v: Ident) -> Self {
24		Self(v)
25	}
26}
27
28impl From<String> for Param {
29	fn from(v: String) -> Self {
30		Self(v.into())
31	}
32}
33
34impl From<&str> for Param {
35	fn from(v: &str) -> Self {
36		Self(v.into())
37	}
38}
39
40impl Deref for Param {
41	type Target = Ident;
42	fn deref(&self) -> &Self::Target {
43		&self.0
44	}
45}
46
47impl Param {
48	/// Process this type returning a computed simple Value
49	pub(crate) async fn compute(
50		&self,
51		ctx: &Context<'_>,
52		opt: &Options,
53		txn: &Transaction,
54		doc: Option<&CursorDoc<'_>>,
55	) -> Result<Value, Error> {
56		// Find the variable by name
57		match self.as_str() {
58			// This is a special param
59			"this" | "self" => match doc {
60				// The base document exists
61				Some(v) => v.doc.compute(ctx, opt, txn, doc).await,
62				// The base document does not exist
63				None => Ok(Value::None),
64			},
65			// This is a normal param
66			v => match ctx.value(v) {
67				// The param has been set locally
68				Some(v) => v.compute(ctx, opt, txn, doc).await,
69				// The param has not been set locally
70				None => {
71					let val = {
72						// Claim transaction
73						let mut run = txn.lock().await;
74						// Get the param definition
75						run.get_and_cache_db_param(opt.ns(), opt.db(), v).await
76					};
77					// Check if the param has been set globally
78					match val {
79						// The param has been set globally
80						Ok(val) => {
81							// Check permissions
82							if opt.check_perms(Action::View) {
83								match &val.permissions {
84									Permission::Full => (),
85									Permission::None => {
86										return Err(Error::ParamPermissions {
87											name: v.to_owned(),
88										})
89									}
90									Permission::Specific(e) => {
91										// Disable permissions
92										let opt = &opt.new_with_perms(false);
93										// Process the PERMISSION clause
94										if !e.compute(ctx, opt, txn, doc).await?.is_truthy() {
95											return Err(Error::ParamPermissions {
96												name: v.to_owned(),
97											});
98										}
99									}
100								}
101							}
102							// Return the value
103							Ok(val.value.to_owned())
104						}
105						// The param has not been set globally
106						Err(_) => Ok(Value::None),
107					}
108				}
109			},
110		}
111	}
112}
113
114impl fmt::Display for Param {
115	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116		write!(f, "${}", &self.0)
117	}
118}