use-db-table 0.1.0

Primitive database table metadata for RustUse
Documentation
#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]

//! Table metadata primitives for `RustUse`.

use use_db_name::{SchemaName, TableName};

/// A table reference with optional schema qualification.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TableRef {
    schema: Option<SchemaName>,
    table: TableName,
}

impl TableRef {
    /// Creates a table reference.
    #[must_use]
    pub const fn new(table: TableName) -> Self {
        Self {
            schema: None,
            table,
        }
    }

    /// Adds a schema qualifier.
    #[must_use]
    pub fn with_schema(mut self, schema: SchemaName) -> Self {
        self.schema = Some(schema);
        self
    }

    /// Returns the optional schema name.
    #[must_use]
    pub const fn schema(&self) -> Option<&SchemaName> {
        self.schema.as_ref()
    }

    /// Returns the table name.
    #[must_use]
    pub const fn table(&self) -> &TableName {
        &self.table
    }
}

/// Broad table families.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum TableKind {
    /// A base table.
    #[default]
    Base,
    /// A view-like table.
    View,
    /// A temporary table.
    Temporary,
    /// A foreign or external table.
    External,
    /// Other or unspecified table kind.
    Other,
}

/// Broad table lifecycle status.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum TableStatus {
    /// Table is active.
    #[default]
    Active,
    /// Table is archived.
    Archived,
    /// Table is deprecated.
    Deprecated,
    /// Status is unknown.
    Unknown,
}

/// Basic table statistics.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TableStats {
    row_count: Option<u64>,
    byte_size: Option<u64>,
}

impl TableStats {
    /// Creates table statistics.
    #[must_use]
    pub const fn new(row_count: Option<u64>, byte_size: Option<u64>) -> Self {
        Self {
            row_count,
            byte_size,
        }
    }

    /// Returns the optional row count.
    #[must_use]
    pub const fn row_count(self) -> Option<u64> {
        self.row_count
    }

    /// Returns the optional byte size.
    #[must_use]
    pub const fn byte_size(self) -> Option<u64> {
        self.byte_size
    }
}

/// Table metadata.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TableMetadata {
    reference: TableRef,
    kind: TableKind,
    status: TableStatus,
    stats: TableStats,
}

impl TableMetadata {
    /// Creates table metadata.
    #[must_use]
    pub const fn new(reference: TableRef) -> Self {
        Self {
            reference,
            kind: TableKind::Base,
            status: TableStatus::Active,
            stats: TableStats::new(None, None),
        }
    }

    /// Sets the table kind.
    #[must_use]
    pub const fn with_kind(mut self, kind: TableKind) -> Self {
        self.kind = kind;
        self
    }

    /// Sets the table status.
    #[must_use]
    pub const fn with_status(mut self, status: TableStatus) -> Self {
        self.status = status;
        self
    }

    /// Sets table statistics.
    #[must_use]
    pub const fn with_stats(mut self, stats: TableStats) -> Self {
        self.stats = stats;
        self
    }

    /// Returns the table reference.
    #[must_use]
    pub const fn reference(&self) -> &TableRef {
        &self.reference
    }

    /// Returns the table kind.
    #[must_use]
    pub const fn kind(&self) -> TableKind {
        self.kind
    }

    /// Returns the table status.
    #[must_use]
    pub const fn status(&self) -> TableStatus {
        self.status
    }

    /// Returns the table statistics.
    #[must_use]
    pub const fn stats(&self) -> TableStats {
        self.stats
    }
}

#[cfg(test)]
mod tests {
    use super::{TableKind, TableMetadata, TableRef, TableStats, TableStatus};
    use use_db_name::{SchemaName, TableName};

    #[test]
    fn stores_table_metadata() -> Result<(), Box<dyn std::error::Error>> {
        let table = TableRef::new(TableName::new("users")?).with_schema(SchemaName::new("public")?);
        let metadata = TableMetadata::new(table)
            .with_kind(TableKind::Base)
            .with_status(TableStatus::Active)
            .with_stats(TableStats::new(Some(10), Some(2048)));

        assert_eq!(
            metadata.reference().schema().expect("schema").as_str(),
            "public"
        );
        assert_eq!(metadata.stats().row_count(), Some(10));
        assert_eq!(metadata.kind(), TableKind::Base);
        Ok(())
    }
}