radixdb-catalog 1.1.0

Generational logical catalog owner for RadixDB
Documentation
use crate::payload::common::{ordered_unique_ids, validate_flags, validate_version, CanonicalSql};
use crate::{CatalogError, CatalogResult, ObjectId};

pub const TRIGGER_EVENT_INSERT: u16 = 1 << 0;
pub const TRIGGER_EVENT_UPDATE: u16 = 1 << 1;
pub const TRIGGER_EVENT_DELETE: u16 = 1 << 2;
pub const ALL_TRIGGER_EVENTS: u16 =
    TRIGGER_EVENT_INSERT | TRIGGER_EVENT_UPDATE | TRIGGER_EVENT_DELETE;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum TriggerTiming {
    Before = 1,
    After = 2,
}
impl TryFrom<u16> for TriggerTiming {
    type Error = CatalogError;
    fn try_from(tag: u16) -> CatalogResult<Self> {
        match tag {
            1 => Ok(Self::Before),
            2 => Ok(Self::After),
            _ => Err(CatalogError::UnknownPayloadEnumTag {
                owner: "trigger timing",
                tag,
            }),
        }
    }
}
impl TriggerTiming {
    pub const fn tag(self) -> u16 {
        self as u16
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum TriggerLevel {
    Row = 1,
    Statement = 2,
}
impl TryFrom<u16> for TriggerLevel {
    type Error = CatalogError;
    fn try_from(tag: u16) -> CatalogResult<Self> {
        match tag {
            1 => Ok(Self::Row),
            2 => Ok(Self::Statement),
            _ => Err(CatalogError::UnknownPayloadEnumTag {
                owner: "trigger level",
                tag,
            }),
        }
    }
}
impl TriggerLevel {
    pub const fn tag(self) -> u16 {
        self as u16
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TriggerPayload {
    table_id: ObjectId,
    function_id: ObjectId,
    timing: TriggerTiming,
    events: u16,
    level: TriggerLevel,
    update_column_ids: Vec<ObjectId>,
    priority: i32,
    when_sql: Option<CanonicalSql>,
}

impl TriggerPayload {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        table_id: ObjectId,
        function_id: ObjectId,
        timing: TriggerTiming,
        events: u16,
        level: TriggerLevel,
        update_column_ids: Vec<ObjectId>,
        priority: i32,
        when_sql: Option<String>,
    ) -> CatalogResult<Self> {
        if events == 0
            || events & !ALL_TRIGGER_EVENTS != 0
            || (!update_column_ids.is_empty() && events & TRIGGER_EVENT_UPDATE == 0)
        {
            return Err(CatalogError::InvalidCatalogFormat {
                detail: "trigger event or UPDATE column set is invalid",
            });
        }
        Ok(Self {
            table_id,
            function_id,
            timing,
            events,
            level,
            update_column_ids: ordered_unique_ids(
                "trigger.update_column_ids",
                update_column_ids,
                true,
            )?,
            priority,
            when_sql: when_sql
                .map(|sql| CanonicalSql::new("trigger.when_sql", sql))
                .transpose()?,
        })
    }
    #[allow(clippy::too_many_arguments)]
    pub fn from_fields(
        version: u16,
        flags: u64,
        table_id: ObjectId,
        function_id: ObjectId,
        timing: TriggerTiming,
        events: u16,
        level: TriggerLevel,
        update_column_ids: Vec<ObjectId>,
        priority: i32,
        when_sql: Option<String>,
    ) -> CatalogResult<Self> {
        validate_version("trigger", version)?;
        validate_flags("trigger", flags)?;
        Self::new(
            table_id,
            function_id,
            timing,
            events,
            level,
            update_column_ids,
            priority,
            when_sql,
        )
    }
    pub const fn table_id(&self) -> ObjectId {
        self.table_id
    }
    pub const fn function_id(&self) -> ObjectId {
        self.function_id
    }
    pub const fn timing(&self) -> TriggerTiming {
        self.timing
    }
    pub const fn events(&self) -> u16 {
        self.events
    }
    pub const fn level(&self) -> TriggerLevel {
        self.level
    }
    pub fn update_column_ids(&self) -> &[ObjectId] {
        &self.update_column_ids
    }
    pub const fn priority(&self) -> i32 {
        self.priority
    }
    pub fn when_sql(&self) -> Option<&CanonicalSql> {
        self.when_sql.as_ref()
    }
    pub const fn flags(&self) -> u64 {
        0
    }
}