uqa-engine 0.3.6

Engine: schema-aware table store, catalog restore, transactions
//
// Unified Query Algebra
//
// Copyright (c) 2023-2026 Cognica, Inc.
//

//! Retained event registries and pending constraint-event state for native lifecycle execution.
use crate::Engine;
use uqa_core::RelationIdentity;
use uqa_execution::schema::events::context::{ConstraintTriggerEvents, EventLifecycleContext};
use uqa_sql::{
    ast::TableHierarchy,
    catalog::{
        constraints::ConstraintIdentity,
        events::{
            definition::lookup::{EventLookupContext, EventPartitionCatalog},
            reads::{EventCatalogReads, EventLookupState, RuleCatalogRead, TriggerCatalogRead},
            RuleCatalog, TriggerCatalog,
        },
    },
};

impl Engine {
    pub(crate) fn event_lookup_context(&self) -> EventLookupContext<'_> {
        EventLookupContext {
            analysis: self.event_analysis_context(),
            partitions: self,
            registry: self,
            state: self,
        }
    }
    pub(crate) fn event_lifecycle_context(&self) -> EventLifecycleContext<'_> {
        EventLifecycleContext {
            lookup: self.event_lookup_context(),
            catalog: self.event_catalog_context(),
            writer: self,
            notices: &self.runtime.notices,
            views: self,
            projection: self.catalog_execution(),
            pending: self,
        }
    }
}
impl EventCatalogReads for Engine {
    fn read_rules(&self) -> RuleCatalogRead<'_> {
        Box::new(self.durable.rules.read())
    }
    fn read_triggers(&self) -> TriggerCatalogRead<'_> {
        Box::new(self.durable.triggers.read())
    }
}
impl EventPartitionCatalog for Engine {
    fn contains_loaded_table(&self, relation: &RelationIdentity) -> bool {
        self.storage.tables.read().contains_key(relation)
    }
    fn table_names(&self) -> Result<Vec<String>, String> {
        Engine::table_names(self).map_err(|error| error.to_string())
    }
    fn try_table_hierarchy(&self, name: &str) -> Result<TableHierarchy, String> {
        Engine::try_table_hierarchy(self, name).map_err(|error| error.to_string())
    }
}
impl ConstraintTriggerEvents for Engine {
    fn forget(&self, identity: &ConstraintIdentity) {
        self.forget_constraint_trigger_events(identity);
    }
    fn rename_trigger(&self, identity: &ConstraintIdentity, name: &str) {
        self.rename_pending_constraint_trigger(identity, name);
    }
    fn rename_constraint(&self, identity: &ConstraintIdentity, name: &str) {
        self.rename_constraint_trigger_identity(identity, name);
    }
}

impl Engine {
    pub(crate) fn event_catalog_context(
        &self,
    ) -> uqa_execution::schema::events::EventCatalogContext<'_> {
        uqa_execution::schema::events::EventCatalogContext {
            registry: self,
            publication: self,
            changes: self,
        }
    }
}
impl uqa_execution::schema::events::EventCatalogGuards for Engine {
    fn triggers(&self) -> uqa_execution::schema::events::TriggerCatalogWrite<'_> {
        Box::new(self.durable.triggers.write())
    }
    fn rules(&self) -> uqa_execution::schema::events::RuleCatalogWrite<'_> {
        Box::new(self.durable.rules.write())
    }
}
impl uqa_execution::schema::events::EventCatalogPublication for Engine {
    fn persist_triggers(
        &self,
        triggers: &uqa_sql::catalog::events::TriggerCatalog,
    ) -> Result<(), uqa_sql::SQLError> {
        uqa_execution::schema::events::persistence::persist_trigger_catalog_snapshot(
            self.storage.catalog.as_deref(),
            self,
            triggers,
        )
    }
    fn persist_rules(
        &self,
        rules: &uqa_sql::catalog::events::RuleCatalog,
    ) -> Result<(), uqa_sql::SQLError> {
        uqa_execution::schema::events::persistence::persist_rule_catalog_snapshot(
            self.storage.catalog.as_deref(),
            self,
            rules,
        )
    }
}

impl EventLookupState for Engine {
    fn query_rules(&self) -> Option<&RuleCatalog> {
        self.query_catalog_snapshot
            .as_ref()
            .map(|snapshot| snapshot.rules.as_ref())
    }
    fn query_triggers(&self) -> Option<&TriggerCatalog> {
        self.query_catalog_snapshot
            .as_ref()
            .map(|snapshot| snapshot.triggers.as_ref())
    }
    fn session_replication_role_is_replica(&self) -> bool {
        Engine::session_replication_role_is_replica(self)
    }
}

impl Engine {
    pub(crate) fn event_restore_context(
        &self,
    ) -> uqa_execution::schema::events::persistence::EventRestoreContext<'_> {
        uqa_execution::schema::events::persistence::EventRestoreContext {
            analysis: self.event_analysis_context(),
            reads: self,
            catalog: self.event_catalog_context(),
            relations: self,
        }
    }
}
use uqa_sql::{ast::RelationPersistence, catalog::events::persistence::EventRelationPersistence};
impl EventRelationPersistence for Engine {
    fn rule_relation_is_temporary(&self, relation: &RelationIdentity) -> bool {
        self.storage
            .tables
            .read()
            .get(relation)
            .is_some_and(|table| table.persistence == RelationPersistence::Temporary)
            || self
                .durable
                .views
                .read()
                .get(relation)
                .is_some_and(|view| view.persistence == RelationPersistence::Temporary)
    }
    fn trigger_relation_persistence(
        &self,
        relation: &RelationIdentity,
    ) -> Option<RelationPersistence> {
        self.storage
            .tables
            .read()
            .get(relation)
            .map(|table| table.persistence)
            .or_else(|| {
                self.durable
                    .views
                    .read()
                    .get(relation)
                    .map(|view| view.persistence)
            })
            .or_else(|| {
                self.durable
                    .foreign_tables
                    .read()
                    .contains_key(relation)
                    .then_some(RelationPersistence::Permanent)
            })
    }
}