mem-query 0.0.1

Relational algebra interface for Rust collections
use crate::prelude::*;
use crate::query::{
    QueryPlan,
    request::QueryRequest,
    filter::Exact,
};

use crate::col::ColProxy;
use crate::record::{ExternalRecord,FromExternalRecord,ErasedExtRecord};
use crate::header::ProjectRefFrom;
use crate::transaction::{Transaction,RevertableOp};
use std::marker::PhantomData;
use either::Either;

mod vec_opt;
mod smart_ptr;
mod btree_map_2;
mod insert;
mod delete;
//mod annotation;
mod subjoin;
mod peerjoin;
mod query;
mod opaque;
mod dynamic;
mod redundant;
mod unique;
mod split_vec;

pub use insert::Insert;
pub use delete::Delete;
//pub use hash_map::HashIndex;
pub use btree_map_2::BTreeIndex;
pub use smart_ptr::RelProxy;
pub use opaque::OpaqueRel;
pub use redundant::RedundantIndex;

pub trait RelationImpl {
    type Cols: Header;
    type FastCols: Header;

    type Planner; //: Eval;

    fn as_ref(&self)->RelProxy<&'_ Self> {
        RelProxy::new(self)
    }

    fn as_mut(&mut self)->RelProxy<&'_ mut Self> {
        RelProxy::new(self)
    }
}

pub trait QueryOutput<'a>: RelationImpl {
    type QueryRow: ExternalRecord<'a, Cols=Self::Cols>;
}

pub trait Relation<'a>: RelationImpl
                      + QueryOutput<'a>
                      + SelfQuery<'a>
                      + Sized
{
    fn subjoin<F:Col>(self) -> subjoin::SubordinateJoin<Self, F>
        where subjoin::SubordinateJoin<Self, F>: Relation<'a>
    {
        subjoin::SubordinateJoin::new(self)
    }


    /// TODO: Maybe reverse the join order; key lookup always on right-hand side
    fn join<Rel>(self, rel:Rel) -> peerjoin::PeerJoin<Self,Rel>
        where peerjoin::PeerJoin<Self,Rel>: Relation<'a>
    {
        peerjoin::PeerJoin::new(self,rel)
    }

    fn where_eq<C:ColProxy>(self, c:C) -> query::FilterRel<Self, Exact<C>>
        where 
              query::FilterRel<Self, Exact<C>>: Relation<'a>
    {
        query::FilterRel { source: self, filter: Exact(c) }
    }

    fn project<H:Header>(self) -> query::ProjectedRel<Self, H>
        where query::ProjectedRel<Self, H>: Relation<'a>
    {
        query::ProjectedRel { source: self, cols: PhantomData }
    }

    fn iter_as<O:FromExternalRecord<'a>>(&'a self) ->
        <query::IterAs<'a,Self,O> as IntoIterator>::IntoIter
    where
        query::IterAs<'a,Self,O>: IntoIterator
    {
        query::IterAs { source: self, target: PhantomData }.into_iter()
    }

    fn as_dyn(self) -> dynamic::DynRel<Self>
    where dynamic::DynRel<Self>: RelationImpl {
        dynamic::DynRel::new(self)
    }

    fn truncate(&mut self)->Result<(), <Self::Op as RevertableOp<Self>>::Err>
     where Self: Delete<HNil> {
        Transaction::start(self)
            .apply((Self::deleter())(HNil))
            .commit()
            .map_err(|e| e.left().unwrap())
    }
}

pub trait Queryable<'a, Req: QueryRequest+'a>: 'a + QueryOutput<'a> + Sized {
    type Plan: QueryPlan<'a, Self, Req>;
    fn explain(&'a self)->&'static str { std::any::type_name::<Self::Plan>() }
    fn query(&'a self, req:Req)
        -> <Self::Plan as IntoIterator>::IntoIter;
    fn prepare(&'a self, req:Req)->Self::Plan;
}

pub trait DynQueryable<'a, Req:QueryRequest+'a> {
    type Cols: Header;
    fn dyn_query(&'a self, req:Req)
        -> Box<dyn 'a + Iterator<Item = ErasedExtRecord<'a, Self::Cols>>>;
}

impl<'a, Req, T> DynQueryable<'a,Req> for T where
    Req: QueryRequest + 'a,
    T:Queryable<'a, Req>,
{
    type Cols = T::Cols;
    fn dyn_query(&'a self, req:Req)
        -> Box<dyn 'a + Iterator<Item = ErasedExtRecord<'a, T::Cols>>>
    {
        Box::new(self.query(req).map(|row| row.erase_type()))
    }
}

impl<'a, Rel, Req, Plan> Queryable<'a, Req> for Rel
where sexpr!{Self::Planner, @&'a Self, @Req}: Eval<Result=Plan>,
      Plan: QueryPlan<'a, Self, Req>,
      Req: QueryRequest + 'a,
      Rel: 'a + Relation<'a>,
{
    type Plan = Plan;
    fn query(&'a self, req:Req)
        -> <Plan as IntoIterator>::IntoIter
    {
        Plan::prepare(self, req).execute()
    }
    fn prepare(&'a self, req:Req)->Plan {
        Plan::prepare(self, req)
    }
}

impl<'a, T:RelationImpl + SelfQuery<'a>> Relation<'a> for T
where T:RelationImpl + SelfQuery<'a>
{
}


pub trait SelfQuery<'a>: QueryOutput<'a> {
    type Iter: Iterator<Item = Self::QueryRow>;
    fn iter_all(&'a self)->Self::Iter;
}

impl<'a,R> SelfQuery<'a> for R
where R: 'a + QueryOutput<'a>,
      &'a R: IntoIterator<Item = Self::QueryRow>,
{
    type Iter = <&'a R as IntoIterator>::IntoIter;
    fn iter_all(&'a self)->Self::Iter { self.into_iter() }
}