surrealdb/sql/
param.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::{
	ctx::Context,
	dbs::{Options, Transaction},
	doc::CursorDoc,
	err::Error,
	iam::Action,
	sql::{ident::Ident, value::Value, Permission},
};
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref, str};

pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Param";

#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
#[serde(rename = "$surrealdb::private::sql::Param")]
#[revisioned(revision = 1)]
pub struct Param(pub Ident);

impl From<Ident> for Param {
	fn from(v: Ident) -> Self {
		Self(v)
	}
}

impl From<String> for Param {
	fn from(v: String) -> Self {
		Self(v.into())
	}
}

impl From<&str> for Param {
	fn from(v: &str) -> Self {
		Self(v.into())
	}
}

impl Deref for Param {
	type Target = Ident;
	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl Param {
	/// Process this type returning a computed simple Value
	pub(crate) async fn compute(
		&self,
		ctx: &Context<'_>,
		opt: &Options,
		txn: &Transaction,
		doc: Option<&CursorDoc<'_>>,
	) -> Result<Value, Error> {
		// Find the variable by name
		match self.as_str() {
			// This is a special param
			"this" | "self" => match doc {
				// The base document exists
				Some(v) => v.doc.compute(ctx, opt, txn, doc).await,
				// The base document does not exist
				None => Ok(Value::None),
			},
			// This is a normal param
			v => match ctx.value(v) {
				// The param has been set locally
				Some(v) => v.compute(ctx, opt, txn, doc).await,
				// The param has not been set locally
				None => {
					let val = {
						// Claim transaction
						let mut run = txn.lock().await;
						// Get the param definition
						run.get_and_cache_db_param(opt.ns(), opt.db(), v).await
					};
					// Check if the param has been set globally
					match val {
						// The param has been set globally
						Ok(val) => {
							// Check permissions
							if opt.check_perms(Action::View) {
								match &val.permissions {
									Permission::Full => (),
									Permission::None => {
										return Err(Error::ParamPermissions {
											name: v.to_owned(),
										})
									}
									Permission::Specific(e) => {
										// Disable permissions
										let opt = &opt.new_with_perms(false);
										// Process the PERMISSION clause
										if !e.compute(ctx, opt, txn, doc).await?.is_truthy() {
											return Err(Error::ParamPermissions {
												name: v.to_owned(),
											});
										}
									}
								}
							}
							// Return the value
							Ok(val.value.to_owned())
						}
						// The param has not been set globally
						Err(_) => Ok(Value::None),
					}
				}
			},
		}
	}
}

impl fmt::Display for Param {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "${}", &self.0)
	}
}