mem-query 0.0.1

Relational algebra interface for Rust collections
use super::{RelationImpl,Relation,DynQueryable,QueryOutput};
use tylisp::{defun, ops::Ret};
use crate::{
    query::{QueryPlanImpl, request::QueryRequest},
    header::Header,
    record::{ExternalRecord,ErasedExtRecord},
};

use std::marker::PhantomData;

#[derive(Clone,Debug,Default,Hash,Eq,PartialEq,Ord,PartialOrd)]
pub struct DynRel<R>(R);

impl<R> DynRel<R> where Self:RelationImpl {
    pub fn new(r:R) -> Self { DynRel(r) }
}

impl<R:RelationImpl> RelationImpl for DynRel<R> 
where for<'a> ErasedExtRecord<'a, R::Cols>: ExternalRecord<'a, Cols=R::Cols>
{
    type Cols = R::Cols;
    type FastCols = R::FastCols;
    type Planner = DynPlanner; 
}

impl<'a, R:RelationImpl> QueryOutput<'a> for DynRel<R>
where Self: RelationImpl<Cols = R::Cols>,
    ErasedExtRecord<'a, R::Cols>: ExternalRecord<'a, Cols=R::Cols>
{
    type QueryRow = ErasedExtRecord<'a, R::Cols>;
}

impl<'a, R:Relation<'a>> IntoIterator for &'a DynRel<R> {
    type Item = ErasedExtRecord<'a, R::Cols>;
    type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
    fn into_iter(self)->Self::IntoIter {
        Box::new( self.0.iter_all().map(|r| r.erase_type()))
    }
}

pub struct DynPlan<'a, Req, Cols>(
    &'a dyn DynQueryable<'a, Req, Cols=Cols>,
    Req,
    PhantomData<Cols>
);

impl<'a, Req:'a, Cols:Header> IntoIterator for DynPlan<'a, Req, Cols>
where Req: QueryRequest + 'a,
      ErasedExtRecord<'a, Cols>: ExternalRecord<'a, Cols=Cols>
{
    type Item = ErasedExtRecord<'a, Cols>;
    type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
    fn into_iter(self)->Self::IntoIter {
        self.0.dyn_query(self.1)
    }
}

impl<'a, R:'a, Req, Cols> QueryPlanImpl<'a, DynRel<R>, Req>
for DynPlan<'a, Req, Cols>
where Req: QueryRequest + 'a,
      R: Relation<'a, Cols=Cols> + DynQueryable<'a, Req,Cols = Cols>,
      Cols: Header,
{
    // type EstimatedCost;
    fn prepare(rel: &'a DynRel<R>, req: Req)->Self {
        DynPlan(&rel.0, req, PhantomData)
    }
}

#[derive(Debug,Default)]
pub struct DynPlanner;
defun!{ DynPlanner {
    ('a, Rel:'a + RelationImpl, Req:'a) { _:&'a DynRel<Rel>, _:Req }
    => { Ret, @DynPlan<'a, Req, Rel::Cols> };
}}

#[cfg(test)] mod test {
    use super::*;
    use crate::relation::{Insert, SelfQuery};
    use crate::record::Record;

    #[test]
    fn test_dyn_rel() {
        col!{pub A: u32};
        col!{pub B: u32};
        col!{pub C: u32};

        use tylisp::sexpr;

        assert_trait!{ sexpr!{A,B}: Record };

        assert_trait!{ Vec<sexpr!{A,B}>: RelationImpl };
        assert_trait!{ Vec<sexpr!{A,B}>: for<'a> Relation<'a> };

        type RelUnderTest = Vec<(A,B)>;//sexpr!{A,B}>;
        let mut rel: RelUnderTest = Default::default();

        assert!(<RelUnderTest as Insert<_>>::insert(&mut rel, (A(3), B(11))).is_ok());
        assert!(<RelUnderTest as Insert<_>>::insert(&mut rel, &(A(3), B(7))).is_ok());
        assert!(<RelUnderTest as Insert<_>>::insert(&mut rel, ((B(5), C(42)), A(7))).is_ok());

        let rel = rel.as_dyn();

        assert_eq!(3, rel.iter_all().count());
        assert_eq!(3, rel.as_ref().iter_all().count());
        assert_eq!(2, rel.as_ref().where_eq(A(3)).iter_all().count());

    }
}