use super::role::RoleValidate;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct RoleSchemaLevel {
pub name: String,
pub grants: Vec<String>,
pub schemas: Vec<String>,
}
impl RoleSchemaLevel {
pub fn to_sql(&self, user: &str) -> String {
let grants = if self.grants.is_empty() || self.grants.contains(&"ALL".to_string()) {
"ALL PRIVILEGES".to_string()
} else {
self.grants.join(", ")
};
let sql = format!(
"GRANT {} ON SCHEMA {} TO {};",
grants,
self.schemas.join(", "),
user
);
sql
}
}
impl RoleValidate for RoleSchemaLevel {
fn validate(&self) -> Result<()> {
if self.name.is_empty() {
return Err(anyhow!("role name is empty"));
}
if self.schemas.is_empty() {
return Err(anyhow!("role schemas is empty"));
}
let valid_grants = vec!["CREATE", "USAGE", "ALL"];
let mut grants = HashSet::new();
for grant in &self.grants {
if !valid_grants.contains(&&grant[..]) {
return Err(anyhow!(
"invalid grant: {}, expected: {:?}",
grant,
valid_grants
));
}
grants.insert(grant.to_string());
}
if self.grants.is_empty() {
return Err(anyhow!("role grants is empty"));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_role_schema_level() {
let role_schema_level = RoleSchemaLevel {
name: "role_schema_level".to_string(),
grants: vec!["CREATE".to_string(), "TEMP".to_string()],
schemas: vec!["schema1".to_string(), "schema2".to_string()],
};
role_schema_level.validate().ok();
let sql = role_schema_level.to_sql("user");
assert_eq!(
sql,
"GRANT CREATE, TEMP ON SCHEMA schema1, schema2 TO user;"
);
}
}