Przeglądaj źródła

Changed EntityPartList to force all parts to have the same Entity type.

Kestrel 7 miesięcy temu
rodzic
commit
1b857e7b78

+ 1 - 1
microrm-macros/src/entity.rs

@@ -60,7 +60,7 @@ pub fn derive(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
     };
 
     let make_part_list = |plist: &Vec<_>| match plist.len() {
-        0 => quote! { () },
+        0 => quote! { microrm::schema::entity::EmptyList<Self> },
         1 => {
             let ty = make_combined_name(plist.first().as_ref().unwrap());
             quote! { #ty }

+ 16 - 5
microrm/src/query/components.rs

@@ -7,7 +7,7 @@ use crate::{
     schema::{
         datum::{Datum, DatumDiscriminator, DatumVisitor, QueryEquivalent, QueryEquivalentList},
         entity::{Entity, EntityPart, EntityPartList, EntityPartVisitor},
-        Stored,
+        LocalSide, Stored,
     },
 };
 
@@ -361,10 +361,21 @@ impl<
 
         let (local_field, remote_field) = d.0.unwrap();
 
-        let assoc_name = format!(
-            "{local_name}_{remote_name}_assoc_{}",
-            d.1.unwrap_or(EP::part_name())
-        );
+        // table name format is {domain}_{range}_assoc_{name}
+        let assoc_name = match AI::SIDE {
+            LocalSide::Range => {
+                format!(
+                    "{remote_name}_{local_name}_assoc_{}",
+                    d.1.unwrap_or(EP::part_name())
+                )
+            }
+            LocalSide::Domain => {
+                format!(
+                    "{local_name}_{remote_name}_assoc_{}",
+                    d.1.unwrap_or(EP::part_name())
+                )
+            }
+        };
 
         self.parent
             .build()

+ 1 - 0
microrm/src/schema.rs

@@ -123,6 +123,7 @@ pub trait Relation: 'static {
     const NAME: &'static str;
 }
 
+#[derive(Debug)]
 pub enum LocalSide {
     Domain,
     Range,

+ 7 - 0
microrm/src/schema/entity.rs

@@ -47,8 +47,13 @@ pub trait EntityPartVisitor {
 
 /// List of EntityParts.
 pub trait EntityPartList: 'static {
+    type Entity: Entity;
     type DatumList: ConcreteDatumList + QueryEquivalentList<Self::DatumList>;
 
+    type ListHead: EntityPart;
+    type ListTail: EntityPartList<Entity = Self::Entity>;
+    const IS_EMPTY: bool = false;
+
     fn build_datum_list(conn: &Connection, stmt: &mut StatementRow) -> DBResult<Self::DatumList>;
 
     fn accept_part_visitor(_: &mut impl EntityPartVisitor);
@@ -58,6 +63,8 @@ pub trait EntityPartList: 'static {
 // trait implementations for EntityPartList
 mod part_list;
 
+pub use part_list::EmptyList;
+
 // ----------------------------------------------------------------------
 // Entity and related types
 // ----------------------------------------------------------------------

+ 73 - 7
microrm/src/schema/entity/part_list.rs

@@ -21,9 +21,60 @@ macro_rules! build_datum {
     };
 }
 
-impl EntityPartList for () {
+pub struct MarkerPart<E: Entity> {
+    _ghost: std::marker::PhantomData<E>,
+}
+
+impl<E: Entity> Default for MarkerPart<E> {
+    fn default() -> Self {
+        Self {
+            _ghost: Default::default(),
+        }
+    }
+}
+
+impl<E: Entity> Clone for MarkerPart<E> {
+    fn clone(&self) -> Self {
+        Self::default()
+    }
+}
+
+impl<E: Entity> EntityPart for MarkerPart<E> {
+    type Entity = E;
+    type Datum = usize;
+
+    fn desc() -> Option<&'static str> {
+        None
+    }
+    fn unique() -> bool {
+        false
+    }
+    fn part_name() -> &'static str {
+        "marker"
+    }
+    fn get_datum(_from: &Self::Entity) -> &Self::Datum {
+        unreachable!()
+    }
+    fn placeholder() -> &'static str {
+        "MarkerPart"
+    }
+}
+
+/// Empty list of entity parts. Since [`EntityPartList`] requires an associated [`Entity`], a
+/// simple unit type is insufficient.
+#[derive(Debug, Default)]
+pub struct EmptyList<E: Entity> {
+    _ghost: std::marker::PhantomData<E>,
+}
+
+impl<E: Entity> EntityPartList for EmptyList<E> {
+    type Entity = E;
     type DatumList = ();
 
+    type ListHead = MarkerPart<E>;
+    type ListTail = EmptyList<E>;
+    const IS_EMPTY: bool = true;
+
     fn build_datum_list(_conn: &Connection, _stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
         Ok(())
     }
@@ -32,9 +83,13 @@ impl EntityPartList for () {
     fn accept_part_visitor_ref(_: &Self::DatumList, _: &mut impl EntityPartVisitor) {}
 }
 
-impl<P0: EntityPart> EntityPartList for P0 {
+impl<E: Entity, P0: EntityPart<Entity = E>> EntityPartList for P0 {
+    type Entity = E;
     type DatumList = P0::Datum;
 
+    type ListHead = P0;
+    type ListTail = EmptyList<E>;
+
     fn build_datum_list(conn: &Connection, stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
         let local_id: i64 = stmt.read(0)?;
         let mut idx = 1; // starting index is 1 since index 0 is the ID
@@ -51,9 +106,13 @@ impl<P0: EntityPart> EntityPartList for P0 {
     }
 }
 
-impl<P0: EntityPart> EntityPartList for (P0,) {
+impl<E: Entity, P0: EntityPart<Entity = E>> EntityPartList for (P0,) {
+    type Entity = E;
     type DatumList = P0::Datum;
 
+    type ListHead = P0;
+    type ListTail = EmptyList<E>;
+
     fn build_datum_list(conn: &Connection, stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
         <P0 as EntityPartList>::build_datum_list(conn, stmt)
     }
@@ -67,27 +126,34 @@ impl<P0: EntityPart> EntityPartList for (P0,) {
 }
 
 macro_rules! part_list_impl {
-    ($($p:ident : $d:ident : $n:tt),+) => {
-        impl< $( $p : EntityPart ),* > EntityPartList for ( $($p),* ) {
-            type DatumList = ( $( $p :: Datum ),* );
+    ($p0:ident : $d0:ident : $n0:tt, $($p:ident : $d:ident : $n:tt),+) => {
+        impl<E: Entity, $p0 : EntityPart<Entity = E>, $( $p : EntityPart<Entity = E> ),* > EntityPartList for ( $p0, $($p),* ) {
+            type Entity = E;
+            type DatumList = ( $p0 :: Datum, $( $p :: Datum ),* );
+
+            type ListHead = $p0;
+            type ListTail = ( $( $p ),* , );
 
             fn build_datum_list(conn: &Connection, stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
                 let local_id: i64 = stmt.read(0)?;
                 let mut idx = 1;
+                build_datum!(conn, local_id, stmt, idx, $d0, $p0);
                 $(
                     build_datum!(conn, local_id, stmt, idx, $d, $p);
                 )*
 
-                Ok(( $( $d ),* ))
+                Ok(( $d0, $( $d ),* ))
             }
 
             fn accept_part_visitor(v: &mut impl EntityPartVisitor) {
+                v.visit::< $p0 >();
                 $(
                     v.visit::< $p >();
                 )*
             }
 
             fn accept_part_visitor_ref(datum_list: &Self::DatumList, v: &mut impl EntityPartVisitor) {
+                v.visit_datum::< $p0 >(&datum_list . $n0);
                 $(
                     v.visit_datum::< $p >(&datum_list . $n);
                 )*