Skip to main content

drizzle_core/traits/
policy.rs

1use core::any::Any;
2
3use crate::{SQLParam, SQLSchemaType, SQLTable, TableRef, ToSQL};
4
5/// Compile-time PostgreSQL row-level security policy metadata.
6///
7/// Implementing this trait automatically provides [`SQLPolicyInfo`] via a
8/// blanket implementation.
9pub trait DrizzlePolicy: Send + Sync + 'static {
10    /// Policy name.
11    const POLICY_NAME: &'static str;
12
13    /// AS clause (`PERMISSIVE` or `RESTRICTIVE`).
14    const AS_CLAUSE: Option<&'static str> = None;
15
16    /// FOR clause (`ALL`, `SELECT`, `INSERT`, `UPDATE`, or `DELETE`).
17    const FOR_CLAUSE: Option<&'static str> = None;
18
19    /// TO roles.
20    const TO: &'static [&'static str] = &[];
21
22    /// USING expression.
23    const USING: Option<&'static str> = None;
24
25    /// WITH CHECK expression.
26    const WITH_CHECK: Option<&'static str> = None;
27
28    /// The table this policy belongs to.
29    fn table_ref() -> &'static TableRef;
30}
31
32/// Blanket: any [`DrizzlePolicy`] automatically satisfies [`SQLPolicyInfo`].
33impl<T: DrizzlePolicy> SQLPolicyInfo for T {
34    fn table(&self) -> &'static TableRef {
35        T::table_ref()
36    }
37
38    fn name(&self) -> &'static str {
39        T::POLICY_NAME
40    }
41
42    fn as_clause(&self) -> Option<&'static str> {
43        T::AS_CLAUSE
44    }
45
46    fn for_clause(&self) -> Option<&'static str> {
47        T::FOR_CLAUSE
48    }
49
50    fn to(&self) -> &'static [&'static str] {
51        T::TO
52    }
53
54    fn using(&self) -> Option<&'static str> {
55        T::USING
56    }
57
58    fn with_check(&self) -> Option<&'static str> {
59        T::WITH_CHECK
60    }
61}
62
63/// Runtime view of policy metadata for schema derivation.
64pub trait SQLPolicyInfo: Any + Send + Sync {
65    fn table(&self) -> &'static TableRef;
66    fn name(&self) -> &'static str;
67    fn as_clause(&self) -> Option<&'static str>;
68    fn for_clause(&self) -> Option<&'static str>;
69    fn to(&self) -> &'static [&'static str];
70    fn using(&self) -> Option<&'static str>;
71    fn with_check(&self) -> Option<&'static str>;
72}
73
74impl core::fmt::Debug for dyn SQLPolicyInfo {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        f.debug_struct("SQLPolicyInfo")
77            .field("name", &self.name())
78            .field("table", &self.table().name)
79            .field("as_clause", &self.as_clause())
80            .field("for_clause", &self.for_clause())
81            .field("to", &self.to())
82            .finish()
83    }
84}
85
86/// Trait for types that represent PostgreSQL policies.
87#[diagnostic::on_unimplemented(
88    message = "`{Self}` is not a SQL policy for this dialect",
89    label = "ensure this type was derived with #[PostgresPolicy]"
90)]
91pub trait SQLPolicy<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
92    SQLPolicyInfo + ToSQL<'a, Value>
93{
94    /// The table type this policy is associated with.
95    type Table: SQLTable<'a, Type, Value>;
96}