surrealdb_core/sql/
permission.rs

1use crate::sql::fmt::is_pretty;
2use crate::sql::fmt::pretty_indent;
3use crate::sql::fmt::pretty_sequence_item;
4use crate::sql::statements::info::InfoStructure;
5use crate::sql::Value;
6use revision::revisioned;
7use serde::{Deserialize, Serialize};
8use std::fmt::Write;
9use std::fmt::{self, Display, Formatter};
10use std::str;
11
12#[revisioned(revision = 1)]
13#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15#[non_exhaustive]
16pub struct Permissions {
17	pub select: Permission,
18	pub create: Permission,
19	pub update: Permission,
20	pub delete: Permission,
21}
22
23impl Permissions {
24	pub fn none() -> Self {
25		Permissions {
26			select: Permission::None,
27			create: Permission::None,
28			update: Permission::None,
29			delete: Permission::None,
30		}
31	}
32
33	pub fn full() -> Self {
34		Permissions {
35			select: Permission::Full,
36			create: Permission::Full,
37			update: Permission::Full,
38			delete: Permission::Full,
39		}
40	}
41
42	pub fn is_none(&self) -> bool {
43		self.select == Permission::None
44			&& self.create == Permission::None
45			&& self.update == Permission::None
46			&& self.delete == Permission::None
47	}
48
49	pub fn is_full(&self) -> bool {
50		self.select == Permission::Full
51			&& self.create == Permission::Full
52			&& self.update == Permission::Full
53			&& self.delete == Permission::Full
54	}
55}
56
57impl Display for Permissions {
58	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59		write!(f, "PERMISSIONS")?;
60		if self.is_none() {
61			return write!(f, " NONE");
62		}
63		if self.is_full() {
64			return write!(f, " FULL");
65		}
66		let mut lines = Vec::<(Vec<PermissionKind>, &Permission)>::new();
67		for (c, permission) in [
68			PermissionKind::Select,
69			PermissionKind::Create,
70			PermissionKind::Update,
71			PermissionKind::Delete,
72		]
73		.into_iter()
74		.zip([&self.select, &self.create, &self.update, &self.delete])
75		{
76			// Alternate permissions display implementation ignores delete permission
77			// This display is used to show field permissions, where delete has no effect
78			// Displaying the permission could mislead users into thinking it has an effect
79			// Additionally, including the permission will cause a parsing error in 3.0.0
80			if f.alternate() && matches!(c, PermissionKind::Delete) {
81				continue;
82			}
83
84			if let Some((existing, _)) = lines.iter_mut().find(|(_, p)| *p == permission) {
85				existing.push(c);
86			} else {
87				lines.push((vec![c], permission));
88			}
89		}
90		let indent = if is_pretty() {
91			Some(pretty_indent())
92		} else {
93			f.write_char(' ')?;
94			None
95		};
96		for (i, (kinds, permission)) in lines.into_iter().enumerate() {
97			if i > 0 {
98				if is_pretty() {
99					pretty_sequence_item();
100				} else {
101					f.write_str(", ")?;
102				}
103			}
104			write!(f, "FOR ")?;
105			for (i, kind) in kinds.into_iter().enumerate() {
106				if i > 0 {
107					f.write_str(", ")?;
108				}
109				f.write_str(kind.as_str())?;
110			}
111			match permission {
112				Permission::Specific(_) if is_pretty() => {
113					let _indent = pretty_indent();
114					Display::fmt(permission, f)?;
115				}
116				_ => write!(f, " {permission}")?,
117			}
118		}
119		drop(indent);
120		Ok(())
121	}
122}
123
124impl InfoStructure for Permissions {
125	fn structure(self) -> Value {
126		Value::from(map! {
127			"select".to_string() => self.select.structure(),
128			"create".to_string() => self.create.structure(),
129			"update".to_string() => self.update.structure(),
130			// TODO(gguillemas): Do not show this value for fields in 3.0.0.
131			"delete".to_string() => self.delete.structure(),
132		})
133	}
134}
135
136#[derive(Clone, Copy, Eq, PartialEq, Debug)]
137pub(crate) enum PermissionKind {
138	Select,
139	Create,
140	Update,
141	Delete,
142}
143
144impl PermissionKind {
145	fn as_str(&self) -> &str {
146		match self {
147			PermissionKind::Select => "select",
148			PermissionKind::Create => "create",
149			PermissionKind::Update => "update",
150			PermissionKind::Delete => "delete",
151		}
152	}
153}
154
155#[revisioned(revision = 1)]
156#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
157#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
158#[non_exhaustive]
159pub enum Permission {
160	None,
161	#[default]
162	Full,
163	Specific(Value),
164}
165
166impl Permission {
167	pub fn is_none(&self) -> bool {
168		matches!(self, Self::None)
169	}
170
171	pub fn is_full(&self) -> bool {
172		matches!(self, Self::Full)
173	}
174
175	pub fn is_specific(&self) -> bool {
176		matches!(self, Self::Specific(_))
177	}
178}
179
180impl Display for Permission {
181	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
182		match self {
183			Self::None => f.write_str("NONE"),
184			Self::Full => f.write_str("FULL"),
185			Self::Specific(ref v) => write!(f, "WHERE {v}"),
186		}
187	}
188}
189
190impl InfoStructure for Permission {
191	fn structure(self) -> Value {
192		match self {
193			Permission::None => Value::Bool(false),
194			Permission::Full => Value::Bool(true),
195			Permission::Specific(v) => v.to_string().into(),
196		}
197	}
198}