microrm 0.6.3

Lightweight ORM using sqlite as a backend
Documentation
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>>()
    }
}