use crate::{
header::{ProjectFrom},
query::{
QueryPlanImpl,
request::*,
filter::QueryFilter,
order::SortKey,
},
relation::{Relation,Queryable},
};
use tylisp::{
sexpr, defun_nocalc,
typenum as tn,
marker_traits::List,
ops::{Cond, logic::Not, list::{EmptyP}},
};
#[derive(Debug, Default)]
pub struct FallbackPlanner;
defun_nocalc!{() FallbackPlanner {
('a, Rel:Relation<'a>, Req:QueryRequest) { _:&'a Rel, _:Req }
=> { Cond, {{Not, {EmptyP, @Req::OrderBy}}, @PostSortPlan<'a, Rel, Req>},
{tn::True, @FallbackPlan<'a, Rel, Req>}
};
}}
pub struct FallbackPlan<'a, Rel, Req>(&'a Rel, Req);
impl<'a,Rel,Req> IntoIterator for FallbackPlan<'a,Rel,Req>
where Rel: Relation<'a>,
Req: QueryRequest<OrderBy=sexpr!{}>,
Req::Filters: QueryFilter + 'a,
{
type Item = Rel::QueryRow;
type IntoIter = impl Iterator<Item = Self::Item>;
fn into_iter(self)->Self::IntoIter {
let filt = self.1.into_filters();
self.0.iter_all()
.filter(move |r| filt.test_record(r))
}
}
impl<'a, Rel, Req> QueryPlanImpl<'a, Rel, Req> for FallbackPlan<'a, Rel, Req>
where Rel: Relation<'a>,
{
fn prepare(rel: &'a Rel, req:Req)->Self { Self(rel,req) }
}
pub struct PostSortPlan<'a, Rel, Req>{
rel: &'a Rel,
req: Req,
}
impl<'a, Rel, Req> QueryPlanImpl<'a, Rel, Req> for PostSortPlan<'a, Rel, Req> {
fn prepare(rel: &'a Rel, req: Req)->Self { PostSortPlan{ rel, req } }
}
impl<'a,Rel,Req,Key> IntoIterator for PostSortPlan<'a, Rel, Req>
where Rel: Relation<'a> + Queryable<'a, ReplaceOrder<Req, sexpr!{}>>,
Req: QueryRequest<OrderBy=Key> + 'a,
ReplaceOrder<Req, sexpr!{}>: QueryRequest,
Key: SortKey + List,
Key::ReqCols: ProjectFrom<Rel::Cols>,
{
type IntoIter = std::vec::IntoIter<Self::Item>;
type Item = Rel::QueryRow;
fn into_iter(self)->Self::IntoIter {
use ::itertools::Itertools;
self.rel.query(self.req.set_order::<sexpr!{}>())
.sorted_by(Req::OrderBy::cmp::<Self::Item>)
}
}