#[cfg(feature = "std")]
use std::borrow::Cow;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::borrow::Cow;
#[cfg(feature = "serde")]
use crate::serde_helpers::{cow_from_string, cow_option_from_string, cow_option_vec_from_strings};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PolicyDef {
pub schema: &'static str,
pub table: &'static str,
pub name: &'static str,
pub as_clause: Option<&'static str>,
pub for_clause: Option<&'static str>,
pub to: Option<&'static [&'static str]>,
pub using: Option<&'static str>,
pub with_check: Option<&'static str>,
}
impl PolicyDef {
#[must_use]
pub const fn new(schema: &'static str, table: &'static str, name: &'static str) -> Self {
Self {
schema,
table,
name,
as_clause: None,
for_clause: None,
to: None,
using: None,
with_check: None,
}
}
#[must_use]
pub const fn as_clause(self, clause: &'static str) -> Self {
Self {
as_clause: Some(clause),
..self
}
}
#[must_use]
pub const fn for_clause(self, clause: &'static str) -> Self {
Self {
for_clause: Some(clause),
..self
}
}
#[must_use]
pub const fn to(self, roles: &'static [&'static str]) -> Self {
Self {
to: Some(roles),
..self
}
}
#[must_use]
pub const fn using(self, expr: &'static str) -> Self {
Self {
using: Some(expr),
..self
}
}
#[must_use]
pub const fn with_check(self, expr: &'static str) -> Self {
Self {
with_check: Some(expr),
..self
}
}
#[must_use]
pub const fn into_policy(self) -> Policy {
Policy {
schema: Cow::Borrowed(self.schema),
table: Cow::Borrowed(self.table),
name: Cow::Borrowed(self.name),
as_clause: match self.as_clause {
Some(s) => Some(Cow::Borrowed(s)),
None => None,
},
for_clause: match self.for_clause {
Some(s) => Some(Cow::Borrowed(s)),
None => None,
},
to: match self.to {
Some(roles) => Some(Cow::Borrowed(roles)),
None => None,
},
using: match self.using {
Some(s) => Some(Cow::Borrowed(s)),
None => None,
},
with_check: match self.with_check {
Some(s) => Some(Cow::Borrowed(s)),
None => None,
},
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Policy {
#[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
pub schema: Cow<'static, str>,
#[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
pub table: Cow<'static, str>,
#[cfg_attr(feature = "serde", serde(deserialize_with = "cow_from_string"))]
pub name: Cow<'static, str>,
#[cfg_attr(
feature = "serde",
serde(
rename = "as",
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub as_clause: Option<Cow<'static, str>>,
#[cfg_attr(
feature = "serde",
serde(
rename = "for",
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub for_clause: Option<Cow<'static, str>>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_vec_from_strings"
)
)]
pub to: Option<Cow<'static, [&'static str]>>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub using: Option<Cow<'static, str>>,
#[cfg_attr(
feature = "serde",
serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "cow_option_from_string"
)
)]
pub with_check: Option<Cow<'static, str>>,
}
impl Policy {
#[must_use]
pub fn new(
schema: impl Into<Cow<'static, str>>,
table: impl Into<Cow<'static, str>>,
name: impl Into<Cow<'static, str>>,
) -> Self {
Self {
schema: schema.into(),
table: table.into(),
name: name.into(),
as_clause: None,
for_clause: None,
to: None,
using: None,
with_check: None,
}
}
#[inline]
#[must_use]
pub fn schema(&self) -> &str {
&self.schema
}
#[inline]
#[must_use]
pub fn table(&self) -> &str {
&self.table
}
#[inline]
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
}
impl From<PolicyDef> for Policy {
fn from(def: PolicyDef) -> Self {
def.into_policy()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_const_policy_def() {
const POLICY: PolicyDef = PolicyDef::new("public", "users", "users_policy")
.for_clause("SELECT")
.using("user_id = current_user_id()");
assert_eq!(POLICY.schema, "public");
assert_eq!(POLICY.table, "users");
assert_eq!(POLICY.name, "users_policy");
}
#[test]
fn test_policy_def_to_policy() {
const DEF: PolicyDef = PolicyDef::new("public", "users", "policy");
let policy = DEF.into_policy();
assert_eq!(policy.schema(), "public");
assert_eq!(policy.table(), "users");
assert_eq!(policy.name(), "policy");
}
}