use super::build::*;
use super::{build::CompareOp, Resolvable};
use crate::entity::EntityID;
use crate::{entity::EntityColumn, model::Modelable, Entity, QueryInterface};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
pub trait Filterable<'r, 'q>: Resolvable<'r, 'q>
where
'q: 'r,
{
type Table: Entity;
type Output;
fn by<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
self,
col: C,
given: &'r G,
) -> Filter<'r, 'q, Self, C, G>
where
Self: Sized,
{
Filter {
wrap: self,
col,
op: CompareOp::Equals,
given,
_ghost: PhantomData,
}
}
fn by_id<I: EntityID<Entity = Self::Table>>(
self,
given: &'r I,
) -> Filter<'r, 'q, Self, <Self::Table as Entity>::IDColumn, I>
where
Self: Sized,
{
Filter {
wrap: self,
col: Self::Table::id_column(),
op: CompareOp::Equals,
given,
_ghost: PhantomData,
}
}
fn by_op<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
self,
col: C,
op: CompareOp,
given: &'r G,
) -> Filter<'r, 'q, Self, C, G>
where
Self: Sized,
{
Filter {
wrap: self,
col,
op,
given,
_ghost: PhantomData,
}
}
}
pub struct Filter<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
where
'q: 'r,
{
wrap: F,
col: C,
op: CompareOp,
given: &'r G,
_ghost: PhantomData<&'q ()>,
}
impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> StaticVersion
for Filter<'r, 'q, F, C, G>
where
<F as StaticVersion>::Is: Filterable<'static, 'static>,
{
type Is = Filter<'static, 'static, <F as StaticVersion>::Is, C, u64>;
}
impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> QueryComponent
for Filter<'r, 'q, F, C, G>
where
<F as StaticVersion>::Is: Filterable<'static, 'static>,
'q: 'r,
{
fn derive(&self) -> DerivedQuery {
self.wrap.derive().add(
QueryPart::Where,
format!("`{}` {} ?", self.col.name(), self.op.ch()),
)
}
fn contribute<H: Hasher>(&self, hasher: &mut H) {
self.wrap.contribute(hasher);
std::any::TypeId::of::<Self::Is>().hash(hasher);
std::any::TypeId::of::<C>().hash(hasher);
}
fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, crate::Error> {
let next_index = self.wrap.bind(stmt)?;
self.given.bind_to(stmt, next_index)?;
Ok(next_index + 1)
}
}
impl<'r, 'q, O, F: Filterable<'r, 'q, Output = O>, C: EntityColumn, G: Modelable + ?Sized>
Resolvable<'r, 'q> for Filter<'r, 'q, F, C, G>
where
<F as StaticVersion>::Is: Filterable<'static, 'static>,
'q: 'r,
{
type Output = O;
fn qi(&self) -> &'r QueryInterface<'q> {
self.wrap.qi()
}
}
impl<'r, 'q, O, F: Filterable<'r, 'q, Output = O>, C: EntityColumn, G: Modelable + ?Sized>
Filterable<'r, 'q> for Filter<'r, 'q, F, C, G>
where
<F as StaticVersion>::Is: Filterable<'static, 'static>,
'q: 'r,
{
type Output = O;
type Table = C::Entity;
}