use std::sync::Arc;
use super::item::AnyItem;
pub type FkExtractor = fn(&dyn std::any::Any) -> Option<Arc<str>>;
pub type ArrayExtractor = fn(&dyn std::any::Any) -> Option<Vec<Arc<str>>>;
pub type ArrayRemover = fn(&dyn std::any::Any, &str) -> Option<Arc<dyn AnyItem>>;
pub type EntityFactory = fn(&[Arc<str>]) -> Arc<dyn AnyItem>;
#[derive(Clone)]
pub enum Relation {
BelongsTo {
local_type: &'static str,
foreign_type: &'static str,
fk_field_json: &'static str,
extract_fk: FkExtractor,
exclude_from_tree: bool,
},
OwnsMany {
local_type: &'static str,
foreign_type: &'static str,
extract_ids: ArrayExtractor,
remove_id: ArrayRemover,
exclude_from_tree: bool,
},
EnsureFor {
local_type: &'static str,
dependencies: &'static [EnsureForDependency],
make_entity: EntityFactory,
exclude_from_tree: bool,
},
}
impl std::fmt::Debug for Relation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Relation::BelongsTo {
local_type,
foreign_type,
..
} => f
.debug_struct("BelongsTo")
.field("local_type", local_type)
.field("foreign_type", foreign_type)
.finish(),
Relation::OwnsMany {
local_type,
foreign_type,
..
} => f
.debug_struct("OwnsMany")
.field("local_type", local_type)
.field("foreign_type", foreign_type)
.finish(),
Relation::EnsureFor {
local_type,
dependencies,
..
} => f
.debug_struct("EnsureFor")
.field("local_type", local_type)
.field("dependencies", dependencies)
.finish(),
}
}
}
#[derive(Clone, Copy)]
pub struct EnsureForDependency {
pub foreign_type: &'static str,
pub extract_fk: FkExtractor,
}
impl std::fmt::Debug for EnsureForDependency {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EnsureForDependency")
.field("foreign_type", &self.foreign_type)
.finish()
}
}
pub struct RelationRegistration {
pub relation: Relation,
}
inventory::collect!(RelationRegistration);
pub fn iter_relations() -> impl Iterator<Item = &'static RelationRegistration> {
inventory::iter::<RelationRegistration>()
}
pub struct ClientIdRegistration {
pub entity_type: &'static str,
pub field_name_json: &'static str,
}
inventory::collect!(ClientIdRegistration);
pub fn iter_client_id_registrations() -> impl Iterator<Item = &'static ClientIdRegistration> {
inventory::iter::<ClientIdRegistration>()
}
pub struct ServerOwnedRegistration {
pub entity_type: &'static str,
pub field_name_json: &'static str,
}
inventory::collect!(ServerOwnedRegistration);
pub fn iter_server_owned_registrations() -> impl Iterator<Item = &'static ServerOwnedRegistration> {
inventory::iter::<ServerOwnedRegistration>()
}
pub struct FallbackToIdRegistration {
pub entity_type: &'static str,
pub field_name_json: &'static str,
}
inventory::collect!(FallbackToIdRegistration);
pub fn iter_fallback_to_id_registrations() -> impl Iterator<Item = &'static FallbackToIdRegistration>
{
inventory::iter::<FallbackToIdRegistration>()
}
#[cfg(test)]
mod tests {
use super::*;
fn dummy_fk_extractor(_: &dyn std::any::Any) -> Option<Arc<str>> {
None
}
fn dummy_array_extractor(_: &dyn std::any::Any) -> Option<Vec<Arc<str>>> {
None
}
fn dummy_array_remover(_: &dyn std::any::Any, _: &str) -> Option<Arc<dyn AnyItem>> {
None
}
#[test]
fn test_relation_variants() {
let belongs_to = Relation::BelongsTo {
local_type: "Binding",
foreign_type: "Scene",
fk_field_json: "scopeId",
extract_fk: dummy_fk_extractor,
exclude_from_tree: false,
};
let owns_many = Relation::OwnsMany {
local_type: "Scene",
foreign_type: "BindingNode",
extract_ids: dummy_array_extractor,
remove_id: dummy_array_remover,
exclude_from_tree: false,
};
match belongs_to {
Relation::BelongsTo { foreign_type, .. } => {
assert_eq!(foreign_type, "Scene");
}
_ => panic!("Expected BelongsTo"),
}
match owns_many {
Relation::OwnsMany { foreign_type, .. } => {
assert_eq!(foreign_type, "BindingNode");
}
_ => panic!("Expected OwnsMany"),
}
}
}