uqa_sql/ast/
acl_role_specification.rs1use super::RoleSpecification;
10use serde::{Deserialize, Deserializer, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
13#[serde(tag = "kind", content = "role", rename_all = "snake_case")]
14pub enum AclRoleSpecification {
15 Public,
16 Role(RoleSpecification),
17}
18
19impl From<RoleSpecification> for AclRoleSpecification {
20 fn from(role: RoleSpecification) -> Self {
21 Self::Role(role)
22 }
23}
24
25impl From<String> for AclRoleSpecification {
26 fn from(name: String) -> Self {
27 Self::Role(RoleSpecification::Named(name))
28 }
29}
30
31impl From<&str> for AclRoleSpecification {
32 fn from(name: &str) -> Self {
33 Self::from(name.to_owned())
34 }
35}
36
37impl<'de> Deserialize<'de> for AclRoleSpecification {
38 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
39 #[derive(Deserialize)]
40 #[serde(
41 tag = "kind",
42 content = "role",
43 rename_all = "snake_case",
44 deny_unknown_fields
45 )]
46 enum Tagged {
47 Public,
48 Role(RoleSpecification),
49 }
50 #[derive(Deserialize)]
51 #[serde(untagged)]
52 enum Stored {
53 Tagged(Tagged),
54 Legacy(String),
55 }
56 Ok(match Stored::deserialize(deserializer)? {
57 Stored::Tagged(Tagged::Public) => Self::Public,
58 Stored::Tagged(Tagged::Role(role)) => Self::Role(role),
59 Stored::Legacy(name) => match name.as_str() {
60 "PUBLIC" => Self::Public,
61 "CURRENT_USER" => Self::Role(RoleSpecification::CurrentUser),
62 "SESSION_USER" => Self::Role(RoleSpecification::SessionUser),
63 _ => Self::Role(RoleSpecification::Named(name)),
64 },
65 })
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn quoted_role_names_public_and_session_keywords_remain_distinct() {
75 let specifications = [
76 AclRoleSpecification::Public,
77 AclRoleSpecification::from("PUBLIC"),
78 AclRoleSpecification::from("CURRENT_USER"),
79 AclRoleSpecification::from("SESSION_USER"),
80 AclRoleSpecification::from(RoleSpecification::CurrentUser),
81 AclRoleSpecification::from(RoleSpecification::SessionUser),
82 ];
83 let mut encodings = std::collections::BTreeSet::new();
84 for specification in specifications {
85 let json = serde_json::to_string(&specification).unwrap();
86 assert!(encodings.insert(json.clone()));
87 assert_eq!(
88 serde_json::from_str::<AclRoleSpecification>(&json).unwrap(),
89 specification
90 );
91 }
92 }
93
94 #[test]
95 fn legacy_object_grant_statements_keep_their_previous_keyword_meanings() {
96 for (name, expected) in [
97 ("PUBLIC", AclRoleSpecification::Public),
98 ("CURRENT_USER", RoleSpecification::CurrentUser.into()),
99 ("SESSION_USER", RoleSpecification::SessionUser.into()),
100 ("reader", AclRoleSpecification::from("reader")),
101 ] {
102 let json = serde_json::to_string(name).unwrap();
103 assert_eq!(
104 serde_json::from_str::<AclRoleSpecification>(&json).unwrap(),
105 expected
106 );
107 }
108 for json in [
109 r#"{"kind":"unknown","role":"PUBLIC"}"#,
110 r#"{"kind":"role"}"#,
111 r#"{"kind":"public","role":"reader"}"#,
112 r#"{"role":"PUBLIC"}"#,
113 r#"{"kind":"role","role":{"kind":"named","name":"PUBLIC","extra":true}}"#,
114 r#"{"kind":"role","role":{"kind":"current_user","name":"PUBLIC"}}"#,
115 "null",
116 ] {
117 assert!(
118 serde_json::from_str::<AclRoleSpecification>(json).is_err(),
119 "{json}"
120 );
121 }
122 }
123}