Parcourir la source

Revert "Add lease-carrier support to Queryable."

Lease-carrier support is useful but for the moment, an unnecessary
complication.
Kestrel il y a 1 semaine
Parent
commit
43638d3bb6

+ 1 - 6
microrm/src/glue.rs

@@ -2,7 +2,7 @@
 
 use crate::{
     db::{ConnectionLease, StatementContext, Transaction},
-    query::{self, Insertable, Query, QueryPart, QueryVerbs, Queryable, RelationInterface},
+    query::{self, Insertable, Query, QueryPart, Queryable, RelationInterface},
     schema::{
         entity::Entity,
         relation::{LocalSide, Relation, RelationData, RelationDomain, RelationMap, RelationRange},
@@ -39,14 +39,9 @@ impl<'a, T: Entity> Queryable for &'a IDMap<T> {
     type EntityOutput = T;
     type OutputContainer = Vec<Stored<T>>;
     type StaticVersion = &'static IDMap<T>;
-    type Carrier = ();
 
     const IS_UNIQUE: bool = false;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
     fn build(&self) -> Query {
         Query::new()
             .attach(QueryPart::Root, "SELECT DISTINCT")

+ 1 - 3
microrm/src/lib.rs

@@ -246,9 +246,7 @@ pub mod cli;
 
 /// Re-exported traits and macros for easy access.
 pub mod prelude {
-    pub use crate::query::{
-        CarrierQueryVerbs, Insertable, QueryVerbs, Queryable, RelationInterface,
-    };
+    pub use crate::query::{Insertable, Queryable, RelationInterface};
     pub use crate::schema::{relation::Relation, Schema, Serializable};
     pub use microrm_macros::{Entity, Schema, Value};
 }

+ 124 - 241
microrm/src/query.rs

@@ -339,17 +339,14 @@ impl<AI: RelationInterface> Insertable<AI::RemoteEntity> for AI {
     }
 }
 
-/// Represents a searchable context of a given entity. See [`QueryVerbs`] for query verbs.
-pub trait Queryable {
+/// Represents a searchable context of a given entity.
+pub trait Queryable: Clone {
     /// The entity that results from a search in this context.
     type EntityOutput: Entity;
     /// How results will be provided. This is either a `Vec` or an `Option`.
     type OutputContainer: OutputContainer<Self::EntityOutput>;
     /// A `'static`-version of `Self`, used for `TypeId`-based caching.
     type StaticVersion: Queryable + 'static;
-    /// A possible tag-along type stored in the query object. See [`Self::carry_lease`] for one
-    /// use.
-    type Carrier;
 
     /// True if the query result is guaranteed to be either unique or absent.
     const IS_UNIQUE: bool;
@@ -361,202 +358,9 @@ pub trait Queryable {
     #[doc(hidden)]
     fn bind(&self, stmt: &mut StatementContext, index: &mut i32);
 
-    #[doc(hidden)]
-    fn carried(&mut self) -> &mut Self::Carrier;
-
-    /// Construct a new [`Queryable`] that carries a connection lease along with it.
-    ///
-    /// This allows the use of the [`CarrierQueryVerbs`] trait instead of the [`QueryVerbs`] trait,
-    /// which reduces the number of objects that need be passed around.
-    fn carry_lease<'r, 'l: 'r>(
-        self,
-        lease: &'r mut ConnectionLease<'l>,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Self::OutputContainer,
-        Carrier = Option<&'r mut ConnectionLease<'l>>,
-    >
-    where
-        Self: Sized,
-    {
-        components::LeaseCarrierComponent::new(self, lease)
-    }
-
-    // Verbs are now implemented in [`QueryVerbs`]
-
-    // ----------------------------------------------------------------------
-    // Filtering methods
-    // ----------------------------------------------------------------------
-    /// Filter using the keying index on the entity.
-    fn keyed(
-        self,
-        values: impl QueryEquivalentList<
-            <<Self::EntityOutput as Entity>::Keys as EntityPartList>::DatumList,
-        >,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Option<Stored<Self::EntityOutput>>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        components::IndexComponent::<_, _, <Self::EntityOutput as Entity>::Keys, _>::new(
-            self, values,
-        )
-    }
-
-    /// Filter using an arbitrary index on the entity.
-    fn indexed<EPL: EntityPartList<Entity = Self::EntityOutput>>(
-        self,
-        _index: &Index<Self::EntityOutput, EPL>,
-        values: impl QueryEquivalentList<EPL::DatumList>,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Option<Stored<Self::EntityOutput>>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        components::IndexComponent::<_, _, EPL, _>::new(self, values)
-    }
-
-    /// Filter using an arbitrary column on the entity.
-    fn with<EP: EntityPart<Entity = Self::EntityOutput>>(
-        self,
-        part: EP,
-        value: impl QueryEquivalent<EP::Datum>,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Self::OutputContainer,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        components::WithComponent::new(self, part, value)
-    }
-
-    /// Filter exactly on an entity ID.
-    fn with_id(
-        self,
-        id: <Self::EntityOutput as Entity>::ID,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Option<Stored<Self::EntityOutput>>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        self.with(<Self::EntityOutput as Entity>::IDPart::default(), id)
-            .first()
-    }
-
-    /// Ask to return at most a single result.
-    fn first(
-        self,
-    ) -> impl Queryable<
-        EntityOutput = Self::EntityOutput,
-        OutputContainer = Option<Stored<Self::EntityOutput>>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        components::SingleComponent::new(self)
-    }
-
     // ----------------------------------------------------------------------
-    // Relation-following and joining methods
+    // Verbs
     // ----------------------------------------------------------------------
-    /// Join based on an existing relation.
-    fn join<
-        AD: RelationInterface + Datum,
-        EP: EntityPart<Entity = Self::EntityOutput, Datum = AD>,
-    >(
-        self,
-        part: EP,
-    ) -> impl Queryable<
-        EntityOutput = AD::RemoteEntity,
-        OutputContainer = Vec<Stored<AD::RemoteEntity>>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-    {
-        components::JoinComponent::<AD::RemoteEntity, Self::EntityOutput, _, Self>::new(self, part)
-    }
-
-    /// Follow a foreign key.
-    fn foreign<EP: EntityPart<Entity = Self::EntityOutput>>(
-        self,
-        part: EP,
-    ) -> impl Queryable<
-        EntityOutput = <EP::Datum as EntityID>::Entity,
-        OutputContainer = <Self::OutputContainer as OutputContainer<
-            Self::EntityOutput,
-        >>::ReplacedEntity<<EP::Datum as EntityID>::Entity>,
-        Carrier = Self::Carrier,
-    >
-    where
-        Self: Sized,
-        EP::Datum: EntityID,
-    {
-        components::ForeignComponent::<_, EP, Self>::new(self, part)
-    }
-}
-
-// Generic implementation for all relation specification types
-impl<'a, AI: RelationInterface> Queryable for &'a AI {
-    type EntityOutput = AI::RemoteEntity;
-    type OutputContainer = Vec<Stored<AI::RemoteEntity>>;
-    type StaticVersion = &'static AI::StaticVersion;
-    type Carrier = ();
-
-    const IS_UNIQUE: bool = false;
-
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
-    fn build(&self) -> Query {
-        let anames = RelationNames::collect(*self).unwrap();
-        let relation_name = anames.relation_name();
-        Query::new()
-            .attach(QueryPart::Root, "SELECT DISTINCT")
-            .attach(QueryPart::Columns, format!("`{}`.*", anames.remote_name))
-            .attach(QueryPart::From, format!("`{}`", relation_name))
-            .attach(
-                QueryPart::Join,
-                format!(
-                    "`{}` ON `{}`.`id` = `{}`.`{}`",
-                    anames.remote_name, anames.remote_name, relation_name, anames.remote_field
-                ),
-            )
-            .attach(
-                QueryPart::Where,
-                format!("`{}`.`{}` = ?", relation_name, anames.local_field),
-            )
-    }
-    fn bind(&self, ctx: &mut StatementContext, index: &mut i32) {
-        let rdata = self
-            .get_data()
-            .expect("binding query for relation with no data");
-
-        ctx.bind(*index, rdata.local_id)
-            .expect("couldn't bind relation id");
-        *index += 1;
-    }
-}
-
-// ----------------------------------------------------------------------
-// Verb traits
-// ----------------------------------------------------------------------
-
-/// Completion verbs for a [`Queryable`] object.
-pub trait QueryVerbs: Queryable<Carrier = ()> {
     /// Count all entities in the current context.
     ///
     /// Returns the number of entities.
@@ -679,7 +483,8 @@ pub trait QueryVerbs: Queryable<Carrier = ()> {
         )?;
         txn.commit()
     }
-    /// Delete all entities in the current context and return them.
+
+    /// Delete all entities in the current context and return them
     fn remove(self, lease: &mut ConnectionLease) -> DBResult<Self::OutputContainer>
     where
         Self: Sized,
@@ -712,72 +517,155 @@ pub trait QueryVerbs: Queryable<Carrier = ()> {
         txn.commit()?;
         Ok(out)
     }
-}
 
-impl<T: Queryable<Carrier = ()>> QueryVerbs for T {}
+    // ----------------------------------------------------------------------
+    // Filtering methods
+    // ----------------------------------------------------------------------
+    /// Filter using the keying index on the entity.
+    fn keyed(
+        self,
+        values: impl QueryEquivalentList<
+            <<Self::EntityOutput as Entity>::Keys as EntityPartList>::DatumList,
+        >,
+    ) -> impl Queryable<
+        EntityOutput = Self::EntityOutput,
+        OutputContainer = Option<Stored<Self::EntityOutput>>,
+    >
+    where
+        Self: Sized,
+    {
+        components::IndexComponent::<_, _, <Self::EntityOutput as Entity>::Keys, _>::new(
+            self, values,
+        )
+    }
 
-/// Completion verbs for a [`Queryable`] object that carries a [`ConnectionLease`].
-pub trait CarrierQueryVerbs<'r, 'l: 'r>:
-    Queryable<Carrier = components::LeaseCarrier<'r, 'l>>
-{
-    /// Count all entities in the current context.
-    ///
-    /// Returns the number of entities.
-    fn count(self) -> DBResult<usize>
+    /// Filter using an arbitrary index on the entity.
+    fn indexed<EPL: EntityPartList<Entity = Self::EntityOutput>>(
+        self,
+        _index: &Index<Self::EntityOutput, EPL>,
+        values: impl QueryEquivalentList<EPL::DatumList>,
+    ) -> impl Queryable<
+        EntityOutput = Self::EntityOutput,
+        OutputContainer = Option<Stored<Self::EntityOutput>>,
+    >
     where
         Self: Sized,
     {
-        let (query, lease) = components::ExtractLeaseComponent::new(self);
-        query.count(lease)
+        components::IndexComponent::<_, _, EPL, _>::new(self, values)
     }
 
-    /// Get all entities in the current context.
-    fn get(self) -> DBResult<Self::OutputContainer>
+    /// Filter using an arbitrary column on the entity.
+    fn with<EP: EntityPart<Entity = Self::EntityOutput>>(
+        self,
+        part: EP,
+        value: impl QueryEquivalent<EP::Datum>,
+    ) -> impl Queryable<EntityOutput = Self::EntityOutput, OutputContainer = Self::OutputContainer>
     where
         Self: Sized,
     {
-        let (query, lease) = components::ExtractLeaseComponent::new(self);
-        query.get(lease)
+        components::WithComponent::new(self, part, value)
     }
 
-    /// Get IDs of all entities in the current context.
-    fn get_ids(
+    /// Filter exactly on an entity ID.
+    fn with_id(
         self,
-    ) -> DBResult<<Self::OutputContainer as OutputContainer<Self::EntityOutput>>::IDContainer>
+        id: <Self::EntityOutput as Entity>::ID,
+    ) -> impl Queryable<
+        EntityOutput = Self::EntityOutput,
+        OutputContainer = Option<Stored<Self::EntityOutput>>,
+    >
     where
         Self: Sized,
     {
-        let (query, lease) = components::ExtractLeaseComponent::new(self);
-        query.get_ids(lease)
+        self.with(<Self::EntityOutput as Entity>::IDPart::default(), id)
+            .first()
     }
 
-    /// Delete all entities in the current context.
-    fn delete(self) -> DBResult<()>
+    /// Ask to return at most a single result.
+    fn first(
+        self,
+    ) -> impl Queryable<
+        EntityOutput = Self::EntityOutput,
+        OutputContainer = Option<Stored<Self::EntityOutput>>,
+    >
     where
         Self: Sized,
     {
-        let (query, lease) = components::ExtractLeaseComponent::new(self);
-        query.delete(lease)
+        components::SingleComponent::new(self)
     }
 
-    /// Delete all entities in the current context and return them.
-    fn remove(self) -> DBResult<Self::OutputContainer>
+    // ----------------------------------------------------------------------
+    // Relation-following and joining methods
+    // ----------------------------------------------------------------------
+    /// Join based on an existing relation.
+    fn join<
+        AD: RelationInterface + Datum,
+        EP: EntityPart<Entity = Self::EntityOutput, Datum = AD>,
+    >(
+        self,
+        part: EP,
+    ) -> impl Queryable<EntityOutput = AD::RemoteEntity, OutputContainer = Vec<Stored<AD::RemoteEntity>>>
     where
         Self: Sized,
     {
-        let (query, lease) = components::ExtractLeaseComponent::new(self);
-        query.remove(lease)
+        components::JoinComponent::<AD::RemoteEntity, Self::EntityOutput, _, Self>::new(self, part)
     }
-}
 
-impl<'r, 'l: 'r, T: Queryable<Carrier = components::LeaseCarrier<'r, 'l>>> CarrierQueryVerbs<'r, 'l>
-    for T
-{
+    /// Follow a foreign key.
+    fn foreign<EP: EntityPart<Entity = Self::EntityOutput>>(
+        self,
+        part: EP,
+    ) -> impl Queryable<
+        EntityOutput = <EP::Datum as EntityID>::Entity,
+        OutputContainer = <Self::OutputContainer as OutputContainer<
+            Self::EntityOutput,
+        >>::ReplacedEntity<<EP::Datum as EntityID>::Entity>,
+    >
+    where
+        Self: Sized,
+        EP::Datum: EntityID,
+    {
+        components::ForeignComponent::<_, EP, Self>::new(self, part)
+    }
 }
 
-// ----------------------------------------------------------------------
-// Implementations on Index
-// ----------------------------------------------------------------------
+// Generic implementation for all relation specification types
+impl<'a, AI: RelationInterface> Queryable for &'a AI {
+    type EntityOutput = AI::RemoteEntity;
+    type OutputContainer = Vec<Stored<AI::RemoteEntity>>;
+    type StaticVersion = &'static AI::StaticVersion;
+
+    const IS_UNIQUE: bool = false;
+
+    fn build(&self) -> Query {
+        let anames = RelationNames::collect(*self).unwrap();
+        let relation_name = anames.relation_name();
+        Query::new()
+            .attach(QueryPart::Root, "SELECT DISTINCT")
+            .attach(QueryPart::Columns, format!("`{}`.*", anames.remote_name))
+            .attach(QueryPart::From, format!("`{}`", relation_name))
+            .attach(
+                QueryPart::Join,
+                format!(
+                    "`{}` ON `{}`.`id` = `{}`.`{}`",
+                    anames.remote_name, anames.remote_name, relation_name, anames.remote_field
+                ),
+            )
+            .attach(
+                QueryPart::Where,
+                format!("`{}`.`{}` = ?", relation_name, anames.local_field),
+            )
+    }
+    fn bind(&self, ctx: &mut StatementContext, index: &mut i32) {
+        let rdata = self
+            .get_data()
+            .expect("binding query for relation with no data");
+
+        ctx.bind(*index, rdata.local_id)
+            .expect("couldn't bind relation id");
+        *index += 1;
+    }
+}
 
 impl<E: Entity, EPL: EntityPartList<Entity = E>> Index<E, EPL> {
     /// Perform a search through this index
@@ -795,14 +683,9 @@ impl<'a, E: Entity, EPL: EntityPartList<Entity = E>> Queryable for &'a Index<E,
     type EntityOutput = E;
     type OutputContainer = Vec<Stored<E>>;
     type StaticVersion = &'static Index<E, EPL>;
-    type Carrier = ();
 
     const IS_UNIQUE: bool = false;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
     fn build(&self) -> Query {
         Query::new()
             .attach(QueryPart::Root, "SELECT DISTINCT")

+ 55 - 123
microrm/src/query/components.rs

@@ -9,100 +9,23 @@ use crate::{
         relation::{LocalSide, Relation},
         Stored,
     },
-    ConnectionLease,
 };
 
 use super::{OutputContainer, Query};
 
-pub(crate) type LeaseCarrier<'r, 'l> = Option<&'r mut ConnectionLease<'l>>;
-
-pub(crate) struct LeaseCarrierComponent<'r, 'l: 'r, Parent: Queryable> {
-    parent: Parent,
-    lease: LeaseCarrier<'r, 'l>,
+/// Allow manipulation of an entire table.
+pub(crate) struct TableComponent<E: Entity> {
+    _ghost: std::marker::PhantomData<E>,
 }
 
-impl<'r, 'l: 'r, Parent: Queryable> LeaseCarrierComponent<'r, 'l, Parent> {
-    pub(crate) fn new(parent: Parent, lease: &'r mut ConnectionLease<'l>) -> Self {
+impl<E: Entity> Clone for TableComponent<E> {
+    fn clone(&self) -> Self {
         Self {
-            parent,
-            lease: Some(lease),
+            _ghost: Default::default(),
         }
     }
 }
 
-impl<'r, 'l: 'r, Parent: Queryable> Queryable for LeaseCarrierComponent<'r, 'l, Parent> {
-    type EntityOutput = Parent::EntityOutput;
-    type OutputContainer = Parent::OutputContainer;
-    // lease carrying does not affect the query at all, so for caching purposes, drop it
-    type StaticVersion = Parent::StaticVersion;
-
-    type Carrier = LeaseCarrier<'r, 'l>;
-
-    const IS_UNIQUE: bool = Parent::IS_UNIQUE;
-
-    fn carried(&mut self) -> &mut Self::Carrier {
-        &mut self.lease
-    }
-
-    fn build(&self) -> Query {
-        self.parent.build()
-    }
-
-    fn bind(&self, stmt: &mut StatementContext, index: &mut i32) {
-        self.parent.bind(stmt, index)
-    }
-}
-
-pub(crate) struct ExtractLeaseComponent<
-    'r,
-    'l: 'r,
-    Parent: Queryable<Carrier = LeaseCarrier<'r, 'l>>,
-> {
-    parent: Parent,
-}
-
-impl<'r, 'l: 'r, Parent: Queryable<Carrier = LeaseCarrier<'r, 'l>>>
-    ExtractLeaseComponent<'r, 'l, Parent>
-{
-    pub(crate) fn new(mut parent: Parent) -> (Self, &'r mut ConnectionLease<'l>) {
-        let lease = parent
-            .carried()
-            .take()
-            .expect("extracting lease a second time?");
-        (Self { parent }, lease)
-    }
-}
-
-impl<'r, 'l: 'r, Parent: Queryable<Carrier = LeaseCarrier<'r, 'l>>> Queryable
-    for ExtractLeaseComponent<'r, 'l, Parent>
-{
-    type EntityOutput = Parent::EntityOutput;
-    type OutputContainer = Parent::OutputContainer;
-    // lease extraction does not affect the query at all, so for caching purposes, drop it
-    type StaticVersion = Parent::StaticVersion;
-
-    type Carrier = ();
-
-    const IS_UNIQUE: bool = Parent::IS_UNIQUE;
-
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
-    fn build(&self) -> Query {
-        self.parent.build()
-    }
-
-    fn bind(&self, stmt: &mut StatementContext, index: &mut i32) {
-        self.parent.bind(stmt, index)
-    }
-}
-
-/// Allow manipulation of an entire table.
-pub(crate) struct TableComponent<E: Entity> {
-    _ghost: std::marker::PhantomData<E>,
-}
-
 impl<E: Entity> TableComponent<E> {
     pub fn new() -> Self {
         Self {
@@ -115,14 +38,9 @@ impl<E: Entity> Queryable for TableComponent<E> {
     type EntityOutput = E;
     type OutputContainer = Vec<Stored<E>>;
     type StaticVersion = Self;
-    type Carrier = ();
 
     const IS_UNIQUE: bool = false;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
     fn build(&self) -> Query {
         Query::new()
             .attach(QueryPart::Root, "SELECT DISTINCT")
@@ -133,6 +51,7 @@ impl<E: Entity> Queryable for TableComponent<E> {
 }
 
 /// Filter on a Datum
+#[derive(Clone)]
 pub(crate) struct WithComponent<WEP: EntityPart, Parent: Queryable, QE: QueryEquivalent<WEP::Datum>>
 {
     datum: QE,
@@ -155,6 +74,7 @@ impl<WEP: EntityPart, Parent: Queryable, QE: QueryEquivalent<WEP::Datum>>
 /// this workaround is needed because we very explicitly would like QE to not be a
 /// 'static-restricted type, and it doesn't matter for the purposes of actually distinguishing
 /// between queries.
+#[derive(Clone)]
 pub(crate) struct CanonicalWithComponent<WEP: EntityPart, Parent: Queryable> {
     _ghost: std::marker::PhantomData<(WEP, Parent)>,
 }
@@ -165,14 +85,9 @@ impl<WEP: EntityPart, Parent: Queryable + 'static> Queryable
     type EntityOutput = WEP::Entity;
     type OutputContainer = Option<Stored<WEP::Entity>>;
     type StaticVersion = Self;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = Parent::IS_UNIQUE;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
     fn build(&self) -> Query {
         unreachable!()
     }
@@ -190,14 +105,9 @@ impl<
     type EntityOutput = WEP::Entity;
     type OutputContainer = Parent::OutputContainer;
     type StaticVersion = CanonicalWithComponent<WEP, Parent::StaticVersion>;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = Parent::IS_UNIQUE;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        self.parent.carried()
-    }
-
     fn build(&self) -> Query {
         self.parent.build().attach(
             QueryPart::Where,
@@ -243,6 +153,22 @@ impl<
     }
 }
 
+impl<
+        E: Entity,
+        Parent: Queryable,
+        EPL: EntityPartList<Entity = E>,
+        EL: QueryEquivalentList<EPL::DatumList>,
+    > Clone for IndexComponent<E, Parent, EPL, EL>
+{
+    fn clone(&self) -> Self {
+        Self {
+            datum: self.datum.clone(),
+            parent: self.parent.clone(),
+            _ghost: Default::default(),
+        }
+    }
+}
+
 /// this workaround is needed because we very explicitly would like EL to not be a
 /// 'static-restricted type, and it doesn't matter for the purposes of actually distinguishing
 /// between queries.
@@ -260,14 +186,9 @@ impl<E: Entity, Parent: Queryable + 'static, EPL: EntityPartList<Entity = E>> Qu
     type EntityOutput = E;
     type OutputContainer = Option<Stored<E>>;
     type StaticVersion = Self;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = Parent::IS_UNIQUE;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        unreachable!()
-    }
-
     fn build(&self) -> Query {
         unreachable!()
     }
@@ -276,6 +197,16 @@ impl<E: Entity, Parent: Queryable + 'static, EPL: EntityPartList<Entity = E>> Qu
     }
 }
 
+impl<E: Entity, Parent: Queryable + 'static, EPL: EntityPartList<Entity = E>> Clone
+    for CanonicalIndexComponent<E, Parent, EPL>
+{
+    fn clone(&self) -> Self {
+        Self {
+            _ghost: Default::default(),
+        }
+    }
+}
+
 impl<
         E: Entity,
         Parent: Queryable,
@@ -286,14 +217,9 @@ impl<
     type EntityOutput = E;
     type OutputContainer = Option<Stored<E>>;
     type StaticVersion = CanonicalIndexComponent<E, Parent::StaticVersion, EPL>;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = true;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        self.parent.carried()
-    }
-
     fn build(&self) -> Query {
         let mut query = self.parent.build();
 
@@ -332,6 +258,7 @@ impl<
     }
 }
 
+#[derive(Clone)]
 pub(crate) struct SingleComponent<Parent: Queryable> {
     parent: Parent,
 }
@@ -346,14 +273,9 @@ impl<Parent: Queryable> Queryable for SingleComponent<Parent> {
     type EntityOutput = Parent::EntityOutput;
     type OutputContainer = Option<Stored<Self::EntityOutput>>;
     type StaticVersion = SingleComponent<Parent::StaticVersion>;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = true;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        self.parent.carried()
-    }
-
     fn build(&self) -> Query {
         // it's not a crime to ask a second time, but it's not valid SQL to repeat the LIMIT 1, either
         if Parent::IS_UNIQUE {
@@ -386,6 +308,17 @@ impl<R: Entity, L: Entity, EP: EntityPart<Entity = L>, Parent: Queryable>
     }
 }
 
+impl<R: Entity, L: Entity, EP: EntityPart<Entity = L>, Parent: Queryable> Clone
+    for JoinComponent<R, L, EP, Parent>
+{
+    fn clone(&self) -> Self {
+        Self {
+            parent: self.parent.clone(),
+            _ghost: Default::default(),
+        }
+    }
+}
+
 impl<
         R: Entity,
         L: Entity,
@@ -397,14 +330,9 @@ impl<
     type EntityOutput = R;
     type OutputContainer = Vec<Stored<R>>;
     type StaticVersion = JoinComponent<R, L, EP, Parent::StaticVersion>;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = Parent::IS_UNIQUE;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        self.parent.carried()
-    }
-
     fn build(&self) -> Query {
         let remote_name = R::entity_name();
         let local_name = L::entity_name();
@@ -491,19 +419,23 @@ impl<FE: Entity, EP: EntityPart, Parent: Queryable> ForeignComponent<FE, EP, Par
     }
 }
 
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> Clone for ForeignComponent<FE, EP, Parent> {
+    fn clone(&self) -> Self {
+        Self {
+            parent: self.parent.clone(),
+            _ghost: Default::default(),
+        }
+    }
+}
+
 impl<FE: Entity, EP: EntityPart, Parent: Queryable> Queryable for ForeignComponent<FE, EP, Parent> {
     type EntityOutput = FE;
     type StaticVersion = ForeignComponent<FE, EP, Parent::StaticVersion>;
     type OutputContainer =
         <Parent::OutputContainer as OutputContainer<Parent::EntityOutput>>::ReplacedEntity<FE>;
-    type Carrier = Parent::Carrier;
 
     const IS_UNIQUE: bool = Parent::IS_UNIQUE;
 
-    fn carried(&mut self) -> &mut Self::Carrier {
-        self.parent.carried()
-    }
-
     fn build(&self) -> Query {
         let subquery = self.parent.build().replace(
             QueryPart::Columns,

+ 2 - 5
microrm/src/schema/build.rs

@@ -2,7 +2,7 @@ use std::collections::HashMap;
 
 use crate::{
     db::{ConnectionLease, Transaction},
-    query::{Insertable, QueryVerbs, Queryable},
+    query::{Insertable, Queryable},
     schema::{
         collect::{EntityStateContainer, PartType},
         entity::{Entity, EntityPart, EntityPartList, EntityPartVisitor},
@@ -338,10 +338,7 @@ pub(crate) fn collect_from_database<DB: Schema>(schema: &DB) -> DatabaseSchema {
     let digest = hasher.finalize();
 
     DatabaseSchema {
-        signature: digest.into_iter().fold(String::new(), |mut a, v| {
-            a += &format!("{:02x}", v);
-            a
-        }),
+        signature: digest.into_iter().fold(String::new(), |mut a, v| { a += &format!("{:02x}", v); a }),
         table_queries: HashMap::from_iter(table_queries),
         index_queries: HashMap::from_iter(index_queries),
     }

+ 3 - 3
microrm/src/schema/datum/datum_list.rs

@@ -14,7 +14,7 @@ impl DatumList for () {
     fn list_head(&self) -> &Self::ListHead {
         unreachable!()
     }
-    fn list_tail(&self) -> Self::ListTail {}
+    fn list_tail(&self) -> Self::ListTail { }
 
     fn accept(&self, _: &mut impl DatumVisitor) {}
 }
@@ -36,7 +36,7 @@ impl<T: Datum> DatumList for T {
     fn list_head(&self) -> &Self::ListHead {
         self
     }
-    fn list_tail(&self) -> Self::ListTail {}
+    fn list_tail(&self) -> Self::ListTail { }
 
     fn accept(&self, visitor: &mut impl DatumVisitor) {
         visitor.visit(self);
@@ -61,7 +61,7 @@ impl<T0: Datum> DatumList for (T0,) {
     fn list_head(&self) -> &Self::ListHead {
         &self.0
     }
-    fn list_tail(&self) -> Self::ListTail {}
+    fn list_tail(&self) -> Self::ListTail { }
 
     fn accept(&self, visitor: &mut impl DatumVisitor) {
         visitor.visit(&self.0);

+ 0 - 2
microrm/tests/common/mod.rs

@@ -1,5 +1,3 @@
-#![allow(unused)]
-
 use microrm::prelude::*;
 
 pub fn open_test_db_helper<DB: Schema + Default>(

+ 0 - 25
microrm/tests/lease_carrier.rs

@@ -1,25 +0,0 @@
-use microrm::prelude::*;
-use test_log::test;
-
-mod common;
-
-#[derive(Entity)]
-struct Entry {
-    #[key]
-    name: String,
-    value: String,
-}
-
-#[derive(Default, Schema)]
-struct KVStore {
-    entries: microrm::IDMap<Entry>,
-}
-
-#[test]
-fn test_carry() {
-    let (pool, db): (_, KVStore) = common::open_test_db!();
-    let mut lease = pool.acquire().unwrap();
-
-    assert_eq!(db.entries.count(&mut lease).unwrap(), 0);
-    assert_eq!(db.entries.carry_lease(&mut lease).count().unwrap(), 0);
-}