mem-query 0.0.1

Relational algebra interface for Rust collections
use crate::{
    header::{ProjectFrom},
    query::{
        QueryPlanImpl,
        request::*,
        filter::QueryFilter,
        order::SortKey,
    },
    relation::{Relation,Queryable},
};
use tylisp::{
    sexpr, defun_nocalc,
    typenum as tn,
    marker_traits::List,
    ops::{Cond, logic::Not, list::{EmptyP}},
};


#[derive(Debug, Default)]
pub struct FallbackPlanner;

defun_nocalc!{() FallbackPlanner {
    ('a, Rel:Relation<'a>, Req:QueryRequest) { _:&'a Rel, _:Req }
    => { Cond, {{Not, {EmptyP, @Req::OrderBy}}, @PostSortPlan<'a, Rel, Req>},
               {tn::True, @FallbackPlan<'a, Rel, Req>}
    };
}}

pub struct FallbackPlan<'a, Rel, Req>(&'a Rel, Req);
impl<'a,Rel,Req> IntoIterator for FallbackPlan<'a,Rel,Req>
    where Rel: Relation<'a>,
          Req: QueryRequest<OrderBy=sexpr!{}>,
          Req::Filters: QueryFilter + 'a,
{
    type Item = Rel::QueryRow;
    type IntoIter = impl Iterator<Item = Self::Item>;
    fn into_iter(self)->Self::IntoIter {
        let filt = self.1.into_filters();
        self.0.iter_all()
              .filter(move |r| filt.test_record(r))
    }
}

impl<'a, Rel, Req> QueryPlanImpl<'a, Rel, Req> for FallbackPlan<'a, Rel, Req>
where Rel: Relation<'a>,
{
    fn prepare(rel: &'a Rel, req:Req)->Self { Self(rel,req) }
}

/*
pub struct PostFilterPlan<'a, Rel, Req, Test>{
    rel: &'a Rel,
    req: Req,
    test: PhantomData<Test>
}

impl<'a, Rel, Req, Test> QueryPlanImpl<'a, Rel, Req> for PostFilterPlan<'a, Rel, Req, Test>
{
    fn prepare(rel: &'a Rel, req: Req)->Self { PostFilterPlan{ rel, req, test: PhantomData } } 
}

impl<'a,Rel,Req,Test,PostFilt:'a, PassthroughFilt:'a,SubPlan> IntoIterator for PostFilterPlan<'a, Rel, Req, Test>
where Req: QueryRequest + 'a,
      Req::Filters: CollatedBy<Test, Passed=PostFilt, Failed=PassthroughFilt>,
      ReplaceFilters<Req, PassthroughFilt>: QueryRequest<OutputCols = Req::OutputCols>,
      Rel: Relation<'a> + Queryable<'a, ReplaceFilters<Req, PassthroughFilt>, Plan=SubPlan>,
      SubPlan: QueryPlan<'a, Rel, ReplaceFilters<Req, PassthroughFilt>>,
      PostFilt: QueryFilter,
      PostFilt::ReqCols: ProjectFrom<Req::OutputCols>,
{
    type IntoIter = impl Iterator<Item=Self::Item>;
    type Item = SubPlan::Row;

    fn into_iter(self)->Self::IntoIter {
        let (post, passthrough) = self.req.clone().into_filters().collate();
        Box::new(
            self.rel.query(self.req.set_filters(passthrough))
                    .filter(move |rec| post.test_record(rec))
        )
    }
}
*/
pub struct PostSortPlan<'a, Rel, Req>{
    rel: &'a Rel,
    req: Req,
}

impl<'a, Rel, Req> QueryPlanImpl<'a, Rel, Req> for PostSortPlan<'a, Rel, Req> {
    fn prepare(rel: &'a Rel, req: Req)->Self { PostSortPlan{ rel, req } }
}


impl<'a,Rel,Req,Key> IntoIterator for PostSortPlan<'a, Rel, Req>
where Rel: Relation<'a> + Queryable<'a, ReplaceOrder<Req, sexpr!{}>>,
      Req: QueryRequest<OrderBy=Key> + 'a,
      ReplaceOrder<Req, sexpr!{}>: QueryRequest,
      Key: SortKey + List,
      Key::ReqCols: ProjectFrom<Rel::Cols>,
{
    type IntoIter = std::vec::IntoIter<Self::Item>;
    type Item = Rel::QueryRow;

    fn into_iter(self)->Self::IntoIter {
        use ::itertools::Itertools;

        self.rel.query(self.req.set_order::<sexpr!{}>())
                .sorted_by(Req::OrderBy::cmp::<Self::Item>)
    }
}