Skip to main content

surrealdb_expr/expr/
permission.rs

1//! Permission guards attached to schema objects.
2//!
3//! `Permission` is the compiled form of a permission clause: `None`, `Full`,
4//! or a guard expression evaluated per row. `Permissions` groups the four
5//! CRUD clauses. The stored (text) twins live in the catalog schema layer.
6
7use surrealdb_types::ToSql;
8
9use crate::expr::Expr;
10use crate::expr::statements::info::InfoStructure;
11use crate::sql;
12use crate::val::Value;
13
14/// Runtime form of [`StoredPermission`]: the guard expression parsed.
15#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
16pub enum Permission {
17	None,
18	#[default]
19	Full,
20	Specific(Expr),
21}
22
23impl Permission {
24	/// Lowers to the sql-side permission for embedding in a
25	/// `sql::Define*Statement` at the INFO/export rendering boundary.
26	pub fn to_sql_permission(&self) -> sql::Permission {
27		match self {
28			Permission::None => sql::Permission::None,
29			Permission::Full => sql::Permission::Full,
30			Permission::Specific(e) => sql::Permission::Specific(e.clone().into()),
31		}
32	}
33}
34
35impl InfoStructure for Permission {
36	fn structure(self) -> Value {
37		match self {
38			Permission::None => Value::Bool(false),
39			Permission::Full => Value::Bool(true),
40			Permission::Specific(e) => Value::from(e.to_stored_sql()),
41		}
42	}
43}
44
45/// Renders the guard expression with the statement-covering parenthesization
46/// its canonical stored text carries (`Expr::to_stored_sql`), so the output is
47/// byte-identical to the stored form's splice.
48impl ToSql for Permission {
49	fn fmt_sql(&self, f: &mut String, _fmt: surrealdb_types::SqlFormat) {
50		match self {
51			Self::None => f.push_str("NONE"),
52			Self::Full => f.push_str("FULL"),
53			Self::Specific(e) => {
54				f.push_str("WHERE ");
55				f.push_str(&e.to_stored_sql());
56			}
57		}
58	}
59}
60
61/// Runtime form of [`StoredPermissions`].
62#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
63pub struct Permissions {
64	pub select: Permission,
65	pub create: Permission,
66	pub update: Permission,
67	pub delete: Permission,
68}
69
70impl Permissions {
71	/// Lowers to the sql-side permissions for embedding in a
72	/// `sql::Define*Statement` at the INFO/export rendering boundary.
73	pub fn to_sql_permissions(&self) -> sql::Permissions {
74		sql::Permissions {
75			select: self.select.to_sql_permission(),
76			create: self.create.to_sql_permission(),
77			update: self.update.to_sql_permission(),
78			delete: self.delete.to_sql_permission(),
79		}
80	}
81}
82
83impl InfoStructure for Permissions {
84	fn structure(self) -> Value {
85		Value::from(map! {
86			"select" => self.select.structure(),
87			"create" => self.create.structure(),
88			"update" => self.update.structure(),
89			"delete" => self.delete.structure(),
90		})
91	}
92}
93
94impl ToSql for Permissions {
95	fn fmt_sql(&self, f: &mut String, fmt: surrealdb_types::SqlFormat) {
96		// One renderer, not two: see `FieldDefinition::to_sql_definition`.
97		self.to_sql_permissions().fmt_sql(f, fmt)
98	}
99}
100
101impl Permission {
102	/// See [`StoredPermission::is_none`]; same predicate on the compiled form.
103	pub fn is_none(&self) -> bool {
104		matches!(self, Self::None)
105	}
106
107	/// See [`StoredPermission::is_specific`]; same predicate on the compiled
108	/// form.
109	pub fn is_specific(&self) -> bool {
110		matches!(self, Self::Specific(_))
111	}
112}