vantage-vista 1.2.0

Universal, schema-bearing data handle for the Vantage data framework
Documentation
use indexmap::IndexMap;

use crate::{
    column::Column,
    reference::{ContainedSpec, Reference},
};

/// Schema a `Vista` is built around.
///
/// Driver factories produce one of these by inspecting a typed
/// `Table<DriverSource, E>`; the universal YAML loader produces one by
/// parsing config. End-user code typically doesn't construct this directly.
///
/// Title columns are derived from column flags at runtime — see
/// `Vista::get_title_columns`.
#[derive(Debug, Clone, Default)]
pub struct VistaMetadata {
    pub columns: IndexMap<String, Column>,
    pub references: IndexMap<String, Reference>,
    /// Contained (embedded-in-row) relations, keyed by relation name. Kept
    /// apart from `references` because their data lives in a column of the
    /// parent row, not in a joined table.
    pub contained: IndexMap<String, ContainedSpec>,
    pub id_column: Option<String>,
}

impl VistaMetadata {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_column(mut self, column: Column) -> Self {
        self.columns.insert(column.name.clone(), column);
        self
    }

    /// [`with_column`](Self::with_column) at position `index` (clamped to the
    /// end), shifting later columns along.
    pub fn with_column_at(mut self, index: usize, column: Column) -> Self {
        let index = index.min(self.columns.len());
        self.columns
            .shift_insert(index, column.name.clone(), column);
        self
    }

    /// [`with_column_at`](Self::with_column_at) for each `(position, column)`,
    /// in order — the shape of `Table::computed_columns`.
    pub fn with_columns_at<'a>(
        self,
        columns: impl IntoIterator<Item = (usize, &'a Column)>,
    ) -> Self {
        columns.into_iter().fold(self, |metadata, (at, column)| {
            metadata.with_column_at(at, column.clone())
        })
    }

    pub fn with_reference(mut self, reference: Reference) -> Self {
        self.references.insert(reference.name.clone(), reference);
        self
    }

    pub fn with_contained(mut self, spec: ContainedSpec) -> Self {
        self.contained.insert(spec.name.clone(), spec);
        self
    }

    pub fn with_id_column(mut self, name: impl Into<String>) -> Self {
        self.id_column = Some(name.into());
        self
    }
}