use crate::{
db::{StatementContext, StatementRow},
schema::{
entity::{Entity, EntityID, EntityPartList},
Stored,
},
DBResult, Error,
};
pub trait IDContainer<T: Entity>: 'static + IntoIterator<Item = T::ID> {
fn assemble_from(ctx: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized;
}
pub trait OutputContainer<T: Entity>: 'static + IntoIterator<Item = Stored<T>> {
type IDContainer: IDContainer<T>;
type WithReplacedEntity<N: Entity>: OutputContainer<N>;
fn assemble_from(stmt: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized;
}
fn assemble_id<T: Entity>(row: StatementRow) -> T::ID {
<T::ID>::from_raw(row.read::<i64>(0).expect("couldn't read ID"))
}
fn assemble_single<T: Entity>(row: &mut StatementRow) -> Stored<T> {
let id = row.read::<i64>(0).expect("couldn't read ID");
let datum_list = <T::Parts>::build_datum_list(row).expect("couldn't build datum list");
Stored::new(T::ID::from_raw(id), T::build(datum_list))
}
impl<T: Entity> IDContainer<T> for Option<T::ID> {
fn assemble_from(ctx: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized,
{
Ok(ctx.run()?.map(assemble_id::<T>))
}
}
impl<T: Entity> OutputContainer<T> for Option<Stored<T>> {
type IDContainer = Option<T::ID>;
type WithReplacedEntity<N: Entity> = Option<Stored<N>>;
fn assemble_from(ctx: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized,
{
Ok(ctx.run()?.map(|mut r| assemble_single(&mut r)))
}
}
impl<T: Entity> IDContainer<T> for Vec<T::ID> {
fn assemble_from(ctx: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized,
{
ctx.iter()
.map(|r| r.map(assemble_id::<T>))
.collect::<Result<Vec<_>, Error>>()
}
}
impl<T: Entity> OutputContainer<T> for Vec<Stored<T>> {
type IDContainer = Vec<T::ID>;
type WithReplacedEntity<N: Entity> = Vec<Stored<N>>;
fn assemble_from(ctx: StatementContext<'_>) -> DBResult<Self>
where
Self: Sized,
{
ctx.iter()
.map(|r| r.map(|mut s| assemble_single(&mut s)))
.collect::<Result<Vec<_>, Error>>()
}
}