|
@@ -1,13 +1,13 @@
|
|
|
use itertools::Itertools;
|
|
|
|
|
|
use crate::{
|
|
|
- db::{Connection, StatementContext, Transaction},
|
|
|
+ db::{ConnectionLease, ConnectionLeaser, StatementContext, Transaction},
|
|
|
schema::{
|
|
|
datum::{Datum, QueryEquivalent, QueryEquivalentList},
|
|
|
entity::{Entity, EntityID, EntityPart, EntityPartList},
|
|
|
index::Index,
|
|
|
relation::{LocalSide, RelationData},
|
|
|
- IDMap, Stored,
|
|
|
+ Stored,
|
|
|
},
|
|
|
DBResult, Error,
|
|
|
};
|
|
@@ -206,36 +206,44 @@ pub trait RelationInterface {
|
|
|
|
|
|
/// Query this entity type without the relation filter.
|
|
|
fn query_all(&self) -> impl Queryable<EntityOutput = Self::RemoteEntity> {
|
|
|
- components::TableComponent::<Self::RemoteEntity>::new(self.get_data().unwrap().conn.clone())
|
|
|
+ components::TableComponent::<Self::RemoteEntity>::new()
|
|
|
}
|
|
|
|
|
|
/// Attempt to connect the contextual instance to a remote instance.
|
|
|
- fn connect_to(&self, remote_id: <Self::RemoteEntity as Entity>::ID) -> DBResult<()>
|
|
|
+ fn connect_to(
|
|
|
+ &self,
|
|
|
+ lease: &ConnectionLease,
|
|
|
+ remote_id: <Self::RemoteEntity as Entity>::ID,
|
|
|
+ ) -> DBResult<()>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
let rdata = self.get_data()?;
|
|
|
let an = RelationNames::collect::<Self>(self)?;
|
|
|
|
|
|
- let txn = Transaction::new(&rdata.conn)?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
|
|
|
- base_queries::do_connect::<Self::RemoteEntity>(rdata, an, remote_id)?;
|
|
|
+ base_queries::do_connect::<Self::RemoteEntity>(lease, rdata, an, remote_id)?;
|
|
|
|
|
|
txn.commit()
|
|
|
}
|
|
|
|
|
|
/// Attempt to disconnect the contextual instance from a remote instance.
|
|
|
- fn disconnect_from(&self, remote_id: <Self::RemoteEntity as Entity>::ID) -> DBResult<()>
|
|
|
+ fn disconnect_from(
|
|
|
+ &self,
|
|
|
+ lease: &ConnectionLease,
|
|
|
+ remote_id: <Self::RemoteEntity as Entity>::ID,
|
|
|
+ ) -> DBResult<()>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
let rdata = self.get_data()?;
|
|
|
let an = RelationNames::collect::<Self>(self)?;
|
|
|
|
|
|
- let txn = Transaction::new(&rdata.conn)?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
|
|
|
// second, add to the relation table
|
|
|
- rdata.conn.with_prepared(
|
|
|
+ txn.lease().as_ref().with_prepared(
|
|
|
hash_of(("disconnect", an.local_name, an.remote_name, an.part_name)),
|
|
|
|| {
|
|
|
format!(
|
|
@@ -264,14 +272,18 @@ pub trait RelationInterface {
|
|
|
/// Represents a context in which we can insert an entity type `E`.
|
|
|
pub trait Insertable<E: Entity> {
|
|
|
/// Insert an entity instance and return its new ID.
|
|
|
- fn insert(&self, value: E) -> DBResult<E::ID>;
|
|
|
+ fn insert(&self, lease: &ConnectionLease, value: E) -> DBResult<E::ID>;
|
|
|
/// Insert an entity instance and return a [`Stored`] instance that can be used to synchronize
|
|
|
/// its values back into the database later.
|
|
|
- fn insert_and_return(&self, value: E) -> DBResult<Stored<E>>;
|
|
|
+ fn insert_and_return(&self, lease: &ConnectionLease, value: E) -> DBResult<Stored<E>>;
|
|
|
}
|
|
|
|
|
|
impl<AI: RelationInterface> Insertable<AI::RemoteEntity> for AI {
|
|
|
- fn insert(&self, value: AI::RemoteEntity) -> DBResult<<AI::RemoteEntity as Entity>::ID>
|
|
|
+ fn insert(
|
|
|
+ &self,
|
|
|
+ lease: &ConnectionLease,
|
|
|
+ value: AI::RemoteEntity,
|
|
|
+ ) -> DBResult<<AI::RemoteEntity as Entity>::ID>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
@@ -282,19 +294,23 @@ impl<AI: RelationInterface> Insertable<AI::RemoteEntity> for AI {
|
|
|
let rdata = self.get_data()?;
|
|
|
let an = RelationNames::collect::<Self>(self)?;
|
|
|
|
|
|
- let txn = Transaction::new(&rdata.conn)?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
|
|
|
// so first, into the remote table
|
|
|
- let remote_id = base_queries::insert(&rdata.conn, &value)?;
|
|
|
+ let remote_id = base_queries::insert(lease, &value)?;
|
|
|
// then the relation
|
|
|
- base_queries::do_connect::<AI::RemoteEntity>(rdata, an, remote_id)?;
|
|
|
+ base_queries::do_connect::<AI::RemoteEntity>(lease, rdata, an, remote_id)?;
|
|
|
|
|
|
txn.commit()?;
|
|
|
|
|
|
Ok(remote_id)
|
|
|
}
|
|
|
|
|
|
- fn insert_and_return(&self, value: AI::RemoteEntity) -> DBResult<Stored<AI::RemoteEntity>>
|
|
|
+ fn insert_and_return(
|
|
|
+ &self,
|
|
|
+ lease: &ConnectionLease,
|
|
|
+ value: AI::RemoteEntity,
|
|
|
+ ) -> DBResult<Stored<AI::RemoteEntity>>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
@@ -305,12 +321,12 @@ impl<AI: RelationInterface> Insertable<AI::RemoteEntity> for AI {
|
|
|
let rdata = self.get_data()?;
|
|
|
let an = RelationNames::collect::<Self>(self)?;
|
|
|
|
|
|
- let txn = Transaction::new(&rdata.conn)?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
|
|
|
// so first, into the remote table
|
|
|
- let remote = base_queries::insert_and_return(&rdata.conn, value)?;
|
|
|
+ let remote = base_queries::insert_and_return(lease, value)?;
|
|
|
// then the relation
|
|
|
- base_queries::do_connect::<AI::RemoteEntity>(rdata, an, remote.id())?;
|
|
|
+ base_queries::do_connect::<AI::RemoteEntity>(lease, rdata, an, remote.id())?;
|
|
|
|
|
|
txn.commit()?;
|
|
|
|
|
@@ -336,8 +352,6 @@ pub trait Queryable: Clone {
|
|
|
/// Bind into any required placeholders to 'fill' an instance created by [`build`].
|
|
|
#[doc(hidden)]
|
|
|
fn bind(&self, stmt: &mut StatementContext, index: &mut i32);
|
|
|
- #[doc(hidden)]
|
|
|
- fn conn(&self) -> &Connection;
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
// Verbs
|
|
@@ -345,13 +359,13 @@ pub trait Queryable: Clone {
|
|
|
/// Count all entities in the current context.
|
|
|
///
|
|
|
/// Returns the number of entities.
|
|
|
- fn count(self) -> DBResult<usize>
|
|
|
+ fn count(self, lease: &ConnectionLease) -> DBResult<usize>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
- let txn = Transaction::new(self.conn())?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
struct CountTag;
|
|
|
- let out = self.conn().with_prepared(
|
|
|
+ let out = txn.lease().as_ref().with_prepared(
|
|
|
std::any::TypeId::of::<(Self::StaticVersion, CountTag)>(),
|
|
|
|| {
|
|
|
self.build()
|
|
@@ -379,13 +393,13 @@ pub trait Queryable: Clone {
|
|
|
Ok(out)
|
|
|
}
|
|
|
/// Get all entities in the current context.
|
|
|
- fn get(self) -> DBResult<Self::OutputContainer>
|
|
|
+ fn get(self, lease: &ConnectionLease) -> DBResult<Self::OutputContainer>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
- let txn = Transaction::new(self.conn())?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
struct GetTag;
|
|
|
- let out = self.conn().with_prepared(
|
|
|
+ let out = txn.lease().as_ref().with_prepared(
|
|
|
std::any::TypeId::of::<(Self::StaticVersion, GetTag)>(),
|
|
|
|| self.build().assemble(),
|
|
|
|mut ctx| {
|
|
@@ -393,7 +407,7 @@ pub trait Queryable: Clone {
|
|
|
let mut index = 1;
|
|
|
self.bind(&mut ctx, &mut index);
|
|
|
|
|
|
- <Self::OutputContainer>::assemble_from(self.conn(), ctx)
|
|
|
+ <Self::OutputContainer>::assemble_from(ctx)
|
|
|
},
|
|
|
)?;
|
|
|
txn.commit()?;
|
|
@@ -402,13 +416,14 @@ pub trait Queryable: Clone {
|
|
|
/// Get IDs of all entities in the current context.
|
|
|
fn get_ids(
|
|
|
self,
|
|
|
+ lease: &ConnectionLease,
|
|
|
) -> DBResult<<Self::OutputContainer as OutputContainer<Self::EntityOutput>>::IDContainer>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
- let txn = Transaction::new(self.conn())?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
struct GetIDTag;
|
|
|
- let out = self.conn().with_prepared(
|
|
|
+ let out = txn.lease().as_ref().with_prepared(
|
|
|
std::any::TypeId::of::<(Self::StaticVersion, GetIDTag)>(),
|
|
|
|| {
|
|
|
self.build()
|
|
@@ -432,13 +447,13 @@ pub trait Queryable: Clone {
|
|
|
Ok(out)
|
|
|
}
|
|
|
/// Delete all entities in the current context.
|
|
|
- fn delete(self) -> DBResult<()>
|
|
|
+ fn delete(self, lease: &ConnectionLease) -> DBResult<()>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
- let txn = Transaction::new(self.conn())?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
struct DeleteTag;
|
|
|
- self.conn().with_prepared(
|
|
|
+ txn.lease().as_ref().with_prepared(
|
|
|
std::any::TypeId::of::<(Self::StaticVersion, DeleteTag)>(),
|
|
|
|| {
|
|
|
format!(
|
|
@@ -465,13 +480,13 @@ pub trait Queryable: Clone {
|
|
|
}
|
|
|
|
|
|
/// Delete all entities in the current context and return them
|
|
|
- fn remove(self) -> DBResult<Self::OutputContainer>
|
|
|
+ fn remove(self, lease: &ConnectionLease) -> DBResult<Self::OutputContainer>
|
|
|
where
|
|
|
Self: Sized,
|
|
|
{
|
|
|
- let txn = Transaction::new(self.conn())?;
|
|
|
+ let txn = Transaction::new(lease)?;
|
|
|
struct DeleteTag;
|
|
|
- let out = self.conn().with_prepared(
|
|
|
+ let out = txn.lease().as_ref().with_prepared(
|
|
|
std::any::TypeId::of::<(Self::StaticVersion, DeleteTag)>(),
|
|
|
|| {
|
|
|
format!(
|
|
@@ -491,7 +506,7 @@ pub trait Queryable: Clone {
|
|
|
let mut index = 1;
|
|
|
self.bind(&mut ctx, &mut index);
|
|
|
|
|
|
- <Self::OutputContainer>::assemble_from(self.conn(), ctx)
|
|
|
+ <Self::OutputContainer>::assemble_from(ctx)
|
|
|
},
|
|
|
)?;
|
|
|
txn.commit()?;
|
|
@@ -609,27 +624,6 @@ pub trait Queryable: Clone {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Generic implementations for all IDMaps
|
|
|
-impl<'a, T: Entity> Queryable for &'a IDMap<T> {
|
|
|
- type EntityOutput = T;
|
|
|
- type OutputContainer = Vec<Stored<T>>;
|
|
|
- type StaticVersion = &'static IDMap<T>;
|
|
|
-
|
|
|
- const IS_UNIQUE: bool = false;
|
|
|
-
|
|
|
- fn build(&self) -> Query {
|
|
|
- Query::new()
|
|
|
- .attach(QueryPart::Root, "SELECT DISTINCT")
|
|
|
- .attach(QueryPart::Columns, "*")
|
|
|
- .attach(QueryPart::From, format!("`{}`", T::entity_name()))
|
|
|
- }
|
|
|
- fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) {}
|
|
|
-
|
|
|
- fn conn(&self) -> &Connection {
|
|
|
- &self.conn
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// Generic implementation for all relation specification types
|
|
|
impl<'a, AI: RelationInterface> Queryable for &'a AI {
|
|
|
type EntityOutput = AI::RemoteEntity;
|
|
@@ -666,10 +660,6 @@ impl<'a, AI: RelationInterface> Queryable for &'a AI {
|
|
|
.expect("couldn't bind relation id");
|
|
|
*index += 1;
|
|
|
}
|
|
|
-
|
|
|
- fn conn(&self) -> &Connection {
|
|
|
- &self.get_data().unwrap().conn
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
impl<E: Entity, EPL: EntityPartList<Entity = E>> Index<E, EPL> {
|
|
@@ -698,8 +688,4 @@ impl<'a, E: Entity, EPL: EntityPartList<Entity = E>> Queryable for &'a Index<E,
|
|
|
.attach(QueryPart::From, format!("`{}`", E::entity_name()))
|
|
|
}
|
|
|
fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) {}
|
|
|
-
|
|
|
- fn conn(&self) -> &Connection {
|
|
|
- &self.conn
|
|
|
- }
|
|
|
}
|