drizzle-core 0.3.1

A type-safe SQL query builder for Rust
Documentation
use core::any::Any;

use crate::{SQLParam, SQLSchemaType, SQLTable, TableRef, ToSQL};

/// A PostgreSQL row-level security policy's metadata as associated
/// constants, generated by `#[PostgresPolicy]`.
///
/// Every `DrizzlePolicy` also implements [`SQLPolicyInfo`].
pub trait DrizzlePolicy: Send + Sync + 'static {
    /// Policy name.
    const POLICY_NAME: &'static str;

    /// AS clause (`PERMISSIVE` or `RESTRICTIVE`).
    const AS_CLAUSE: Option<&'static str> = None;

    /// FOR clause (`ALL`, `SELECT`, `INSERT`, `UPDATE`, or `DELETE`).
    const FOR_CLAUSE: Option<&'static str> = None;

    /// Roles in the `TO` clause.
    const TO: &'static [&'static str] = &[];

    /// `USING` expression, as SQL text.
    const USING: Option<&'static str> = None;

    /// `WITH CHECK` expression, as SQL text.
    const WITH_CHECK: Option<&'static str> = None;

    /// The table this policy belongs to.
    fn table_ref() -> &'static TableRef;
}

// Every `DrizzlePolicy` is a `SQLPolicyInfo`.
impl<T: DrizzlePolicy> SQLPolicyInfo for T {
    fn table(&self) -> &'static TableRef {
        T::table_ref()
    }

    fn name(&self) -> &'static str {
        T::POLICY_NAME
    }

    fn as_clause(&self) -> Option<&'static str> {
        T::AS_CLAUSE
    }

    fn for_clause(&self) -> Option<&'static str> {
        T::FOR_CLAUSE
    }

    fn to(&self) -> &'static [&'static str] {
        T::TO
    }

    fn using(&self) -> Option<&'static str> {
        T::USING
    }

    fn with_check(&self) -> Option<&'static str> {
        T::WITH_CHECK
    }
}

/// Runtime metadata of a policy, usable as a trait object. See
/// [`DrizzlePolicy`] for what each field means.
pub trait SQLPolicyInfo: Any + Send + Sync {
    /// The table the policy applies to.
    fn table(&self) -> &'static TableRef;
    /// The policy name.
    fn name(&self) -> &'static str;
    /// `PERMISSIVE` or `RESTRICTIVE`, if set.
    fn as_clause(&self) -> Option<&'static str>;
    /// The command the policy covers, if set.
    fn for_clause(&self) -> Option<&'static str>;
    /// Roles in the `TO` clause.
    fn to(&self) -> &'static [&'static str];
    /// `USING` expression, as SQL text.
    fn using(&self) -> Option<&'static str>;
    /// `WITH CHECK` expression, as SQL text.
    fn with_check(&self) -> Option<&'static str>;
}

impl core::fmt::Debug for dyn SQLPolicyInfo {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("SQLPolicyInfo")
            .field("name", &self.name())
            .field("table", &self.table().name)
            .field("as_clause", &self.as_clause())
            .field("for_clause", &self.for_clause())
            .field("to", &self.to())
            .finish()
    }
}

/// A PostgreSQL row-level security policy. Renders as its `CREATE POLICY`
/// statement.
#[diagnostic::on_unimplemented(
    message = "`{Self}` is not a SQL policy for this dialect",
    label = "ensure this type was derived with #[PostgresPolicy]"
)]
pub trait SQLPolicy<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
    SQLPolicyInfo + ToSQL<'a, Value>
{
    /// The table the policy applies to.
    type Table: SQLTable<'a, Type, Value>;
}