reddb-io-server 1.2.0

RedDB server-side engine: storage, runtime, replication, MCP, AI, and the gRPC/HTTP/RedWire/PG-wire dispatchers. Re-exported by the umbrella `reddb` crate.
Documentation
use std::collections::BTreeMap;

use crate::application::ports::RuntimeAdminPort;
use crate::catalog::{CatalogAnalyticsJobStatus, CatalogGraphProjectionStatus, CatalogIndexStatus};
use crate::runtime::RuntimeGraphProjection;
use crate::{PhysicalAnalyticsJob, PhysicalGraphProjection, PhysicalIndexState, RedDBResult};

#[derive(Debug, Clone, Default)]
pub struct ServerlessAnalyticsWarmupTarget {
    pub kind: String,
    pub projection: Option<String>,
}

#[derive(Debug, Clone, Default)]
pub struct ServerlessWarmupPlan {
    pub indexes: Vec<String>,
    pub graph_projections: Vec<String>,
    pub analytics_jobs: Vec<ServerlessAnalyticsWarmupTarget>,
    pub includes_native_artifacts: bool,
}

pub struct AdminUseCases<'a, P: ?Sized> {
    runtime: &'a P,
}

impl<'a, P: RuntimeAdminPort + ?Sized> AdminUseCases<'a, P> {
    pub fn new(runtime: &'a P) -> Self {
        Self { runtime }
    }

    pub fn set_index_enabled(&self, name: &str, enabled: bool) -> RedDBResult<PhysicalIndexState> {
        self.runtime.set_index_enabled(name, enabled)
    }

    pub fn mark_index_building(&self, name: &str) -> RedDBResult<PhysicalIndexState> {
        self.runtime.mark_index_building(name)
    }

    pub fn fail_index(&self, name: &str) -> RedDBResult<PhysicalIndexState> {
        self.runtime.fail_index(name)
    }

    pub fn mark_index_stale(&self, name: &str) -> RedDBResult<PhysicalIndexState> {
        self.runtime.mark_index_stale(name)
    }

    pub fn mark_index_ready(&self, name: &str) -> RedDBResult<PhysicalIndexState> {
        self.runtime.mark_index_ready(name)
    }

    pub fn warmup_index(&self, name: &str) -> RedDBResult<PhysicalIndexState> {
        self.runtime.warmup_index_with_lifecycle(name)
    }

    pub fn rebuild_indexes(
        &self,
        collection: Option<&str>,
    ) -> RedDBResult<Vec<PhysicalIndexState>> {
        self.runtime.rebuild_indexes_with_lifecycle(collection)
    }

    pub fn save_graph_projection(
        &self,
        name: impl Into<String>,
        projection: RuntimeGraphProjection,
        source: Option<String>,
    ) -> RedDBResult<PhysicalGraphProjection> {
        self.runtime.save_graph_projection(name, projection, source)
    }

    pub fn mark_graph_projection_materializing(
        &self,
        name: &str,
    ) -> RedDBResult<PhysicalGraphProjection> {
        self.runtime.mark_graph_projection_materializing(name)
    }

    pub fn materialize_graph_projection(&self, name: &str) -> RedDBResult<PhysicalGraphProjection> {
        self.runtime.materialize_graph_projection(name)
    }

    pub fn fail_graph_projection(&self, name: &str) -> RedDBResult<PhysicalGraphProjection> {
        self.runtime.fail_graph_projection(name)
    }

    pub fn mark_graph_projection_stale(&self, name: &str) -> RedDBResult<PhysicalGraphProjection> {
        self.runtime.mark_graph_projection_stale(name)
    }

    pub fn save_analytics_job(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .save_analytics_job(kind, projection_name, metadata)
    }

    pub fn start_analytics_job(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .start_analytics_job(kind, projection_name, metadata)
    }

    pub fn queue_analytics_job(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .queue_analytics_job(kind, projection_name, metadata)
    }

    pub fn fail_analytics_job(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .fail_analytics_job(kind, projection_name, metadata)
    }

    pub fn mark_analytics_job_stale(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .mark_analytics_job_stale(kind, projection_name, metadata)
    }

    pub fn complete_analytics_job(
        &self,
        kind: impl Into<String>,
        projection_name: Option<String>,
        metadata: BTreeMap<String, String>,
    ) -> RedDBResult<PhysicalAnalyticsJob> {
        self.runtime
            .complete_analytics_job(kind, projection_name, metadata)
    }

    pub fn build_serverless_warmup_plan(
        &self,
        index_statuses: &[CatalogIndexStatus],
        graph_projection_statuses: &[CatalogGraphProjectionStatus],
        analytics_job_statuses: &[CatalogAnalyticsJobStatus],
        force: bool,
        include_indexes: bool,
        include_graph_projections: bool,
        include_analytics_jobs: bool,
        include_native_artifacts: bool,
    ) -> ServerlessWarmupPlan {
        let mut plan = ServerlessWarmupPlan::default();

        if include_indexes {
            for status in index_statuses {
                if !status.declared {
                    continue;
                }
                if force || status.requires_rebuild {
                    plan.indexes.push(status.name.clone());
                }
            }
        }

        if include_graph_projections {
            for status in graph_projection_statuses {
                if !status.declared {
                    continue;
                }
                let should_rematerialize = force
                    || status.requires_rematerialization
                    || status.rerun_required
                    || !status.dependent_jobs_in_sync;
                if should_rematerialize {
                    plan.graph_projections.push(status.name.clone());
                }
            }
        }

        if include_analytics_jobs {
            for status in analytics_job_statuses {
                if !status.declared {
                    continue;
                }
                if force || status.requires_rerun || status.executable {
                    plan.analytics_jobs.push(ServerlessAnalyticsWarmupTarget {
                        kind: status.kind.clone(),
                        projection: status.projection.clone(),
                    });
                }
            }
        }

        plan.includes_native_artifacts = include_native_artifacts;
        plan
    }
}