uqa_sql/ast/
role_specification.rs1use serde::{Deserialize, Deserializer, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
12#[serde(tag = "kind", content = "name", rename_all = "snake_case")]
13pub enum RoleSpecification {
14 Named(String),
15 CurrentUser,
16 SessionUser,
17}
18
19impl From<String> for RoleSpecification {
20 fn from(name: String) -> Self {
21 Self::Named(name)
22 }
23}
24
25impl From<&str> for RoleSpecification {
26 fn from(name: &str) -> Self {
27 Self::Named(name.into())
28 }
29}
30
31impl std::fmt::Display for RoleSpecification {
32 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 formatter.write_str(match self {
34 Self::Named(name) => name,
35 Self::CurrentUser => "CURRENT_USER",
36 Self::SessionUser => "SESSION_USER",
37 })
38 }
39}
40
41impl<'de> Deserialize<'de> for RoleSpecification {
42 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
43 #[derive(Deserialize)]
44 #[serde(
45 tag = "kind",
46 content = "name",
47 rename_all = "snake_case",
48 deny_unknown_fields
49 )]
50 enum Tagged {
51 Named(String),
52 CurrentUser,
53 SessionUser,
54 }
55 #[derive(Deserialize)]
56 #[serde(untagged)]
57 enum Stored {
58 Tagged(Tagged),
59 Legacy(String),
60 }
61 Ok(match Stored::deserialize(deserializer)? {
62 Stored::Tagged(Tagged::Named(name)) => Self::Named(name),
63 Stored::Tagged(Tagged::CurrentUser) => Self::CurrentUser,
64 Stored::Tagged(Tagged::SessionUser) => Self::SessionUser,
65 Stored::Legacy(name) => match name.as_str() {
67 "CURRENT_USER" => Self::CurrentUser,
68 "SESSION_USER" => Self::SessionUser,
69 _ => Self::Named(name),
70 },
71 })
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn explicit_names_and_keywords_have_distinct_durable_encodings() {
81 for specification in [
82 RoleSpecification::Named("CURRENT_USER".into()),
83 RoleSpecification::Named("SESSION_USER".into()),
84 RoleSpecification::CurrentUser,
85 RoleSpecification::SessionUser,
86 ] {
87 let stored = serde_json::to_string(&specification).unwrap();
88 assert!(stored.starts_with('{'));
89 assert_eq!(
90 serde_json::from_str::<RoleSpecification>(&stored).unwrap(),
91 specification
92 );
93 }
94 }
95
96 #[test]
97 fn legacy_role_specifications_preserve_their_previous_keyword_meaning() {
98 for (legacy, expected) in [
99 ("CURRENT_USER", RoleSpecification::CurrentUser),
100 ("SESSION_USER", RoleSpecification::SessionUser),
101 ("reader", RoleSpecification::Named("reader".into())),
102 ] {
103 let json = serde_json::to_string(legacy).unwrap();
104 assert_eq!(
105 serde_json::from_str::<RoleSpecification>(&json).unwrap(),
106 expected
107 );
108 }
109 }
110}