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)]);
}