mem-query 0.0.1

Relational algebra interface for Rust collections
use super::{RelationImpl,Relation,Queryable,QueryOutput,Insert,Delete};
use tylisp::{defun, ops::Ret};
use crate::{
    query::{QueryPlanImpl, request::QueryRequest, filter::QueryFilter},
    transaction::{RevertableOp,Transaction,UndoLog,Accessor},
    header::Header,
    record::Record,
};
use std::ops::{Deref,DerefMut};

#[derive(Clone,Debug)]
pub struct RelProxy<Ptr>(Ptr);

impl<Ptr> RelProxy<Ptr> {
    pub fn new(rel: impl Into<Ptr>) -> Self {
        RelProxy(rel.into())
    }
}

impl<Ptr:Deref> Deref for RelProxy<Ptr> {
    type Target = Ptr::Target;
    fn deref(&self)->&Ptr::Target { self.0.deref() }
}

impl<Ptr:Deref<Target=R>, R:RelationImpl> RelationImpl for RelProxy<Ptr> {
    type Cols = R::Cols;
    type FastCols = R::FastCols;
    type Planner = ProxyPlanner; 
//    type Planner = crate::query::fallback::FallbackPlanner; 
}

impl<'a, Ptr:Deref<Target = R>, R:QueryOutput<'a>>
QueryOutput<'a> for RelProxy<Ptr> {
    type QueryRow = R::QueryRow;
}

impl<'a, Ptr:Deref<Target=R>, R:'a + Relation<'a>>
IntoIterator for &'a RelProxy<Ptr> {
    type IntoIter = impl Iterator<Item = Self::Item>;
    type Item = R::QueryRow;

    fn into_iter(self)->Self::IntoIter {
        let r:&'a R = &*self.0;
        r.iter_all()
    }
}

pub struct ProxyPlan<'a, Ptr, Req>(&'a RelProxy<Ptr>, Req);

impl<'a, Ptr:'a + Deref<Target=Rel>, Req:'a, Rel> IntoIterator for ProxyPlan<'a, Ptr, Req>
where Rel: Queryable<'a, Req>,
      Req: QueryRequest,
{
    type Item = Rel::QueryRow;
    type IntoIter = <Rel::Plan as IntoIterator>::IntoIter;
    fn into_iter(self)->Self::IntoIter {
        let r:&'a Rel = &*self.0;
        r.query(self.1)
    }
}

impl<'a, Ptr, Req> QueryPlanImpl<'a, RelProxy<Ptr>, Req> for ProxyPlan<'a, Ptr, Req> {
    // type EstimatedCost;
    fn prepare(rel: &'a RelProxy<Ptr>, req: Req)->Self {
        ProxyPlan(rel, req)
    }
}

#[derive(Debug,Default)]
pub struct ProxyPlanner;
defun!{ ProxyPlanner {
    ('a, Rel:'a, Req) { _:&'a RelProxy<Rel>, _:Req } => { Ret, @ProxyPlan<'a, Rel, Req> };
}}

impl<Ptr:DerefMut<Target=R>, R, H> Insert<H> for RelProxy<Ptr>
where
    R: Insert<H>,
    H: Header,
{
    type Remainder = R::Remainder;
    type Op = ProxyOp<R::Op>;

    fn insert_op<FromRec:Record<Cols=H>>(rec:FromRec)
    -> (Self::Op, Self::Remainder) {
        let (op, remainder) = R::insert_op(rec);
        (ProxyOp(op), remainder)
    }
}

impl<Ptr:DerefMut<Target=R>, R, Q> Delete<Q> for RelProxy<Ptr>
where
    R: Delete<Q>,
    Q: QueryFilter,
{
    type Op = ProxyOp<R::Op>;
    type Deleter = impl Fn(Q)->Self::Op;

    fn deleter() -> Self::Deleter {
        |q| ProxyOp((R::deleter())(q))
    }
}

pub struct ProxyOp<Op>(Op);

impl<Ptr, Op> RevertableOp<RelProxy<Ptr>> for ProxyOp<Op>
where
    Ptr: DerefMut,
    Op: RevertableOp<Ptr::Target>
{
    type Err = impl std::error::Error;
    type Log = impl UndoLog<RelProxy<Ptr>>;

    fn apply(self, proxy: &mut RelProxy<Ptr>)->Result<Self::Log,Self::Err> {
        Transaction::start(proxy)
            .subtransaction(AccessProxy, move |tx| tx.apply(self.0))
            .into_undo_log()
    }
}

struct AccessProxy;
impl<Ptr> Accessor<RelProxy<Ptr>> for AccessProxy
where Ptr: DerefMut {
    type Dest = Ptr::Target;
    fn access<F,O>(&self, proxy: &mut RelProxy<Ptr>, op:F)->O
        where F:FnOnce(&mut Self::Dest)->O
    {
        op(&mut *proxy.0)
    }
}