use std::any::TypeId;
use std::borrow::Cow;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct PropertyMeta {
pub field_name: Cow<'static, str>,
pub column_name: Cow<'static, str>,
pub type_id: TypeId,
pub type_name: Cow<'static, str>,
pub is_primary_key: bool,
pub is_auto_increment: bool,
pub is_sequence: bool,
pub sequence_name: Option<Cow<'static, str>>,
pub is_required: bool,
pub is_foreign_key: bool,
pub is_concurrency_token: bool,
pub max_length: Option<usize>,
pub is_unique: bool,
pub has_index: bool,
pub is_not_mapped: bool,
}
pub struct PropertyMetaBuilder {
meta: PropertyMeta,
}
impl PropertyMetaBuilder {
pub fn new(field_name: &'static str, type_id: TypeId, type_name: &'static str) -> Self {
Self {
meta: PropertyMeta {
field_name: Cow::Borrowed(field_name),
column_name: Cow::Borrowed(field_name),
type_id,
type_name: Cow::Borrowed(type_name),
is_primary_key: false,
is_auto_increment: false,
is_sequence: false,
sequence_name: None,
is_required: false,
is_foreign_key: false,
is_concurrency_token: false,
max_length: None,
is_unique: false,
has_index: false,
is_not_mapped: false,
},
}
}
pub fn column_name(mut self, name: &'static str) -> Self {
self.meta.column_name = Cow::Borrowed(name);
self
}
pub fn is_primary_key(mut self, v: bool) -> Self {
self.meta.is_primary_key = v;
self
}
pub fn is_auto_increment(mut self, v: bool) -> Self {
self.meta.is_auto_increment = v;
self
}
pub fn is_sequence(mut self, v: bool) -> Self {
self.meta.is_sequence = v;
self
}
pub fn sequence_name(mut self, name: &'static str) -> Self {
self.meta.sequence_name = Some(Cow::Borrowed(name));
self
}
pub fn is_required(mut self, v: bool) -> Self {
self.meta.is_required = v;
self
}
pub fn is_foreign_key(mut self, v: bool) -> Self {
self.meta.is_foreign_key = v;
self
}
pub fn is_concurrency_token(mut self, v: bool) -> Self {
self.meta.is_concurrency_token = v;
self
}
pub fn max_length(mut self, n: usize) -> Self {
self.meta.max_length = Some(n);
self
}
pub fn is_unique(mut self, v: bool) -> Self {
self.meta.is_unique = v;
self
}
pub fn has_index(mut self, v: bool) -> Self {
self.meta.has_index = v;
self
}
pub fn is_not_mapped(mut self, v: bool) -> Self {
self.meta.is_not_mapped = v;
self
}
pub fn build(self) -> PropertyMeta {
self.meta
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NavigationKind {
BelongsTo,
HasOne,
HasMany,
ManyToMany,
}
#[derive(Debug, Clone)]
pub struct NavigationMeta {
pub field_name: Cow<'static, str>,
pub kind: NavigationKind,
pub related_type_id: TypeId,
pub related_type_name: Cow<'static, str>,
pub foreign_key_field: Option<Cow<'static, str>>,
pub inverse_navigation: Option<Cow<'static, str>>,
pub through_type_id: Option<TypeId>,
pub through_table: Option<Cow<'static, str>>,
pub through_parent_fk: Option<Cow<'static, str>>,
pub through_related_fk: Option<Cow<'static, str>>,
pub through_parent_fk_index: usize,
pub through_related_fk_index: usize,
pub related_table: Option<Cow<'static, str>>,
pub fk_column: Option<Cow<'static, str>>,
pub referenced_key_column: Option<Cow<'static, str>>,
pub fk_row_index: usize,
pub pk_row_index: usize,
pub related_entity_meta: Option<fn() -> EntityTypeMeta>,
pub delete_behavior: Option<crate::relations::DeleteBehavior>,
}
#[derive(Debug, Clone)]
pub struct EntityTypeMeta {
pub type_id: TypeId,
pub type_name: Cow<'static, str>,
pub table_name: Cow<'static, str>,
pub properties: Vec<PropertyMeta>,
pub navigations: Vec<NavigationMeta>,
pub primary_keys: Vec<Cow<'static, str>>,
#[doc(hidden)]
pub property_index: std::sync::OnceLock<HashMap<String, usize>>,
#[doc(hidden)]
pub navigation_index: std::sync::OnceLock<HashMap<String, usize>>,
}
impl EntityTypeMeta {
pub fn find_property(&self, field_name: &str) -> Option<&PropertyMeta> {
let idx = self
.property_index
.get_or_init(|| {
self.properties
.iter()
.enumerate()
.map(|(i, p)| (p.field_name.to_string(), i))
.collect()
})
.get(field_name)
.copied();
idx.and_then(|i| self.properties.get(i))
}
pub fn find_navigation(&self, field_name: &str) -> Option<&NavigationMeta> {
let idx = self
.navigation_index
.get_or_init(|| {
self.navigations
.iter()
.enumerate()
.map(|(i, n)| (n.field_name.to_string(), i))
.collect()
})
.get(field_name)
.copied();
idx.and_then(|i| self.navigations.get(i))
}
pub fn primary_key_property(&self) -> Option<&PropertyMeta> {
self.properties.iter().find(|p| p.is_primary_key)
}
pub fn mapped_scalar_properties(&self) -> impl Iterator<Item = &PropertyMeta> {
self.properties.iter().filter(|p| !p.is_not_mapped)
}
}
impl Default for EntityTypeMeta {
fn default() -> Self {
Self {
type_id: TypeId::of::<()>(),
type_name: Cow::Borrowed(""),
table_name: Cow::Borrowed(""),
properties: Vec::new(),
navigations: Vec::new(),
primary_keys: Vec::new(),
property_index: std::sync::OnceLock::new(),
navigation_index: std::sync::OnceLock::new(),
}
}
}