microrm 0.6.3

Lightweight ORM using sqlite as a backend
Documentation
use crate::{db::StatementRow, schema::relation::RelationData, DBResult};

use super::{
    Datum, Entity, EntityPart, EntityPartList, EntityPartVisitor, OwnedDatum, OwnedDatumList,
};

macro_rules! build_datum {
    ($local_id:ident,$stmt:ident,$idx:ident,$d:ident,$t:ident) => {
        let $d = <$t::Datum as Datum>::build_from(
            RelationData {
                local_name: <$t::Entity as Entity>::entity_name(),
                part_name: $t::part_name(),
                local_id: $local_id,
            },
            $stmt,
            &mut $idx,
        )?;
    };
}

macro_rules! build_ref_datum {
    ($local_id:ident,$stmt:ident,$idx:ident,$d:ident,$t:ident) => {
        let $d = <<$t::Datum as OwnedDatum>::RefData<'m> as Datum>::build_from(
            RelationData {
                local_name: <$t::Entity as Entity>::entity_name(),
                part_name: $t::part_name(),
                local_id: $local_id,
            },
            $stmt,
            &mut $idx,
        )?;
    };
}

pub struct MarkerPart<E: Entity> {
    _ghost: std::marker::PhantomData<E>,
}

impl<E: Entity> Default for MarkerPart<E> {
    fn default() -> Self {
        Self {
            _ghost: Default::default(),
        }
    }
}

impl<E: Entity> Clone for MarkerPart<E> {
    fn clone(&self) -> Self {
        Self::default()
    }
}

impl<E: Entity> EntityPart for MarkerPart<E> {
    type Entity = E;
    type Datum = bool;

    fn desc() -> Option<&'static str> {
        None
    }
    fn unique() -> bool {
        false
    }
    fn part_name() -> &'static str {
        "marker"
    }
    fn get_datum(_from: &Self::Entity) -> &Self::Datum {
        unreachable!()
    }
}

/// Empty list of entity parts. Since [`EntityPartList`] requires an associated [`Entity`], a
/// simple unit type is insufficient.
#[derive(Debug, Default)]
pub struct EmptyList<E: Entity> {
    _ghost: std::marker::PhantomData<E>,
}

impl<E: Entity> EntityPartList for EmptyList<E> {
    type Entity = E;
    type DatumList = ();

    type ListHead = MarkerPart<E>;
    type ListTail = EmptyList<E>;
    const IS_EMPTY: bool = true;

    fn build_datum_list(_stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
        Ok(())
    }
    fn build_datum_ref_list<'l, 'm>(
        _stmt: &'l mut StatementRow,
    ) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>>
    where
        'l: 'm,
    {
        Ok(())
    }

    fn accept_part_visitor(_: &mut impl EntityPartVisitor) {}
    fn accept_part_visitor_ref(
        _: &Self::DatumList,
        _: &mut impl EntityPartVisitor,
    ) -> DBResult<()> {
        Ok(())
    }
}

impl<E: Entity, P0: EntityPart<Entity = E>> EntityPartList for P0 {
    type Entity = E;
    type DatumList = P0::Datum;

    type ListHead = P0;
    type ListTail = EmptyList<E>;

    fn build_datum_list(stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
        let local_id: i64 = stmt.read(0)?;
        let mut idx = 1; // starting index is 1 since index 0 is the ID
        build_datum!(local_id, stmt, idx, d0, P0);

        Ok(d0)
    }

    fn build_datum_ref_list<'l, 'm>(
        stmt: &'l mut StatementRow,
    ) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>>
    where
        'l: 'm,
    {
        let local_id: i64 = stmt.read(0)?;
        let mut idx = 1; // starting index is 1 since index 0 is the ID
        build_ref_datum!(local_id, stmt, idx, d0, P0);

        Ok(d0)
    }

    fn accept_part_visitor(v: &mut impl EntityPartVisitor<Entity = Self::Entity>) {
        v.visit::<P0>();
    }
    fn accept_part_visitor_ref(
        datum_list: &Self::DatumList,
        v: &mut impl EntityPartVisitor<Entity = Self::Entity>,
    ) -> DBResult<()> {
        v.visit_datum::<P0>(datum_list)
    }
}

impl<E: Entity, P0: EntityPart<Entity = E>> EntityPartList for (P0,) {
    type Entity = E;
    type DatumList = (P0::Datum,);

    type ListHead = P0;
    type ListTail = EmptyList<E>;

    fn build_datum_list(stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
        let local_id: i64 = stmt.read(0)?;
        let mut idx = 1; // starting index is 1 since index 0 is the ID
        build_datum!(local_id, stmt, idx, d0, P0);

        Ok((d0,))
    }

    fn build_datum_ref_list<'l, 'm>(
        stmt: &'l mut StatementRow,
    ) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>>
    where
        'l: 'm,
    {
        let local_id: i64 = stmt.read(0)?;
        let mut idx = 1; // starting index is 1 since index 0 is the ID
        build_ref_datum!(local_id, stmt, idx, d0, P0);

        Ok((d0,))
    }

    fn accept_part_visitor(v: &mut impl EntityPartVisitor<Entity = Self::Entity>) {
        v.visit::<P0>();
    }
    fn accept_part_visitor_ref(
        datum_list: &Self::DatumList,
        v: &mut impl EntityPartVisitor<Entity = Self::Entity>,
    ) -> DBResult<()> {
        v.visit_datum::<P0>(&datum_list.0)
    }
}

macro_rules! part_list_impl {
    ($p0:ident : $d0:ident : $n0:tt, $($p:ident : $d:ident : $n:tt),+) => {
        impl<E: Entity, $p0 : EntityPart<Entity = E>, $( $p : EntityPart<Entity = E> ),* > EntityPartList for ( $p0, $($p),* ) where ( $( $p ),* ,) : EntityPartList<Entity = E, DatumList = ( $( $p ::Datum ),* ,)> {
            type Entity = E;
            type DatumList = ( $p0 :: Datum, $( $p :: Datum ),* );

            type ListHead = $p0;
            type ListTail = ( $( $p ),* , );

            fn build_datum_list(stmt: &mut StatementRow) -> DBResult<Self::DatumList> {
                let local_id: i64 = stmt.read(0)?;
                let mut idx = 1;
                build_datum!(local_id, stmt, idx, $d0, $p0);
                $(
                    build_datum!(local_id, stmt, idx, $d, $p);
                )*

                Ok(( $d0, $( $d ),* ))
            }

            fn build_datum_ref_list<'l, 'm>(stmt: &'l mut StatementRow) -> DBResult<<Self::DatumList as OwnedDatumList>::RefList<'m>> where 'l: 'm {
                let local_id: i64 = stmt.read(0)?;
                let mut idx = 1;
                build_ref_datum!(local_id, stmt, idx, $d0, $p0);
                $(
                    build_ref_datum!(local_id, stmt, idx, $d, $p);
                )*

                Ok(( $d0, $( $d ),* ))
            }

            fn accept_part_visitor(v: &mut impl EntityPartVisitor<Entity = Self::Entity>) {
                v.visit::< $p0 >();
                $(
                    v.visit::< $p >();
                )*
            }

            fn accept_part_visitor_ref(datum_list: &Self::DatumList, v: &mut impl EntityPartVisitor<Entity = Self::Entity>) -> DBResult<()> {
                v.visit_datum::< $p0 >(&datum_list . $n0)?;
                $(
                    v.visit_datum::< $p >(&datum_list . $n)?;
                )*
                Ok(())
            }
        }
    }
}

part_list_impl!(P0:d0:0, P1:d1:1);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10, P11:d11:11);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10, P11:d11:11, P12:d12:12);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10, P11:d11:11, P12:d12:12, P13:d13:13);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10, P11:d11:11, P12:d12:12, P13:d13:13, P14:d14:14);
part_list_impl!(P0:d0:0, P1:d1:1, P2:d2:2, P3:d3:3, P4:d4:4, P5:d5:5, P6:d6:6, P7:d7:7, P8:d8:8, P9:d9:9, P10:d10:10, P11:d11:11, P12:d12:12, P13:d13:13, P14:d14:14, P15:d15:15);