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 ProjectedRel<Rel, Cols> {
pub(crate) source: Rel,
pub(crate) cols: PhantomData<Cols>,
}
impl<Rel, Cols, FastCols> RelationImpl for ProjectedRel<Rel,Cols>
where
Rel: RelationImpl,
Cols: Header,
Cols: ProjectFrom<Rel::Cols>,
FastCols: Header,
sexpr!{Intersect, {Phantom, @Cols}, @Rel::FastCols}: Eval<Result=FastCols>,
{
type Cols = Cols;
type FastCols = FastCols;
type Planner = Planner;
}
impl<'a,Rel,Cols> QueryOutput<'a> for ProjectedRel<Rel,Cols>
where
Rel: QueryOutput<'a>,
Cols: Header,
Cols: ProjectFrom<Rel::Cols>,
Self: RelationImpl<Cols = Cols>,
{
type QueryRow = Projection<Rel::QueryRow, Cols>;
}
#[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 ProjectedRel<R,C>
where
ProjectedRel<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, @ProjectedRelPlan<'a, Rel, Req>};
}}
pub struct ProjectedRelPlan<'a, Rel, Req> {
proj: &'a Rel,
req: Req,
}
impl<'a, Rel, Req, Cols> IntoIterator for ProjectedRelPlan<'a, ProjectedRel<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 ProjectedRelPlan<'a, Rel, Req>
where
{
fn prepare(proj: &'a Rel, req: Req)->Self {
ProjectedRelPlan { 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);
}
#[test] fn test_iter_as_example() {
col!{ProjectId: usize}
col!{QtyCommitted: usize}
let rel = vec![
(ProjectId(1), QtyCommitted(3)),
(ProjectId(2), QtyCommitted(5)),
(ProjectId(3), QtyCommitted(7)),
];
let mut total = 0;
for &QtyCommitted(qty) in rel.iter_as() {
total += qty;
}
assert_eq!(15, total);
}