mem-query 0.0.1

Relational algebra interface for Rust collections
use crate::{
    relation::{RelationImpl,Queryable,Relation,QueryOutput},
    header::{Header, ProjectFrom},
    query::{
        QueryPlanImpl,
        request::{QueryRequest, NewRequest},
    },
    record::{Record, proj::Projection},
};

use tylisp::{
    sexpr, defun, defun_nocalc, HNil,
    engine::{Eval},
    ops::{
        Phantom, Ret,
        list::{BuildList,Intersect},
    },
};

use std::marker::PhantomData;

pub struct RenamedRel<Rel,A,B> {
    pub(crate) source: Rel,
    pub(crate) cols: PhantomData<(A,B)>,
}

impl<Rel, A, B, Cols, FastCols> RelationImpl for RenamedRel<Rel,A,B>
where
    A: Col, B:Col<Inner = A>,
    Rel: RelationImpl<Cols=Cols, FastCols=FastCols>,
    Cols: Header + RenameCol<A,B>,
    Cols::Renamed: Header,
    FastCols: Header + RenameCol<A,B>,
    FastCols::Renamed: Header,
{
    type Cols = Cols::Renamed;
    type FastCols = FastCols::Renamed;
    type Planner = Planner;
}


// ============================

impl<'a,A,B,Cols> QueryOutput<'a> for RenamedRel<Rel,A,B>
where
    A: Col, B:Col<Inner=A::Inner>,
    Rel: QueryOutput<'a>,
    Cols: Header,
    Cols: ProjectFrom<Rel::Cols>,
    Self: RelationImpl<Cols = Cols>,
{
    type QueryRow = Rename<Rel::QueryRow, A,B>;
}

#[derive(Default,Copy,Clone,Debug)]
pub struct IterAllQuery;
defun!{ IterAllQuery {
    (Src: RelationImpl, Cols: Header) {_:PhantomData<Src>, _:PhantomData<Cols>} =>
        {NewRequest, {BuildList},
                     {Phantom, @HNil}};
}}

impl<'a,R,C> IntoIterator for &'a RenamedRel<R,C>
where
    RenamedRel<R,C>: RelationImpl,
    R: Relation<'a>,
    C: ProjectFrom<R::Cols>,
{
    type Item = Projection<R::QueryRow, C>;
    type IntoIter = impl Iterator<Item = Self::Item>;
    fn into_iter(self)->Self::IntoIter {
        self.source.iter_all().map(|r| r.project())
    }
}

pub struct IterAs<'a, Src,Out> {
    pub(crate) source: &'a Src,
    pub(crate) target: PhantomData<Out>
}

impl<'a, Src,Out:'a> IntoIterator for IterAs<'a, Src,Out>
where
    Out: crate::record::FromExternalRecord<'a>,
    Src: Relation<'a>,
    Out::Cols: ProjectFrom<Src::Cols>,
{
    type Item = Out;
    type IntoIter = impl Iterator<Item = Out>;
    fn into_iter(self)->Self::IntoIter {
        self.source.iter_all().map(Out::from_ext_rec)
    }
}

#[derive(Default,Copy,Clone,Debug)]
pub struct Planner;
defun_nocalc!{() Planner {
    ('a, Rel, Req) {_: &'a Rel, _: Req} => {Ret, @RenamedRelPlan<'a, Rel, Req>};
}}

pub struct RenamedRelPlan<'a, Rel, Req> {
    proj: &'a Rel,
    req: Req,
}

impl<'a, Rel, Req, Cols> IntoIterator for RenamedRelPlan<'a, RenamedRel<Rel,Cols>, Req>
where
    Cols: Header,
    Req: QueryRequest + 'a,
    Rel: Queryable<'a, Req>,
    Cols: ProjectFrom<Rel::Cols>
{
    type Item = Projection<Rel::QueryRow, Cols>;
    type IntoIter = impl Iterator<Item = Self::Item>;
    fn into_iter(self)->Self::IntoIter {
        self.proj.source.query(self.req).map(|r| r.project())
    }
}

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

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

    use crate::relation::{Relation,SelfQuery,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<B> = source.as_ref().where_eq(A(3)).project::<sexpr!{B}>().iter_all().map(|rec| rec.into_cols().head).collect();
    assert_eq!(vec![B(6), B(7)], result);
    let result: Vec<B> = source.where_eq(A(3)).project::<sexpr!{B}>().iter_all().map(|rec| rec.into_cols().head).collect();
    assert_eq!(vec![B(6), B(7)], result);
}

#[test]
fn test_iter_as() {
    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<B> = source.as_ref().where_eq(A(3)).iter_as().collect();
    assert_eq!(vec![B(6), B(7)], result);

    let result: Vec<B> = source.where_eq(A(3)).iter_as().collect();
    assert_eq!(vec![B(6), B(7)], result);
}