use serde::{Deserialize, Serialize};
use crate::identifier::Identifier;
use crate::ir::difference::Difference;
use crate::ir::eq::{Equiv, field_difference};
use crate::ir::grant::Grant;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DefaultPrivilegeRule {
pub target_role: Identifier,
pub schema: Option<Identifier>,
pub object_type: DefaultPrivObjectType,
pub grants: Vec<Grant>,
}
impl Equiv for DefaultPrivilegeRule {
fn differences(&self, other: &Self) -> Vec<Difference> {
let Self {
target_role: _,
schema: _,
object_type: _,
grants: _,
} = self;
let mut out = Vec::new();
out.extend(field_difference(
"target_role",
&self.target_role,
&other.target_role,
));
out.extend(field_difference(
"schema",
&format!("{:?}", self.schema),
&format!("{:?}", other.schema),
));
out.extend(field_difference(
"object_type",
&format!("{:?}", self.object_type),
&format!("{:?}", other.object_type),
));
out.extend(field_difference(
"grants",
&format!("{:?}", self.grants),
&format!("{:?}", other.grants),
));
out
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DefaultPrivObjectType {
Tables,
Sequences,
Functions,
Types,
Schemas,
}
impl DefaultPrivObjectType {
#[must_use]
pub const fn pg_char(self) -> char {
match self {
Self::Tables => 'r',
Self::Sequences => 'S',
Self::Functions => 'f',
Self::Types => 'T',
Self::Schemas => 'n',
}
}
#[must_use]
pub const fn from_pg_char(c: char) -> Option<Self> {
Some(match c {
'r' => Self::Tables,
'S' => Self::Sequences,
'f' => Self::Functions,
'T' => Self::Types,
'n' => Self::Schemas,
_ => return None,
})
}
#[must_use]
pub const fn sql_keyword(self) -> &'static str {
match self {
Self::Tables => "TABLES",
Self::Sequences => "SEQUENCES",
Self::Functions => "FUNCTIONS",
Self::Types => "TYPES",
Self::Schemas => "SCHEMAS",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::eq::Equiv;
fn id(s: &str) -> Identifier {
Identifier::from_unquoted(s).unwrap()
}
fn base() -> DefaultPrivilegeRule {
DefaultPrivilegeRule {
target_role: id("app_owner"),
schema: None,
object_type: DefaultPrivObjectType::Tables,
grants: Vec::new(),
}
}
#[test]
fn equal_rules_have_no_diff() {
assert!(base().canonical_eq(&base()));
}
#[test]
fn object_type_change_diffs() {
let mut b = base();
b.object_type = DefaultPrivObjectType::Sequences;
let d = base().differences(&b);
assert_eq!(d.len(), 1);
assert_eq!(d[0].path, "object_type");
}
#[test]
fn pg_char_roundtrips() {
for kind in [
DefaultPrivObjectType::Tables,
DefaultPrivObjectType::Sequences,
DefaultPrivObjectType::Functions,
DefaultPrivObjectType::Types,
DefaultPrivObjectType::Schemas,
] {
assert_eq!(
DefaultPrivObjectType::from_pg_char(kind.pg_char()),
Some(kind)
);
}
}
#[test]
fn from_pg_char_rejects_unknown() {
assert_eq!(DefaultPrivObjectType::from_pg_char('q'), None);
}
}