dataloom-db-core 0.9.1

A database abstraction layer
Documentation
use std::{collections::HashMap, sync::Arc};

use itertools::Itertools;
use tracing::trace;

use crate::{
    MigrationKind, ModelMigration,
    column::{ColumnType, ModifyColumnOptionsValues, create::CreateOptions},
    search::SearchQuery,
    traits::{DatabaseStrategy, DatabaseStrategyError, from_iter::FromIter, save_data::SaveData},
};

pub trait Model {
    const TABLE_NAME: &'static str;

    /// This function should return the migration path for this Model
    fn get_migration() -> &'static Vec<ModelMigration>;

    /// This function controls wether the model is saved or inserted into the database
    fn get_id(&self) -> Option<i64>;

    /// This function returns the name of the id field
    fn get_id_column_name(&self) -> &'static str;

    /// This function sets the id returned by the database
    fn set_id(&mut self, id: i64);

    /// This function returns the latest name of a column by traversing the migration path.
    /// An option of None indicates that the Column was dropped in the migration path
    fn get_latest_column_name(initial_name: &str) -> Option<String> {
        let mut past_names = vec![initial_name.to_string()];
        let mut name = Some(String::from(initial_name));

        for migration in Self::get_migration()
            .iter()
            .sorted_by_key(|item| item.ordering)
        {
            match &migration.kind {
                MigrationKind::Create(columns) => {
                    let existed_at_creation = columns.iter().any(|elem| elem.key == initial_name);
                    if !existed_at_creation {
                        name = None;
                    }
                }
                MigrationKind::Modify(modifiers) => {
                    for modification in modifiers {
                        if !past_names.contains(&modification.key) {
                            continue;
                        }

                        match &modification.options {
                            ModifyColumnOptionsValues::Rename { to } => {
                                if Some(&modification.key) == name.as_ref() {
                                    name = Some(to.to_string());
                                    past_names.push(modification.key.clone());
                                }
                            }

                            ModifyColumnOptionsValues::Drop => name = None,
                            ModifyColumnOptionsValues::Add {
                                new_type: _,
                                new_options: _,
                            } => {
                                if modification.key == initial_name {
                                    name = Some(initial_name.to_string())
                                }
                            }
                        }
                    }
                }
            }
        }

        name
    }

    /// This function returns all columns and types defined by the get_migration()
    fn get_columns() -> Vec<(String, ColumnType, CreateOptions)> {
        let migration = Self::get_migration();

        let mut columns: HashMap<String, (ColumnType, CreateOptions)> = HashMap::new();

        for (idx, column) in migration
            .iter()
            .sorted_by_key(|item| item.ordering)
            .enumerate()
        {
            match &column.kind {
                MigrationKind::Create(values) => {
                    if idx != 0 {
                        panic!("The first iteration must be a creation.")
                    }

                    for item in values.iter().map(|col| {
                        (
                            Self::get_latest_column_name(&col.key).unwrap(),
                            col.value,
                            col.options.clone(),
                        )
                    }) {
                        columns.insert(item.0, (item.1, item.2));
                    }
                }

                MigrationKind::Modify(values) => {
                    for value in values {
                        match &value.options {
                            ModifyColumnOptionsValues::Rename { to: _ } => {}
                            ModifyColumnOptionsValues::Drop => {}
                            ModifyColumnOptionsValues::Add {
                                new_type,
                                new_options: options,
                            } => {
                                columns.insert(
                                    Self::get_latest_column_name(&value.key).unwrap(),
                                    (*new_type, options.clone()),
                                );
                            }
                        }
                    }
                }
            }
        }

        if let MigrationKind::Create(value) = &migration[0].kind {
            for item in value.iter().map(|e| {
                (
                    Self::get_latest_column_name(&e.key).unwrap(),
                    e.value,
                    e.options.clone(),
                )
            }) {
                columns.insert(item.0, (item.1, item.2));
            }
        }

        columns
            .into_iter()
            .map(|(key, (col_value, col_options))| (key, col_value, col_options))
            .collect_vec()
    }

    /// This function is a helper intended for use in Box<dyn ...> situations where T is not available
    fn self_get_migration(&self) -> &'static Vec<ModelMigration> {
        Self::get_migration()
    }

    /// This function is a helper intended for use in Box<dyn ...> situations where T is not available
    fn self_get_table_name(&self) -> &'static str {
        Self::TABLE_NAME
    }

    /// This function is a helper intended for use in Box<dyn ...> situations where T is not available
    fn self_get_columns(&self) -> Vec<(String, ColumnType, CreateOptions)> {
        Self::get_columns()
    }

    fn save<D>(&mut self, db: Arc<D>) -> Result<(), DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.save_model(&db.get_connection(), self)
    }

    fn save_conn<D>(
        &mut self,
        db: Arc<D>,
        conn: &D::FunctionConnType<'_>,
    ) -> Result<(), DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.save_model(conn, self)
    }

    fn search_single<D>(
        db: Arc<D>,
        query: SearchQuery,
    ) -> Result<Option<Self>, DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.search_single_model(&db.get_connection(), query)
    }

    fn search_single_conn<D>(
        db: Arc<D>,
        conn: &D::FunctionConnType<'_>,
        query: SearchQuery,
    ) -> Result<Option<Self>, DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.search_single_model(conn, query)
    }

    fn search_multiple<D>(
        db: Arc<D>,
        query: SearchQuery,
    ) -> Result<Vec<Self>, DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.search_multiple_model(&db.get_connection(), query)
    }

    fn search_multiple_conn<D>(
        db: Arc<D>,
        conn: &D::FunctionConnType<'_>,
        query: SearchQuery,
    ) -> Result<Vec<Self>, DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.search_multiple_model(conn, query)
    }

    fn remove<D>(db: Arc<D>, query: SearchQuery) -> Result<(), DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.remove_model::<Self>(&db.get_connection(), query)
    }

    fn remove_conn<D>(
        db: Arc<D>,
        conn: &D::FunctionConnType<'_>,
        query: SearchQuery,
    ) -> Result<(), DatabaseStrategyError>
    where
        D: DatabaseStrategy,
        Self: Sized + FromIter + SaveData,
    {
        db.remove_model::<Self>(conn, query)
    }
}