Skip to main content

drizzle_types/postgres/ddl/
privilege.rs

1//! `PostgreSQL` Privilege DDL types
2//!
3//! See: <https://github.com/drizzle-team/drizzle-orm/blob/beta/drizzle-kit/src/dialects/postgres/ddl.ts>
4
5use crate::alloc_prelude::*;
6
7#[cfg(feature = "serde")]
8use crate::serde_helpers::cow_from_string;
9
10// =============================================================================
11// Privilege Type Enum
12// =============================================================================
13
14/// `PostgreSQL` privilege type
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
18pub enum PrivilegeType {
19    /// All privileges
20    #[default]
21    All,
22    /// SELECT privilege
23    Select,
24    /// INSERT privilege
25    Insert,
26    /// UPDATE privilege
27    Update,
28    /// DELETE privilege
29    Delete,
30    /// TRUNCATE privilege
31    Truncate,
32    /// REFERENCES privilege
33    References,
34    /// TRIGGER privilege
35    Trigger,
36}
37
38impl PrivilegeType {
39    /// Get the SQL representation
40    #[must_use]
41    pub const fn as_sql(&self) -> &'static str {
42        match self {
43            Self::All => "ALL",
44            Self::Select => "SELECT",
45            Self::Insert => "INSERT",
46            Self::Update => "UPDATE",
47            Self::Delete => "DELETE",
48            Self::Truncate => "TRUNCATE",
49            Self::References => "REFERENCES",
50            Self::Trigger => "TRIGGER",
51        }
52    }
53
54    /// Parse from SQL string
55    #[must_use]
56    pub fn from_sql(s: &str) -> Option<Self> {
57        match s.to_uppercase().as_str() {
58            "ALL" => Some(Self::All),
59            "SELECT" => Some(Self::Select),
60            "INSERT" => Some(Self::Insert),
61            "UPDATE" => Some(Self::Update),
62            "DELETE" => Some(Self::Delete),
63            "TRUNCATE" => Some(Self::Truncate),
64            "REFERENCES" => Some(Self::References),
65            "TRIGGER" => Some(Self::Trigger),
66            _ => None,
67        }
68    }
69}
70
71// =============================================================================
72// Const-friendly Definition Type
73// =============================================================================
74
75/// Const-friendly privilege definition for compile-time schema definitions.
76#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
77pub struct PrivilegeDef {
78    /// Role granting the privilege
79    pub grantor: &'static str,
80    /// Role receiving the privilege
81    pub grantee: &'static str,
82    /// Schema name
83    pub schema: &'static str,
84    /// Table name
85    pub table: &'static str,
86    /// Privilege type
87    pub privilege_type: PrivilegeType,
88    /// Can the grantee grant this privilege to others?
89    pub is_grantable: bool,
90}
91
92impl PrivilegeDef {
93    /// Create a new privilege definition
94    #[must_use]
95    pub const fn new(
96        schema: &'static str,
97        table: &'static str,
98        grantee: &'static str,
99        privilege_type: PrivilegeType,
100    ) -> Self {
101        Self {
102            grantor: "",
103            grantee,
104            schema,
105            table,
106            privilege_type,
107            is_grantable: false,
108        }
109    }
110
111    /// Set the grantor
112    #[must_use]
113    pub const fn grantor(self, grantor: &'static str) -> Self {
114        Self { grantor, ..self }
115    }
116
117    /// Set `is_grantable` flag
118    #[must_use]
119    pub const fn grantable(self) -> Self {
120        Self {
121            is_grantable: true,
122            ..self
123        }
124    }
125
126    /// Convert to runtime [`Privilege`] type
127    #[must_use]
128    pub const fn into_privilege(self) -> Privilege {
129        Privilege {
130            grantor: Cow::Borrowed(self.grantor),
131            grantee: Cow::Borrowed(self.grantee),
132            schema: Cow::Borrowed(self.schema),
133            table: Cow::Borrowed(self.table),
134            privilege_type: self.privilege_type,
135            is_grantable: self.is_grantable,
136        }
137    }
138}
139
140impl Default for PrivilegeDef {
141    fn default() -> Self {
142        Self::new("public", "", "", PrivilegeType::All)
143    }
144}
145
146// =============================================================================
147// Runtime Type for Serde
148// =============================================================================
149
150/// Runtime privilege entity for serde serialization.
151#[derive(Clone, Debug, PartialEq, Eq)]
152#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
153#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
154pub struct Privilege {
155    /// Role granting the privilege
156    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
157    pub grantor: Cow<'static, str>,
158
159    /// Role receiving the privilege
160    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
161    pub grantee: Cow<'static, str>,
162
163    /// Schema name
164    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
165    pub schema: Cow<'static, str>,
166
167    /// Table name
168    #[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
169    pub table: Cow<'static, str>,
170
171    /// Privilege type
172    #[cfg_attr(feature = "serde", serde(rename = "type"))]
173    pub privilege_type: PrivilegeType,
174
175    /// Can the grantee grant this privilege to others?
176    #[cfg_attr(feature = "serde", serde(default))]
177    pub is_grantable: bool,
178}
179
180impl Privilege {
181    /// Create a new privilege (runtime)
182    #[must_use]
183    pub fn new(
184        schema: impl Into<Cow<'static, str>>,
185        table: impl Into<Cow<'static, str>>,
186        grantee: impl Into<Cow<'static, str>>,
187        privilege_type: PrivilegeType,
188    ) -> Self {
189        Self {
190            grantor: Cow::Borrowed(""),
191            grantee: grantee.into(),
192            schema: schema.into(),
193            table: table.into(),
194            privilege_type,
195            is_grantable: false,
196        }
197    }
198
199    /// Get the schema name
200    #[inline]
201    #[must_use]
202    pub fn schema(&self) -> &str {
203        &self.schema
204    }
205
206    /// Get the table name
207    #[inline]
208    #[must_use]
209    pub fn table(&self) -> &str {
210        &self.table
211    }
212
213    /// Get the grantee
214    #[inline]
215    #[must_use]
216    pub fn grantee(&self) -> &str {
217        &self.grantee
218    }
219
220    /// Get the grantor
221    #[inline]
222    #[must_use]
223    pub fn grantor(&self) -> &str {
224        &self.grantor
225    }
226}
227
228impl Default for Privilege {
229    fn default() -> Self {
230        Self::new("public", "", "", PrivilegeType::All)
231    }
232}
233
234impl From<PrivilegeDef> for Privilege {
235    fn from(def: PrivilegeDef) -> Self {
236        def.into_privilege()
237    }
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    #[test]
245    fn test_const_privilege_def() {
246        const PRIV: PrivilegeDef =
247            PrivilegeDef::new("public", "users", "app_user", PrivilegeType::Select)
248                .grantor("admin")
249                .grantable();
250
251        assert_eq!(PRIV.schema, "public");
252        assert_eq!(PRIV.table, "users");
253        assert_eq!(PRIV.grantee, "app_user");
254        assert_eq!(PRIV.grantor, "admin");
255        assert_eq!(PRIV.privilege_type, PrivilegeType::Select);
256        const {
257            assert!(PRIV.is_grantable);
258        }
259    }
260
261    #[test]
262    fn test_privilege_def_to_privilege() {
263        const DEF: PrivilegeDef =
264            PrivilegeDef::new("public", "users", "reader", PrivilegeType::Select);
265        let priv_ = DEF.into_privilege();
266        assert_eq!(priv_.schema(), "public");
267        assert_eq!(priv_.table(), "users");
268        assert_eq!(priv_.grantee(), "reader");
269    }
270
271    #[test]
272    fn test_privilege_type_sql() {
273        assert_eq!(PrivilegeType::Select.as_sql(), "SELECT");
274        assert_eq!(PrivilegeType::All.as_sql(), "ALL");
275        assert_eq!(PrivilegeType::Truncate.as_sql(), "TRUNCATE");
276    }
277}