use crate::{
db::{StatementContext, Transaction},
query::{self, Insertable, Query, QueryPart, Queryable, RelationInterface},
schema::{
entity::Entity,
relation::{LocalSide, Relation, RelationData, RelationDomain, RelationMap, RelationRange},
IDMap, Stored,
},
DBResult, Error,
};
impl<T: Entity> Stored<T> {
pub fn sync(&mut self, txn: &mut Transaction) -> DBResult<()> {
query::base_queries::update_entity(txn, self)
}
}
impl<T: Entity> IDMap<T> {
pub fn by_id(&self, lease: &mut Transaction, id: T::ID) -> DBResult<Option<Stored<T>>> {
self.with(T::IDPart::default(), id).first().get(lease)
}
}
impl<T: Entity> Queryable for &IDMap<T> {
type EntityOutput = T;
type OutputContainer = Vec<Stored<T>>;
type StaticVersion = &'static IDMap<T>;
fn build(&self) -> DBResult<Query<'_>> {
Ok(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) -> DBResult<()> {
Ok(())
}
}
impl<T: Entity> Insertable<T> for IDMap<T> {
fn insert(&self, txn: &mut Transaction, value: T) -> DBResult<T::ID> {
let out = query::base_queries::insert(txn, &value)?;
Ok(out)
}
fn insert_ref(&self, txn: &mut Transaction, value: T::ERef<'_>) -> DBResult<T::ID> {
let out = query::base_queries::insert_ref::<T>(txn, value)?;
Ok(out)
}
fn insert_and_return(&self, txn: &mut Transaction, value: T) -> DBResult<Stored<T>> {
query::base_queries::insert_and_return(txn, value)
}
}
impl<T: Entity> Insertable<T> for &IDMap<T> {
fn insert(&self, lease: &mut Transaction, value: T) -> DBResult<T::ID> {
<IDMap<T> as Insertable<T>>::insert(self, lease, value)
}
fn insert_ref(&self, lease: &mut Transaction, value: T::ERef<'_>) -> DBResult<T::ID> {
<IDMap<T> as Insertable<T>>::insert_ref(self, lease, value)
}
fn insert_and_return(&self, lease: &mut Transaction, value: T) -> DBResult<Stored<T>> {
<IDMap<T> as Insertable<T>>::insert_and_return(self, lease, value)
}
}
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> {
self.data
.as_ref()
.ok_or(Error::LogicError(
"no distinguishing name for empty RelationMap",
))
.map(|d| d.part_name)
}
fn get_data(&self) -> DBResult<&RelationData> {
self.data
.as_ref()
.ok_or(Error::LogicError("Reading from unassigned RelationMap"))
}
}
impl<T: Entity> RelationInterface for &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<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> {
Ok(R::NAME)
}
fn get_data(&self) -> DBResult<&RelationData> {
self.data
.as_ref()
.ok_or(Error::LogicError("Reading from unassigned RelationDomain"))
}
}
impl<R: Relation> RelationInterface for &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> RelationInterface for RelationRange<R> {
type RemoteEntity = R::Domain;
type StaticVersion = Self;
const SIDE: LocalSide = LocalSide::Range;
fn get_distinguishing_name(&self) -> DBResult<&'static str> {
Ok(R::NAME)
}
fn get_data(&self) -> DBResult<&RelationData> {
self.data
.as_ref()
.ok_or(Error::LogicError("Reading from unassigned RelationRange"))
}
}
impl<R: Relation> RelationInterface for &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)
}
}