mem-query 0.0.1

Relational algebra interface for Rust collections
use std::collections::BTreeSet;
use std::marker::PhantomData;
use crate::{
    col::Col,
    header::{Header,HasCol},
    relation::{Relation, RelationImpl,Queryable,QueryOutput,ExternalRecord},
    query::{QueryPlanImpl,request::QueryRequest},
};

use tylisp::{defun, ops::Ret};

struct Unique<C,R>{
    rel: R,
    col: PhantomData<C>
}

impl<C:Col+Ord, R:RelationImpl> Unique<C,R> {
    fn new(rel:R)->Self {
        Unique { rel, col: PhantomData }
    }
}

impl<C:Col,R> RelationImpl for Unique<C,R> where
    R: RelationImpl,
    R::Cols: HasCol<C> {
    type Cols = R::Cols;
    type FastCols = R::FastCols;
    type Planner = UniquePlanner;
}

#[derive(Debug, Default)]
pub struct UniquePlanner;
defun!{UniquePlanner {
    ('a, C:Col, R:QueryOutput<'a>, Req)
    { _:&'a Unique<C,R>, _:Req }
    => { Ret, @UniquePlan<'a, C, R::QueryRow> };
}}


struct UniquePlan<'a,C:Col,Out>
{
    seen: BTreeSet<&'a C>,
    iter: Box<dyn Iterator<Item=Out> + 'a>
}

impl<'a,C:Col,R> QueryOutput<'a> for Unique<C,R> where
    R:QueryOutput<'a, Cols=Self::Cols>,
    Self:RelationImpl
{
    type QueryRow = R::QueryRow;
}

impl<'a,C:Col+Ord,Out> Iterator for UniquePlan<'a,C,Out> where
    Out: ExternalRecord<'a>,
    Out::Cols: HasCol<C>
{
    type Item = Out;
    fn next(&mut self)->Option<Self::Item> {
        for result in &mut self.iter {
            if self.seen.insert(result.ext_col_ref()) {
                return Some(result)
            }
        }
        None
    }
}

impl<'a,C:Col+Ord,R,Q> QueryPlanImpl<'a,Unique<C,R>,Q>
for UniquePlan<'a,C,R::QueryRow> where
    Q: QueryRequest + 'a,
    R: Queryable<'a, Q>,
{
    fn prepare(r: &'a Unique<C,R>, q:Q)->Self {
        UniquePlan {
            seen: BTreeSet::new(),
            iter: Box::new(r.rel.query(q))
        }
    }
}

impl<'a,R,C> IntoIterator for &'a Unique<C,R> where
    R: Relation<'a>,
    C: Col + Ord,
    R::Cols: HasCol<C>,
    &'a R: IntoIterator<Item = R::QueryRow>
{
    type IntoIter = UniquePlan<'a,C,R::QueryRow>;
    type Item = R::QueryRow;
    fn into_iter(self)->Self::IntoIter {
        UniquePlan {
            seen: BTreeSet::new(),
            iter: Box::new(<&R as IntoIterator>::into_iter(&self.rel))
        }
    }
}

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

    let rel = vec![(A(1), B(1)), (A(2), B(2)), (A(1), B(3))];
    let out:Vec<B> = Unique::<A,_>::new(rel).iter_as().collect();

    assert_eq!(out, vec![B(1), B(2)]);
}