use convert_case::{Case, Casing};
use inflector::string::singularize::to_singular;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use super::{to_id_name, ModelDef, GROUPS, MODEL, MODELS};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[schemars(title = "Relations Type")]
pub enum RelationsType {
Many,
One,
OneToOne,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[schemars(title = "Reference Option")]
pub enum ReferenceOption {
Restrict,
Cascade,
SetNull,
SetZero,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default, JsonSchema)]
#[schemars(deny_unknown_fields)]
#[schemars(title = "Relation Def")]
pub struct RelDef {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(rename = "type")]
#[serde(skip_serializing_if = "Option::is_none")]
pub type_def: Option<RelationsType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub local: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub foreign: Option<String>,
#[serde(default, skip_serializing_if = "super::is_false")]
pub in_cache: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub raw_cond: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_by: Option<String>,
#[serde(default, skip_serializing_if = "super::is_false")]
pub desc: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(default, skip_serializing_if = "super::is_false")]
pub use_cache: bool,
#[serde(default, skip_serializing_if = "super::is_false")]
pub use_cache_with_trashed: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub on_delete: Option<ReferenceOption>,
#[serde(skip_serializing_if = "Option::is_none")]
pub on_update: Option<ReferenceOption>,
}
pub const MODEL_NAME_SPLITTER: &str = "::";
impl RelDef {
pub fn get_stem_name(rel_def: &Option<RelDef>, name: &str) -> String {
if let Some(ref rel) = rel_def {
match rel.model {
None => name,
Some(ref name) => {
if name.contains(MODEL_NAME_SPLITTER) {
let (group_name, stem_name) = name.split_once(MODEL_NAME_SPLITTER).unwrap();
crate::common::check_name(group_name);
crate::common::check_name(stem_name);
stem_name
} else {
crate::common::check_name(name);
name
}
}
}
} else {
name
}
.to_owned()
}
pub fn get_foreign_class_name(rel_def: &Option<RelDef>, name: &str) -> String {
format!(
"_{}",
Self::get_foreign_model_name(rel_def, name)
.1
.to_case(Case::Pascal)
)
}
pub fn get_id_name(rel_def: &Option<RelDef>, name: &str) -> String {
to_id_name(&Self::get_foreign_model_name(rel_def, name).1)
}
pub fn get_mod_name(rel_def: &Option<RelDef>, name: &str) -> String {
Self::get_foreign_model_name(rel_def, name).0
}
pub fn get_group_mod_name(rel_def: &Option<RelDef>, name: &str) -> String {
let model_def = unsafe { MODEL.get().unwrap() }.clone();
format!(
"{}_{}",
RelDef::get_group_name(rel_def, model_def.as_ref()),
RelDef::get_mod_name(rel_def, name)
)
}
pub fn get_local_id(rel_def: &Option<RelDef>, name: &str, id_name: &str) -> String {
if let Some(ref rel) = rel_def {
match rel.local {
None => {
if rel.type_def == Some(RelationsType::OneToOne) {
id_name.to_string()
} else {
format!("{}_id", name)
}
}
Some(ref name) => name.to_owned(),
}
} else {
format!("{}_id", name)
}
}
pub fn get_foreign_id(
rel_def: &Option<RelDef>,
self_model: &ModelDef,
target_model: &Arc<ModelDef>,
) -> String {
if let Some(ref rel) = rel_def {
if let Some(ref name) = rel.foreign {
return name.to_owned();
}
}
let id = format!("{}_id", self_model.name);
if target_model.merged_columns.contains_key(&id) {
return id;
}
"foreign id not found!".to_string()
}
pub fn foreign_is_not_null(
rel_def: &Option<RelDef>,
name: &str,
self_model: &ModelDef,
) -> bool {
let target_model = Self::get_foreign_model(rel_def, name);
let foreign = Self::get_foreign_id(rel_def, self_model, &target_model);
let column = target_model
.merged_columns
.get(&foreign)
.unwrap_or_else(|| panic!("{} is not found in {}.", foreign, target_model.name));
column.not_null
}
pub fn get_foreign_table_name(rel_def: &Option<RelDef>, name: &str) -> String {
Self::get_foreign_model(rel_def, name).table_name()
}
pub fn get_foreign_model(rel_def: &Option<RelDef>, name: &str) -> Arc<ModelDef> {
let group_name = rel_def
.as_ref()
.and_then(|v| v.model.as_ref())
.and_then(|name| {
if name.contains(MODEL_NAME_SPLITTER) {
let (group_name, _) = name.split_once(MODEL_NAME_SPLITTER).unwrap();
crate::common::check_name(group_name);
Some(group_name)
} else {
None
}
});
let stem_name = Self::get_stem_name(rel_def, name);
get_model(group_name, &stem_name)
}
pub fn get_foreign_model_name(rel_def: &Option<RelDef>, name: &str) -> (String, String) {
let group_name = rel_def
.as_ref()
.and_then(|v| v.model.as_ref())
.and_then(|name| {
if name.contains(MODEL_NAME_SPLITTER) {
let (group_name, _) = name.split_once(MODEL_NAME_SPLITTER).unwrap();
crate::common::check_name(group_name);
Some(group_name)
} else {
None
}
});
let stem_name = Self::get_stem_name(rel_def, name);
get_model_name(group_name, &stem_name)
}
pub fn get_model_by_name(name: &str) -> Arc<ModelDef> {
let (group_name, stem_name) = if name.contains(MODEL_NAME_SPLITTER) {
let (group_name, stem_name) = name.split_once(MODEL_NAME_SPLITTER).unwrap();
crate::common::check_name(group_name);
crate::common::check_name(stem_name);
(Some(group_name), stem_name)
} else {
(None, name)
};
get_model(group_name, stem_name)
}
pub fn get_group_name(rel_def: &Option<RelDef>, model_def: &ModelDef) -> String {
if let Some(ref rel) = rel_def {
match rel.model {
None => model_def.group_name.to_owned(),
Some(ref name) => {
if name.contains(MODEL_NAME_SPLITTER) {
let (group_name, stem_name) = name.split_once(MODEL_NAME_SPLITTER).unwrap();
crate::common::check_name(group_name);
crate::common::check_name(stem_name);
group_name.to_string()
} else {
crate::common::check_name(&model_def.group_name);
model_def.group_name.to_owned()
}
}
}
} else {
model_def.group_name.to_owned()
}
}
}
fn get_model(group_name: Option<&str>, stem_name: &str) -> Arc<ModelDef> {
if let Some(group_name) = group_name {
if let Some(model) = unsafe { GROUPS.get().unwrap() }
.get(group_name)
.unwrap_or_else(|| panic!("{} group is not defined", group_name))
.get(stem_name)
{
return model.clone();
}
let singular_name = to_singular(stem_name);
unsafe { GROUPS.get().unwrap() }
.get(group_name)
.unwrap_or_else(|| panic!("{} group is not defined", group_name))
.get(&singular_name)
.unwrap_or_else(|| panic!("{} model is not defined", stem_name))
.clone()
} else {
if let Some(model) = unsafe { MODELS.get().unwrap() }.get(stem_name) {
return model.clone();
}
let singular_name = to_singular(stem_name);
unsafe { MODELS.get().unwrap() }
.get(&singular_name)
.unwrap_or_else(|| panic!("{} model is not defined", stem_name))
.clone()
}
}
fn get_model_name(group_name: Option<&str>, stem_name: &str) -> (String, String) {
if let Some(group_name) = group_name {
if let Some(model) = unsafe { GROUPS.get().unwrap() }
.get(group_name)
.unwrap_or_else(|| panic!("{} group is not defined", group_name))
.get(stem_name)
{
return (model.mod_name().to_string(), model.name.clone());
}
let singular_name = to_singular(stem_name);
let model = unsafe { GROUPS.get().unwrap() }
.get(group_name)
.unwrap_or_else(|| panic!("{} group is not defined", group_name))
.get(&singular_name)
.unwrap_or_else(|| panic!("{} model is not defined", stem_name));
(model.mod_name().to_string(), model.name.clone())
} else {
if let Some(model) = unsafe { MODELS.get().unwrap() }.get(stem_name) {
return (model.mod_name().to_string(), model.name.clone());
}
let singular_name = to_singular(stem_name);
let model = unsafe { MODELS.get().unwrap() }
.get(&singular_name)
.unwrap_or_else(|| panic!("{} model is not defined", stem_name));
(model.mod_name().to_string(), model.name.clone())
}
}