123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- use std::collections::HashMap;
- use crate::schema::datum::Datum;
- use crate::schema::entity::{Entity, EntityPart, EntityPartList, EntityPartVisitor, EntityVisitor};
- use crate::schema::{DatumDiscriminator, Relation};
- #[derive(Debug)]
- pub enum PartType {
- /// stores sql data type
- Datum(&'static str),
- /// stores the entity name
- IDReference(
- &'static str,
- ),
- AssocDomain {
- table_name: String,
- range_name: &'static str,
- },
- AssocRange {
- table_name: String,
- domain_name: &'static str,
- },
- }
- #[derive(Debug)]
- pub struct PartState {
- pub name: &'static str,
- pub ty: PartType,
- pub unique: bool,
- pub key: bool,
- }
- impl PartState {
- fn build<EP: EntityPart>() -> Self {
- struct Discriminator<EP: EntityPart> {
- ty: Option<PartType>,
- _ghost: std::marker::PhantomData<EP>,
- }
- impl<EP: EntityPart> DatumDiscriminator for Discriminator<EP> {
- fn visit_entity_id<E: Entity>(&mut self) {
- self.ty = Some(PartType::IDReference(E::entity_name()));
- }
- fn visit_bare_field<T: Datum>(&mut self) {
- self.ty = Some(PartType::Datum(T::sql_type()));
- }
- fn visit_serialized<T: serde::Serialize + serde::de::DeserializeOwned>(&mut self) {
- self.ty = Some(PartType::Datum("text"));
- }
- fn visit_assoc_map<E: Entity>(&mut self) {
- self.ty = Some(PartType::AssocDomain {
- table_name: format!(
- "{}_{}_assoc_{}",
- EP::Entity::entity_name(),
- E::entity_name(),
- EP::part_name()
- ),
- range_name: E::entity_name(),
- });
- }
- fn visit_assoc_domain<R: Relation>(&mut self) {
- self.ty = Some(PartType::AssocDomain {
- table_name: format!(
- "{}_{}_assoc_{}",
- R::Domain::entity_name(),
- R::Range::entity_name(),
- R::NAME
- ),
- range_name: R::Range::entity_name(),
- });
- }
- fn visit_assoc_range<R: Relation>(&mut self) {
- self.ty = Some(PartType::AssocRange {
- table_name: format!(
- "{}_{}_assoc_{}",
- R::Domain::entity_name(),
- R::Range::entity_name(),
- R::NAME
- ),
- domain_name: R::Domain::entity_name(),
- });
- }
- }
- let mut discrim = Discriminator::<EP> {
- ty: None,
- _ghost: Default::default(),
- };
- <EP::Datum>::accept_discriminator(&mut discrim);
- if let Some(ty) = discrim.ty {
- PartState {
- name: EP::part_name(),
- ty,
- unique: EP::unique(),
- key: false,
- }
- } else {
- unreachable!("no PartType extracted from EntityPart")
- }
- }
- }
- #[derive(Debug)]
- pub struct EntityState {
- pub name: &'static str,
- typeid: std::any::TypeId,
- pub parts: Vec<PartState>,
- }
- impl EntityState {
- fn build<E: Entity>() -> Self {
- #[derive(Default)]
- struct PartVisitor(Vec<PartState>);
- impl EntityPartVisitor for PartVisitor {
- fn visit<EP: EntityPart>(&mut self) {
- self.0.push(PartState::build::<EP>());
- }
- }
- let mut pv = PartVisitor::default();
- E::accept_part_visitor(&mut pv);
- struct KeyVisitor<'l>(&'l mut Vec<PartState>);
- impl<'l> EntityPartVisitor for KeyVisitor<'l> {
- fn visit<EP: EntityPart>(&mut self) {
- for part in self.0.iter_mut() {
- if part.name == EP::part_name() {
- part.key = true;
- }
- }
- }
- }
- <E::Keys as EntityPartList>::accept_part_visitor(&mut KeyVisitor(&mut pv.0));
- Self {
- name: E::entity_name(),
- typeid: std::any::TypeId::of::<E>(),
- parts: pv.0,
- }
- }
- }
- #[derive(Default, Debug)]
- pub struct EntityStateContainer {
- states: HashMap<&'static str, EntityState>,
- }
- impl EntityStateContainer {
- pub fn iter_states(&self) -> impl Iterator<Item = &EntityState> {
- self.states.values()
- }
- pub fn make_context(&mut self) -> EntityContext {
- EntityContext { container: self }
- }
- }
- pub struct EntityContext<'a> {
- container: &'a mut EntityStateContainer,
- }
- impl<'a> EntityVisitor for EntityContext<'a> {
- fn visit<E: Entity>(&mut self) {
- // three cases:
- // 1. we haven't seen this entity
- // 2. we've seen this entity before
- if self.container.states.contains_key(E::entity_name()) {
- return;
- }
- let entry = self.container.states.entry(E::entity_name());
- let entry = entry.or_insert_with(EntityState::build::<E>);
- // sanity-check
- if entry.typeid != std::any::TypeId::of::<E>() {
- panic!("Identical entity name but different typeid!");
- }
- struct RecursiveVisitor<'a, 'b>(&'a mut EntityContext<'b>);
- impl<'a, 'b> EntityPartVisitor for RecursiveVisitor<'a, 'b> {
- fn visit<EP: EntityPart>(&mut self) {
- EP::Datum::accept_entity_visitor(self.0);
- }
- }
- E::accept_part_visitor(&mut RecursiveVisitor(self));
- }
- }
|