mem-query 0.0.1

Relational algebra interface for Rust collections
use crate::{
    relation::{RelationImpl,Queryable,QueryOutput,Delete},
    query::{
        QueryPlanImpl,
        request::{QueryRequest, NewRequest, BlankRequest, AddFilter},
        filter::{QueryFilter, FilterForHeader},
    },
    transaction::{Transaction,UndoLog,RevertableOp},
};

use tylisp::{
    sexpr, sexpr_val, sexpr_quoted_types, calc, defun, HNil,
    marker_traits::{Pass, List},
    ops::{
        Phantom, Ret,
        list::{Concat},
    },
};

use std::marker::PhantomData;

pub struct FilterRel<Rel, Filt> {
    pub(crate) source: Rel,
    pub(crate) filter: Filt,
}

impl<Rel, Filt> RelationImpl for FilterRel<Rel,Filt>
where
    Rel: RelationImpl,
    Filt: QueryFilter,
    sexpr!{FilterForHeader, @Rel::Cols, @Filt}: Pass
{
    type Cols = Rel::Cols;
    type FastCols = Rel::FastCols;
    type Planner = Planner;
}

impl<'a, Rel, Filt> QueryOutput<'a> for FilterRel<Rel,Filt>
where
    Rel: QueryOutput<'a>,
    Self: RelationImpl<Cols = Rel::Cols>,
{
    type QueryRow = Rel::QueryRow;
}

impl<'a,R,F> IntoIterator for &'a FilterRel<R,F>
where
    F: QueryFilter,
    AddFilter<BlankRequest,F>: QueryRequest,
    R:Queryable<'a, AddFilter<BlankRequest,F>>
{
    type Item = R::QueryRow;
    type IntoIter = impl Iterator<Item = Self::Item>;
    fn into_iter(self)->Self::IntoIter {
        self.source.query(
            BlankRequest.add_filter(self.filter.clone())
        )
    }
}

pub struct FilteredRequest<'a,R,F,Q> {
    rel: &'a FilterRel<R,F>,
    q: Q
}

impl<'a,R,F,Q>
    IntoIterator for FilteredRequest<'a,R,F,Q>
where
    F: QueryFilter,
    R: Queryable<'a, AddFilter<Q,F>>,
    Q: QueryRequest + 'a,
    AddFilter<Q,F>: QueryRequest
{
    type Item = R::QueryRow;
    type IntoIter = impl Iterator<Item = Self::Item>;
    fn into_iter(self)->Self::IntoIter {
        self.rel.source.query(
            self.q.add_filter(self.rel.filter.clone())
        )
    }
}

impl<'a,R,F,Q>
    QueryPlanImpl<'a, FilterRel<R,F>, Q> for FilteredRequest<'a,R,F,Q>
where
{
    fn prepare(rel: &'a FilterRel<R,F>, q:Q)->Self {
        FilteredRequest { rel, q }
    }
}

#[derive(Default,Copy,Clone,Debug)]
pub struct Planner;
defun!{ Planner {
    ('a, Rel, Filt: QueryFilter + Clone, Req: QueryRequest)
    {fr: &'a FilterRel<Rel, Filt>, req: Req}
     => { Ret, @FilteredRequest<'a, Rel, Filt, Req> };
}}

impl<R,F,Q> Delete<Q> for FilterRel<R,F>
where
    R:Delete<sexpr!{F,Q}>,
    Q: QueryFilter,
    F: QueryFilter,
    sexpr!{F,Q}: QueryFilter,
{
    type Op = DeleteOp<Q, R::Deleter>;
    type Deleter = impl Fn(Q)->Self::Op;
    fn deleter()->Self::Deleter {
        |q| DeleteOp{ q, deleter: R::deleter() }
    }
}

pub struct DeleteOp<Q,Deleter> {
    q: Q,
    deleter: Deleter
}   

impl<R,F,Q,Deleter,Op> RevertableOp<FilterRel<R,F>> for DeleteOp<Q,Deleter>
where
    Deleter: Fn(sexpr!{F, Q})->Op,
    Op: RevertableOp<R>,
    F: QueryFilter,
    Q: QueryFilter
{
    type Err = Op::Err;
    type Log = impl UndoLog<FilterRel<R,F>>;

    fn apply(self, rel: &mut FilterRel<R,F>)->Result<Self::Log, Self::Err> {
        let op = (self.deleter)(sexpr_val!{rel.filter.clone(), self.q});
        let inner_log =
            Transaction::start(&mut rel.source)
            .apply(op)
            .into_undo_log()
            .map_err(|e| e.left().unwrap())?;
        Ok(UndoInner(inner_log))
    }
}

pub struct UndoInner<Log>(Log);
impl<R,F,Log> UndoLog<FilterRel<R,F>> for UndoInner<Log>
where Log: UndoLog<R> {
    fn revert(self, rel: &mut FilterRel<R,F>) {
        self.0.revert(&mut rel.source)
    }
}

#[test]
fn test_filter_rel() {
    col!{A: usize}
    col!{B: usize}

    use crate::relation::{Relation,OpaqueRel};
    use crate::record::Record;
    let source: OpaqueRel<Vec<(A,B)>> = OpaqueRel::new(vec![ (A(3), B(6)), (A(5), B(2)), (A(3), B(7)) ]);

    let result: Vec<usize> = source.as_ref().where_eq(A(3)).into_iter().map(|r| **r.col_ref::<B>()).collect();
    assert_eq!(vec![6usize,7], result);

    let result: Vec<usize> = source.where_eq(A(3)).into_iter().map(|r| **r.col_ref::<B>()).collect();
    assert_eq!(vec![6usize,7], result);
}

#[test]
fn test_filter_rel_ref() {
    col!{A: usize}
    col!{B: usize}

    use crate::relation::{Relation,OpaqueRel};
    use crate::record::Record;
    let source: OpaqueRel<Vec<(A,B)>> = OpaqueRel::new(vec![ (A(3), B(6)), (A(5), B(2)), (A(3), B(7)) ]);

    let result: Vec<usize> = source.as_ref().where_eq(&A(3)).into_iter().map(|r| **r.col_ref::<B>()).collect();
    assert_eq!(vec![6usize,7], result);

    let result: Vec<usize> = source.where_eq(&A(3)).into_iter().map(|r| **r.col_ref::<B>()).collect();
    assert_eq!(vec![6usize,7], result);
}