use serde::{Deserialize, Serialize};
use indexmap::IndexMap;
use super::column::Column;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelDef {
pub name: String,
pub table: Option<String>,
pub columns: IndexMap<String, Column>,
pub relationships: Vec<Relationship>,
pub indexes: Vec<IndexDef>,
pub pivot: bool,
pub soft_deletes: bool,
pub timestamps: bool,
pub traits: Vec<String>,
pub primary_key: String,
pub timestamps_type: String,
pub soft_delete_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Relationship {
pub type_: String,
pub model: String,
pub foreign_key: Option<String>,
pub local_key: Option<String>,
pub table: Option<String>,
pub pivot_table: Option<String>,
pub related_key: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexDef {
pub columns: Vec<String>,
pub index_type: Option<String>,
}
impl ModelDef {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
table: None,
columns: IndexMap::new(),
relationships: vec![],
indexes: vec![],
pivot: false,
soft_deletes: false,
timestamps: true,
traits: vec![],
primary_key: "id".to_string(),
timestamps_type: "timestamps".to_string(),
soft_delete_type: "softDeletes".to_string(),
}
}
pub fn table_name(&self) -> String {
self.table
.clone()
.unwrap_or_else(|| self.name_to_table())
}
pub fn name_to_table(&self) -> String {
let snake = convert_case::Casing::to_case(&self.name, convert_case::Case::Snake);
let plural = pluralize(&snake);
plural
}
pub fn fillable_columns(&self) -> Vec<&Column> {
self.columns
.values()
.filter(|c| {
!c.is_timestamps()
&& !c.is_soft_deletes()
&& c.name != self.primary_key
&& !c.is_relationship
})
.collect()
}
pub fn has_soft_deletes(&self) -> bool {
self.soft_deletes || self.columns.values().any(|c| c.is_soft_deletes())
}
}
fn pluralize(s: &str) -> String {
if s.ends_with('y') && !s.ends_with("ay") && !s.ends_with("ey") && !s.ends_with("oy") && !s.ends_with("uy") {
format!("{}ies", &s[..s.len() - 1])
} else if s.ends_with('s') || s.ends_with('x') || s.ends_with('z') || s.ends_with("ch") || s.ends_with("sh") {
format!("{}es", s)
} else {
format!("{}s", s)
}
}