use-db-index 0.1.0

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

//! Index metadata primitives for `RustUse`.

use use_db_name::{ColumnName, IndexName, TableName};

/// Index reference metadata.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IndexRef {
    name: Option<IndexName>,
    table: Option<TableName>,
}

impl IndexRef {
    /// Creates index reference metadata.
    #[must_use]
    pub const fn new(name: Option<IndexName>, table: Option<TableName>) -> Self {
        Self { name, table }
    }

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

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

/// Broad index kind.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IndexKind {
    /// B-tree-like index.
    #[default]
    BTree,
    /// Hash-like index.
    Hash,
    /// Full-text or search index.
    FullText,
    /// Spatial index.
    Spatial,
    /// Other or unspecified index kind.
    Other,
}

/// Index column sort order.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IndexOrder {
    /// Ascending order.
    #[default]
    Ascending,
    /// Descending order.
    Descending,
    /// Engine default order.
    Default,
}

/// Index uniqueness metadata.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IndexUniqueness {
    /// Non-unique index.
    #[default]
    NonUnique,
    /// Unique index.
    Unique,
}

/// An indexed column.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IndexColumn {
    column: ColumnName,
    order: IndexOrder,
}

impl IndexColumn {
    /// Creates indexed column metadata.
    #[must_use]
    pub const fn new(column: ColumnName, order: IndexOrder) -> Self {
        Self { column, order }
    }

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

    /// Returns the order metadata.
    #[must_use]
    pub const fn order(&self) -> IndexOrder {
        self.order
    }
}

/// Index metadata.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IndexMetadata {
    reference: IndexRef,
    kind: IndexKind,
    columns: Vec<IndexColumn>,
    uniqueness: IndexUniqueness,
}

impl IndexMetadata {
    /// Creates index metadata.
    #[must_use]
    pub const fn new(reference: IndexRef) -> Self {
        Self {
            reference,
            kind: IndexKind::BTree,
            columns: Vec::new(),
            uniqueness: IndexUniqueness::NonUnique,
        }
    }

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

    /// Sets indexed columns.
    #[must_use]
    pub fn with_columns(mut self, columns: Vec<IndexColumn>) -> Self {
        self.columns = columns;
        self
    }

    /// Sets uniqueness metadata.
    #[must_use]
    pub const fn with_uniqueness(mut self, uniqueness: IndexUniqueness) -> Self {
        self.uniqueness = uniqueness;
        self
    }

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

    /// Returns indexed columns.
    #[must_use]
    pub fn columns(&self) -> &[IndexColumn] {
        &self.columns
    }

    /// Returns uniqueness metadata.
    #[must_use]
    pub const fn uniqueness(&self) -> IndexUniqueness {
        self.uniqueness
    }
}

#[cfg(test)]
mod tests {
    use super::{IndexColumn, IndexMetadata, IndexOrder, IndexRef, IndexUniqueness};
    use use_db_name::{ColumnName, IndexName, TableName};

    #[test]
    fn stores_index_metadata() -> Result<(), Box<dyn std::error::Error>> {
        let reference = IndexRef::new(
            Some(IndexName::new("users_id_idx")?),
            Some(TableName::new("users")?),
        );
        let column = IndexColumn::new(ColumnName::new("id")?, IndexOrder::Ascending);
        let metadata = IndexMetadata::new(reference)
            .with_columns(vec![column])
            .with_uniqueness(IndexUniqueness::Unique);

        assert_eq!(
            metadata.reference().name().expect("name").as_str(),
            "users_id_idx"
        );
        assert_eq!(metadata.columns()[0].order(), IndexOrder::Ascending);
        assert_eq!(metadata.uniqueness(), IndexUniqueness::Unique);
        Ok(())
    }
}