use std::{collections::HashMap, ops::Deref, sync::Arc};
use super::table::{DatabaseTableDefinition, Identifier};
#[derive(Debug)]
pub struct DatabaseDefinition<T> {
data: Arc<DatabaseDefinitionBuilder<T>>,
}
impl<T> Deref for DatabaseDefinition<T> {
type Target = DatabaseDefinitionBuilder<T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DatabaseDefinition<T> {
#[allow(clippy::new_ret_no_self)]
pub fn new(name: &str) -> Result<DatabaseDefinitionBuilder<T>, String> {
DatabaseDefinitionBuilder::<T>::new(name)
}
pub fn new_unchecked(name: &str) -> DatabaseDefinitionBuilder<T> {
match DatabaseDefinitionBuilder::<T>::new(name) {
Ok(def) => def,
Err(e) => panic!("DatabaseDefinition::new_unchecked() failed: {}", e),
}
}
}
#[derive(Debug, Clone)]
pub struct DatabaseDefinitionBuilder<T> {
pub name: Identifier,
pub tables: Vec<DatabaseTableDefinition<T>>,
}
impl<T> From<DatabaseDefinitionBuilder<T>> for DatabaseDefinition<T> {
fn from(mut val: DatabaseDefinitionBuilder<T>) -> Self {
let map = val
.tables
.iter()
.map(|table| (&table.table_name, table))
.collect::<HashMap<_, _>>();
let mut new_tables = Vec::new();
for table in map.values() {
for column in table.columns.values() {
match &column.column_type {
super::table::DatabaseColumnType::OneToMany(_child_table_ident) => {
},
super::table::DatabaseColumnType::ManyToMany(child_table_ident) => {
let join_table = DatabaseTableDefinition::new(&format!(
"{}_to_{}",
&table.table_name, &child_table_ident
))
.expect("Should always be valid")
.with_uuid(&format!("{}_id", &table.table_name))
.expect("Should always be valid")
.with_uuid(&format!("{}_id", &child_table_ident))
.expect("Should always be valid");
new_tables.push(join_table.into());
todo!("Many to Many not yet supported. Need to add constraints still, and impl the non mmigratory parts.");
},
super::table::DatabaseColumnType::OneToOne(_) => {
},
_ => (),
}
}
}
val.tables.append(&mut new_tables);
DatabaseDefinition {
data: Arc::new(val),
}
}
}
impl<T> DatabaseDefinitionBuilder<T> {
pub fn new(name: &str) -> Result<Self, String> {
Ok(Self {
name: Identifier::new(name)?,
tables: Vec::new(),
})
}
pub fn add_table(
mut self,
table: DatabaseTableDefinition<T>,
) -> Self {
self.tables.push(table);
self
}
pub fn table<D: Into<DatabaseTableDefinition<T>>>(
self,
table: D,
) -> Self {
self.add_table(table.into())
}
}