use crate::alloc_prelude::*;
#[cfg(feature = "serde")]
use crate::serde_helpers::{cow_from_string, cow_option_from_string};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RoleDef {
pub name: &'static str,
pub superuser: Option<bool>,
pub create_db: Option<bool>,
pub create_role: Option<bool>,
pub inherit: Option<bool>,
pub can_login: Option<bool>,
pub replication: Option<bool>,
pub bypass_rls: Option<bool>,
pub conn_limit: Option<i32>,
pub password: Option<&'static str>,
pub valid_until: Option<&'static str>,
}
impl RoleDef {
#[must_use]
pub const fn new(name: &'static str) -> Self {
Self {
name,
superuser: None,
create_db: None,
create_role: None,
inherit: None,
can_login: None,
replication: None,
bypass_rls: None,
conn_limit: None,
password: None,
valid_until: None,
}
}
#[must_use]
pub const fn superuser(self, value: bool) -> Self {
Self {
superuser: Some(value),
..self
}
}
#[must_use]
pub const fn create_db(self, value: bool) -> Self {
Self {
create_db: Some(value),
..self
}
}
#[must_use]
pub const fn create_role(self, value: bool) -> Self {
Self {
create_role: Some(value),
..self
}
}
#[must_use]
pub const fn inherit(self, value: bool) -> Self {
Self {
inherit: Some(value),
..self
}
}
#[must_use]
pub const fn can_login(self, value: bool) -> Self {
Self {
can_login: Some(value),
..self
}
}
#[must_use]
pub const fn replication(self, value: bool) -> Self {
Self {
replication: Some(value),
..self
}
}
#[must_use]
pub const fn bypass_rls(self, value: bool) -> Self {
Self {
bypass_rls: Some(value),
..self
}
}
#[must_use]
pub const fn conn_limit(self, limit: i32) -> Self {
Self {
conn_limit: Some(limit),
..self
}
}
#[must_use]
pub const fn password(self, password: &'static str) -> Self {
Self {
password: Some(password),
..self
}
}
#[must_use]
pub const fn valid_until(self, date: &'static str) -> Self {
Self {
valid_until: Some(date),
..self
}
}
#[must_use]
pub const fn into_role(self) -> Role {
Role {
name: Cow::Borrowed(self.name),
superuser: self.superuser,
create_db: self.create_db,
create_role: self.create_role,
inherit: self.inherit,
can_login: self.can_login,
replication: self.replication,
bypass_rls: self.bypass_rls,
conn_limit: self.conn_limit,
password: match self.password {
Some(p) => Some(Cow::Borrowed(p)),
None => None,
},
valid_until: match self.valid_until {
Some(d) => Some(Cow::Borrowed(d)),
None => None,
},
}
}
}
impl Default for RoleDef {
fn default() -> Self {
Self::new("")
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Role {
#[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
pub name: Cow<'static, str>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub superuser: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub create_db: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub create_role: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub inherit: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub can_login: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub replication: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub bypass_rls: Option<bool>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub conn_limit: Option<i32>,
#[cfg_attr(
feature = "serde",
serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub password: Option<Cow<'static, str>>,
#[cfg_attr(
feature = "serde",
serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub valid_until: Option<Cow<'static, str>>,
}
impl Role {
#[must_use]
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
superuser: None,
create_db: None,
create_role: None,
inherit: None,
can_login: None,
replication: None,
bypass_rls: None,
conn_limit: None,
password: None,
valid_until: None,
}
}
#[inline]
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
}
impl Default for Role {
fn default() -> Self {
Self::new("")
}
}
impl From<RoleDef> for Role {
fn from(def: RoleDef) -> Self {
def.into_role()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_const_role_def() {
const ROLE: RoleDef = RoleDef::new("app_user")
.create_db(true)
.create_role(true)
.can_login(true);
assert_eq!(ROLE.name, "app_user");
assert_eq!(ROLE.create_db, Some(true));
assert_eq!(ROLE.create_role, Some(true));
assert_eq!(ROLE.can_login, Some(true));
}
#[test]
fn test_role_def_to_role() {
const DEF: RoleDef = RoleDef::new("admin").superuser(true).create_db(true);
let role = DEF.into_role();
assert_eq!(role.name(), "admin");
assert_eq!(role.superuser, Some(true));
assert_eq!(role.create_db, Some(true));
}
#[test]
fn test_role_with_conn_limit() {
const ROLE: RoleDef = RoleDef::new("limited_user").conn_limit(5).can_login(true);
let role = ROLE.into_role();
assert_eq!(role.conn_limit, Some(5));
}
}