Procházet zdrojové kódy

Implemented Insertable and Queryable for additional types to be more flexible.

Kestrel před 7 měsíci
rodič
revize
885e0406e7

+ 10 - 14
microrm/src/cli.rs

@@ -62,8 +62,7 @@ pub trait EntityInterface {
     fn run_custom(
         ctx: &Self::Context,
         cmd: Self::CustomCommand,
-        query_ctx: impl Queryable<EntityOutput = Self::Entity>,
-        insert_ctx: &impl Insertable<Self::Entity>,
+        query_ctx: impl Queryable<EntityOutput = Self::Entity> + Insertable<Self::Entity>,
     ) -> Result<(), Self::Error>;
 
     /// Provide a summary of the entity, ideally a string with no newlines that can identify the
@@ -199,12 +198,11 @@ mod tests {
         fn run_custom(
             _ctx: &Self::Context,
             cmd: Self::CustomCommand,
-            _query_ctx: impl Queryable<EntityOutput = Self::Entity>,
-            insert_ctx: &impl Insertable<Self::Entity>,
+            query_ctx: impl Queryable<EntityOutput = Self::Entity> + Insertable<Self::Entity>,
         ) -> Result<(), Self::Error> {
             match cmd {
                 CCustom::Create { name } => {
-                    insert_ctx.insert(Customer {
+                    query_ctx.insert(Customer {
                         name,
                         txs: Default::default(),
                     })?;
@@ -230,12 +228,11 @@ mod tests {
         fn run_custom(
             _ctx: &Self::Context,
             cmd: Self::CustomCommand,
-            _query_ctx: impl Queryable<EntityOutput = Self::Entity>,
-            insert_ctx: &impl Insertable<Self::Entity>,
+            query_ctx: impl Queryable<EntityOutput = Self::Entity> + Insertable<Self::Entity>,
         ) -> Result<(), Self::Error> {
             match cmd {
                 ECustom::Create { name } => {
-                    insert_ctx.insert(Employee {
+                    query_ctx.insert(Employee {
                         name,
                         txs: Default::default(),
                     })?;
@@ -261,12 +258,11 @@ mod tests {
         fn run_custom(
             _ctx: &Self::Context,
             cmd: Self::CustomCommand,
-            _query_ctx: impl Queryable<EntityOutput = Self::Entity>,
-            insert_ctx: &impl Insertable<Self::Entity>,
+            query_ctx: impl Queryable<EntityOutput = Self::Entity> + Insertable<Self::Entity>,
         ) -> Result<(), Self::Error> {
             match cmd {
                 TCustom::Create { title, amount } => {
-                    insert_ctx.insert(Transaction {
+                    query_ctx.insert(Transaction {
                         title,
                         amount,
                         customer: Default::default(),
@@ -297,15 +293,15 @@ mod tests {
     fn run_cmd(db: &TransactionTestDB, args: &[&str]) {
         match <Params as Parser>::try_parse_from(args) {
             Ok(Params::Customer { cmd }) => {
-                cmd.perform(&(), &db.customers, &db.customers)
+                cmd.perform(&(), &db.customers)
                     .expect("couldn't perform command");
             },
             Ok(Params::Employee { cmd }) => {
-                cmd.perform(&(), &db.employees, &db.employees)
+                cmd.perform(&(), &db.employees)
                     .expect("couldn't perform command");
             },
             Ok(Params::Tx { cmd }) => {
-                cmd.perform(&(), &db.transactions, &db.transactions)
+                cmd.perform(&(), &db.transactions)
                     .expect("couldn't perform command");
             },
             Err(e) => {

+ 2 - 3
microrm/src/cli/eval.rs

@@ -19,8 +19,7 @@ impl<EI: EntityInterface> Autogenerate<EI> {
     pub fn perform(
         self,
         ctx: &EI::Context,
-        query_ctx: impl Queryable<EntityOutput = EI::Entity>,
-        insert_ctx: &impl Insertable<EI::Entity>,
+        query_ctx: impl Queryable<EntityOutput = EI::Entity> + Insertable<EI::Entity>,
     ) -> Result<(), EI::Error> {
         match self.verb {
             Verb::Attach {
@@ -186,7 +185,7 @@ impl<EI: EntityInterface> Autogenerate<EI> {
                 obj.accept_part_visitor_ref(&mut RelationFieldWalker(Default::default()));
             },
             Verb::Custom(custom) => {
-                EI::run_custom(ctx, custom, query_ctx, insert_ctx)?;
+                EI::run_custom(ctx, custom, query_ctx)?;
             },
         }
 

+ 4 - 2
microrm/src/query.rs

@@ -190,9 +190,11 @@ fn hash_of<T: Hash>(val: T) -> u64 {
 }
 
 /// Relation map generic interface trait.
-pub trait RelationInterface: 'static {
+pub trait RelationInterface {
     /// The type of the entity on the non-local end of the relation.
     type RemoteEntity: Entity;
+    /// A static version of the current interface, used for type-based query caching.
+    type StaticVersion: RelationInterface + 'static;
 
     #[doc(hidden)]
     fn get_data(&self) -> DBResult<&RelationData>;
@@ -578,7 +580,7 @@ impl<'a, T: Entity> Queryable for &'a IDMap<T> {
 impl<'a, AI: RelationInterface> Queryable for &'a AI {
     type EntityOutput = AI::RemoteEntity;
     type OutputContainer = Vec<Stored<AI::RemoteEntity>>;
-    type StaticVersion = &'static AI;
+    type StaticVersion = &'static AI::StaticVersion;
 
     fn build(&self) -> Query {
         let anames = RelationNames::collect(*self).unwrap();

+ 10 - 1
microrm/src/schema.rs

@@ -245,7 +245,6 @@ impl<T: Entity> IDMap<T> {
 }
 
 impl<T: Entity> Insertable<T> for IDMap<T> {
-    /// Insert a new Entity into this map, and return its new ID.
     fn insert(&self, value: T) -> DBResult<T::ID> {
         let txn = Transaction::new(self.conn())?;
         let out = query::base_queries::insert(self.conn(), &value)?;
@@ -261,6 +260,16 @@ impl<T: Entity> Insertable<T> for IDMap<T> {
     }
 }
 
+impl<'l, T: Entity> Insertable<T> for &'l IDMap<T> {
+    fn insert(&self, value: T) -> DBResult<T::ID> {
+        <IDMap<T> as Insertable<T>>::insert(self, value)
+    }
+
+    fn insert_and_return(&self, value: T) -> DBResult<Stored<T>> {
+        <IDMap<T> as Insertable<T>>::insert_and_return(self, value)
+    }
+}
+
 impl<E: Entity> DatabaseItem for IDMap<E> {
     fn accept_item_visitor(visitor: &mut impl DatabaseItemVisitor) {
         visitor.visit_idmap::<E>();

+ 45 - 0
microrm/src/schema/relation.rs

@@ -86,6 +86,7 @@ impl<T: Entity> Default for RelationMap<T> {
 
 impl<T: Entity> RelationInterface for RelationMap<T> {
     type RemoteEntity = T;
+    type StaticVersion = Self;
     const SIDE: LocalSide = LocalSide::Domain;
 
     fn get_distinguishing_name(&self) -> DBResult<&'static str> {
@@ -104,6 +105,20 @@ impl<T: Entity> RelationInterface for RelationMap<T> {
     }
 }
 
+impl<'l, T: Entity> RelationInterface for &'l RelationMap<T> {
+    type RemoteEntity = T;
+    type StaticVersion = RelationMap<T>;
+    const SIDE: LocalSide = LocalSide::Domain;
+
+    fn get_distinguishing_name(&self) -> DBResult<&'static str> {
+        <RelationMap<T> as RelationInterface>::get_distinguishing_name(self)
+    }
+
+    fn get_data(&self) -> DBResult<&RelationData> {
+        <RelationMap<T> as RelationInterface>::get_data(self)
+    }
+}
+
 impl<T: Entity> Datum for RelationMap<T> {
     fn sql_type() -> &'static str {
         unreachable!()
@@ -188,6 +203,7 @@ impl<R: Relation> std::fmt::Debug for RelationDomain<R> {
 
 impl<R: Relation> RelationInterface for RelationDomain<R> {
     type RemoteEntity = R::Range;
+    type StaticVersion = Self;
     const SIDE: LocalSide = LocalSide::Domain;
 
     fn get_distinguishing_name(&self) -> DBResult<&'static str> {
@@ -201,6 +217,20 @@ impl<R: Relation> RelationInterface for RelationDomain<R> {
     }
 }
 
+impl<'l, R: Relation> RelationInterface for &'l RelationDomain<R> {
+    type RemoteEntity = R::Range;
+    type StaticVersion = RelationDomain<R>;
+    const SIDE: LocalSide = LocalSide::Domain;
+
+    fn get_distinguishing_name(&self) -> DBResult<&'static str> {
+        <RelationDomain<R> as RelationInterface>::get_distinguishing_name(self)
+    }
+
+    fn get_data(&self) -> DBResult<&RelationData> {
+        <RelationDomain<R> as RelationInterface>::get_data(self)
+    }
+}
+
 impl<R: Relation> Datum for RelationDomain<R> {
     fn sql_type() -> &'static str {
         unreachable!()
@@ -285,6 +315,7 @@ impl<R: Relation> std::fmt::Debug for RelationRange<R> {
 
 impl<R: Relation> RelationInterface for RelationRange<R> {
     type RemoteEntity = R::Domain;
+    type StaticVersion = Self;
     const SIDE: LocalSide = LocalSide::Range;
 
     fn get_distinguishing_name(&self) -> DBResult<&'static str> {
@@ -298,6 +329,20 @@ impl<R: Relation> RelationInterface for RelationRange<R> {
     }
 }
 
+impl<'l, R: Relation> RelationInterface for &'l RelationRange<R> {
+    type RemoteEntity = R::Domain;
+    type StaticVersion = RelationRange<R>;
+    const SIDE: LocalSide = LocalSide::Range;
+
+    fn get_distinguishing_name(&self) -> DBResult<&'static str> {
+        <RelationRange<R> as RelationInterface>::get_distinguishing_name(self)
+    }
+
+    fn get_data(&self) -> DBResult<&RelationData> {
+        <RelationRange<R> as RelationInterface>::get_data(self)
+    }
+}
+
 impl<R: Relation> Datum for RelationRange<R> {
     fn sql_type() -> &'static str {
         unreachable!()