use std::fmt::Write;
use crate::{
db::StatementContext,
query::{QueryPart, Queryable, RelationInterface},
schema::{
datum::{BorrowedDatum, BorrowedDatumList, Datum, DatumDiscriminator, DatumVisitor},
entity::{Entity, EntityPart, EntityPartList, EntityPartVisitor},
relation::{LocalSide, Relation},
Stored,
},
DBResult, Error,
};
use super::{OutputContainer, Query};
pub(crate) struct TableComponent<E: Entity> {
_ghost: std::marker::PhantomData<E>,
}
impl<E: Entity> Clone for TableComponent<E> {
fn clone(&self) -> Self {
Self {
_ghost: Default::default(),
}
}
}
impl<E: Entity> TableComponent<E> {
pub fn new() -> Self {
Self {
_ghost: Default::default(),
}
}
}
impl<E: Entity> Queryable for TableComponent<E> {
type EntityOutput = E;
type OutputContainer = Vec<Stored<E>>;
type StaticVersion = Self;
fn build(&self) -> DBResult<Query<'_>> {
Ok(Query::new()
.attach(QueryPart::Root, "SELECT DISTINCT")
.attach(QueryPart::Columns, "*")
.attach(QueryPart::From, format!("`{}`", E::entity_name())))
}
fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) -> DBResult<()> {
Ok(())
}
}
#[derive(Clone)]
pub(crate) struct WithComponent<
'a,
WEP: EntityPart,
Parent: Queryable,
BD: BorrowedDatum<'a, WEP::Datum>,
> {
datum: BD,
parent: Parent,
_ghost: std::marker::PhantomData<&'a WEP>,
}
impl<'a, WEP: EntityPart, Parent: Queryable, BD: BorrowedDatum<'a, WEP::Datum>>
WithComponent<'a, WEP, Parent, BD>
{
pub fn new(parent: Parent, _part: WEP, datum: BD) -> Self {
Self {
datum,
parent,
_ghost: Default::default(),
}
}
}
#[derive(Clone)]
pub(crate) struct CanonicalWithComponent<WEP: EntityPart, Parent: Queryable> {
_ghost: std::marker::PhantomData<(WEP, Parent)>,
}
impl<WEP: EntityPart, Parent: Queryable + 'static> Queryable
for CanonicalWithComponent<WEP, Parent>
{
type EntityOutput = WEP::Entity;
type OutputContainer = Option<Stored<WEP::Entity>>;
type StaticVersion = Self;
fn build(&self) -> DBResult<Query<'_>> {
unreachable!()
}
fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) -> DBResult<()> {
unreachable!()
}
}
impl<
'a,
Parent: Queryable,
WEP: EntityPart<Entity = Parent::EntityOutput>,
BD: BorrowedDatum<'a, WEP::Datum>,
> Queryable for WithComponent<'a, WEP, Parent, BD>
{
type EntityOutput = WEP::Entity;
type OutputContainer = Parent::OutputContainer;
type StaticVersion = CanonicalWithComponent<WEP, Parent::StaticVersion>;
fn build(&self) -> DBResult<Query<'_>> {
Ok(self.parent.build()?.attach(
QueryPart::Where,
format!(
"`{}`.`{}` = ?",
<Self::EntityOutput>::entity_name(),
WEP::part_name()
),
))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)?;
self.datum.bind_to(stmt, *index)?;
*index += 1;
Ok(())
}
}
pub(crate) struct FilterComponent<
'a,
Parent: Queryable,
EPL: EntityPartList,
const OP: u8,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> {
datum: BDL,
parent: Parent,
_ghost: std::marker::PhantomData<&'a EPL>,
}
impl<
'a,
Parent: Queryable,
EPL: EntityPartList,
const OP: u8,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> FilterComponent<'a, Parent, EPL, OP, BDL>
{
pub fn new(parent: Parent, datum: BDL) -> Self {
Self {
datum,
parent,
_ghost: Default::default(),
}
}
}
impl<
'a,
Parent: Queryable,
EPL: EntityPartList,
const OP: u8,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> Clone for FilterComponent<'a, Parent, EPL, OP, BDL>
{
fn clone(&self) -> Self {
Self {
parent: self.parent.clone(),
datum: self.datum,
_ghost: Default::default(),
}
}
}
pub(crate) struct CanonicalFilterComponent<Parent: Queryable, EPL: EntityPartList, const OP: u8> {
_ghost: std::marker::PhantomData<(Parent, EPL)>,
}
impl<Parent: Queryable, EPL: EntityPartList, const OP: u8> Clone
for CanonicalFilterComponent<Parent, EPL, OP>
{
fn clone(&self) -> Self {
Self {
_ghost: Default::default(),
}
}
}
impl<Parent: Queryable + 'static, EPL: EntityPartList, const OP: u8> Queryable
for CanonicalFilterComponent<Parent, EPL, OP>
{
type EntityOutput = Parent::EntityOutput;
type OutputContainer = Parent::OutputContainer;
type StaticVersion = Self;
fn build(&self) -> DBResult<Query<'_>> {
unreachable!()
}
fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) -> DBResult<()> {
unreachable!()
}
}
impl<
'a,
Parent: Queryable,
EPL: EntityPartList,
const OP: u8,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> Queryable for FilterComponent<'a, Parent, EPL, OP, BDL>
{
type EntityOutput = Parent::EntityOutput;
type OutputContainer = Parent::OutputContainer;
type StaticVersion = CanonicalFilterComponent<Parent::StaticVersion, EPL, OP>;
fn build(&self) -> DBResult<Query<'_>> {
fn process<PL: EntityPartList>(query: &mut Query<'_>, op: &str) {
if PL::IS_EMPTY {
return;
}
query.attach_mut(
QueryPart::Where,
format!(
"`{}`.`{}` {op} ?",
PL::Entity::entity_name(),
PL::ListHead::part_name()
),
);
process::<PL::ListTail>(query, op);
}
let mut query = self.parent.build()?;
process::<EPL>(
&mut query,
match OP {
0 => "<",
1 => "<=",
2 => "=",
3 => ">=",
4 => ">",
5 => "GLOB",
6 => "REGEXP",
_ => unreachable!("FilterComponent with unknown operator"),
},
);
Ok(query)
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)?;
struct Visitor<'a, 'b>(&'a mut StatementContext<'b>, &'a mut i32);
impl DatumVisitor for Visitor<'_, '_> {
fn visit<ED: Datum>(&mut self, datum: &ED) -> DBResult<()> {
datum.bind_to(self.0, *self.1)?;
*self.1 += 1;
Ok(())
}
}
self.datum.accept(&mut Visitor(stmt, index))
}
}
pub(crate) struct IndexComponent<
'a,
E: Entity,
Parent: Queryable,
EPL: EntityPartList<Entity = E>,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> {
datum: BDL,
parent: Parent,
_ghost: std::marker::PhantomData<&'a (E, EPL)>,
}
impl<
'a,
E: Entity,
Parent: Queryable,
EPL: EntityPartList<Entity = E>,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> IndexComponent<'a, E, Parent, EPL, BDL>
{
pub fn new(parent: Parent, datum: BDL) -> Self {
Self {
datum,
parent,
_ghost: Default::default(),
}
}
}
impl<
'a,
E: Entity,
Parent: Queryable,
EPL: EntityPartList<Entity = E>,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> Clone for IndexComponent<'a, E, Parent, EPL, BDL>
{
fn clone(&self) -> Self {
Self {
datum: self.datum,
parent: self.parent.clone(),
_ghost: Default::default(),
}
}
}
pub(crate) struct CanonicalIndexComponent<
E: Entity,
Parent: Queryable,
EPL: EntityPartList<Entity = E>,
> {
_ghost: std::marker::PhantomData<(E, Parent, EPL)>,
}
impl<E: Entity, Parent: Queryable + 'static, EPL: EntityPartList<Entity = E>> Queryable
for CanonicalIndexComponent<E, Parent, EPL>
{
type EntityOutput = E;
type OutputContainer = Option<Stored<E>>;
type StaticVersion = Self;
fn build(&self) -> DBResult<Query<'_>> {
unreachable!()
}
fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) -> DBResult<()> {
unreachable!()
}
}
impl<E: Entity, Parent: Queryable + 'static, EPL: EntityPartList<Entity = E>> Clone
for CanonicalIndexComponent<E, Parent, EPL>
{
fn clone(&self) -> Self {
Self {
_ghost: Default::default(),
}
}
}
impl<
'a,
E: Entity,
Parent: Queryable,
EPL: EntityPartList<Entity = E>,
BDL: BorrowedDatumList<'a, EPL::DatumList>,
> Queryable for IndexComponent<'a, E, Parent, EPL, BDL>
{
type EntityOutput = E;
type OutputContainer = Option<Stored<E>>;
type StaticVersion = CanonicalIndexComponent<E, Parent::StaticVersion, EPL>;
fn build(&self) -> DBResult<Query<'_>> {
let mut query = self.parent.build()?;
struct PartVisitor<'a, 'b, E: Entity>(&'a mut Query<'b>, std::marker::PhantomData<E>);
impl<E: Entity> EntityPartVisitor for PartVisitor<'_, '_, E> {
type Entity = E;
fn visit<EP: EntityPart>(&mut self) {
self.0.attach_mut(
QueryPart::Where,
format!(
"`{}`.`{}` = ?",
<EP::Entity>::entity_name(),
EP::part_name()
),
);
}
}
EPL::accept_part_visitor(&mut PartVisitor::<E>(&mut query, Default::default()));
Ok(query)
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)?;
struct Visitor<'a, 'b>(&'a mut StatementContext<'b>, &'a mut i32);
impl DatumVisitor for Visitor<'_, '_> {
fn visit<ED: Datum>(&mut self, datum: &ED) -> DBResult<()> {
datum.bind_to(self.0, *self.1)?;
*self.1 += 1;
Ok(())
}
}
self.datum.accept(&mut Visitor(stmt, index))
}
}
#[derive(Clone)]
pub(crate) struct SingleComponent<Parent: Queryable> {
parent: Parent,
}
impl<Parent: Queryable> SingleComponent<Parent> {
pub fn new(parent: Parent) -> Self {
Self { parent }
}
}
impl<Parent: Queryable> Queryable for SingleComponent<Parent> {
type EntityOutput = Parent::EntityOutput;
type OutputContainer = Option<Stored<Self::EntityOutput>>;
type StaticVersion = SingleComponent<Parent::StaticVersion>;
fn build(&self) -> DBResult<Query<'_>> {
let q = self.parent.build()?;
if q.parts.contains_key(&QueryPart::Limit) {
return Err(Error::LogicError("repeated limit on query"));
}
Ok(q.attach(QueryPart::Limit, "LIMIT 1"))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)
}
}
pub(crate) struct OrderByComponent<Parent: Queryable, EPL: EntityPartList, const ASC: bool> {
parent: Parent,
_ghost: std::marker::PhantomData<(Parent, EPL)>,
}
impl<Parent: Queryable, EPL: EntityPartList, const ASC: bool> OrderByComponent<Parent, EPL, ASC> {
pub fn new(parent: Parent, _parts: EPL) -> Self {
Self {
parent,
_ghost: Default::default(),
}
}
}
impl<Parent: Queryable, EPL: EntityPartList, const ASC: bool> Clone
for OrderByComponent<Parent, EPL, ASC>
{
fn clone(&self) -> Self {
Self {
parent: self.parent.clone(),
_ghost: Default::default(),
}
}
}
impl<Parent: Queryable, EPL: EntityPartList, const ASC: bool> Queryable
for OrderByComponent<Parent, EPL, ASC>
{
type EntityOutput = Parent::EntityOutput;
type OutputContainer = Parent::OutputContainer;
type StaticVersion = OrderByComponent<Parent::StaticVersion, EPL, ASC>;
fn build(&self) -> DBResult<Query<'_>> {
fn process<PL: EntityPartList>(out: &mut String, asc: bool) {
if PL::IS_EMPTY {
return;
}
write!(
out,
"{}.{} {}",
PL::Entity::entity_name(),
PL::ListHead::part_name(),
if asc { "ASC" } else { "DESC" }
)
.unwrap();
if !<PL::ListTail as EntityPartList>::IS_EMPTY {
write!(out, ", ").unwrap()
}
process::<PL::ListTail>(out, asc);
}
let mut clauses = String::new();
process::<EPL>(&mut clauses, ASC);
Ok(self
.parent
.build()?
.replace(QueryPart::Order, format!("ORDER BY {clauses}")))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)
}
}
#[derive(Clone)]
pub(crate) struct LimitComponent<Parent: Queryable, const HAS_OFFSET: bool> {
parent: Parent,
limit: usize,
offset: Option<usize>,
}
impl<Parent: Queryable> LimitComponent<Parent, false> {
pub(crate) fn new(parent: Parent, limit: usize) -> Self {
Self {
parent,
limit,
offset: None,
}
}
}
impl<Parent: Queryable> LimitComponent<Parent, true> {
pub(crate) fn new_with_offset(parent: Parent, limit: usize, offset: usize) -> Self {
Self {
parent,
limit,
offset: Some(offset),
}
}
}
impl<Parent: Queryable, const HAS_OFFSET: bool> Queryable for LimitComponent<Parent, HAS_OFFSET> {
type EntityOutput = Parent::EntityOutput;
type StaticVersion = LimitComponent<Parent::StaticVersion, HAS_OFFSET>;
type OutputContainer = Parent::OutputContainer;
fn build(&self) -> DBResult<Query<'_>> {
let q = self.parent.build()?;
if q.parts.contains_key(&QueryPart::Limit) {
return Err(Error::LogicError("repeated limit on query"));
}
Ok(q.attach(
QueryPart::Limit,
if HAS_OFFSET {
"LIMIT ? OFFSET ?"
} else {
"LIMIT ?"
},
))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)?;
log::trace!(
"binding limit ({}) to statement at index {index}",
self.limit
);
self.limit.bind_to(stmt, *index)?;
*index += 1;
if HAS_OFFSET {
self.offset.bind_to(stmt, *index)?;
*index += 1;
}
Ok(())
}
}
pub(crate) struct JoinComponent<R: Entity, L: Entity, EP: EntityPart<Entity = L>, Parent: Queryable>
{
parent: Parent,
_ghost: std::marker::PhantomData<(L, R, EP)>,
}
impl<R: Entity, L: Entity, EP: EntityPart<Entity = L>, Parent: Queryable>
JoinComponent<R, L, EP, Parent>
{
pub fn new(parent: Parent, _part: EP) -> Self {
Self {
parent,
_ghost: Default::default(),
}
}
}
impl<R: Entity, L: Entity, EP: EntityPart<Entity = L>, Parent: Queryable> Clone
for JoinComponent<R, L, EP, Parent>
{
fn clone(&self) -> Self {
Self {
parent: self.parent.clone(),
_ghost: Default::default(),
}
}
}
impl<
R: Entity,
L: Entity,
EP: EntityPart<Entity = L, Datum = AI>,
AI: RelationInterface + Datum,
Parent: Queryable,
> Queryable for JoinComponent<R, L, EP, Parent>
{
type EntityOutput = R;
type OutputContainer = Vec<Stored<R>>;
type StaticVersion = JoinComponent<R, L, EP, Parent::StaticVersion>;
fn build(&self) -> DBResult<Query<'_>> {
let remote_name = R::entity_name();
let local_name = L::entity_name();
struct Discriminator(Option<(&'static str, &'static str)>, Option<&'static str>);
impl DatumDiscriminator for Discriminator {
fn visit_entity_id<E: Entity>(&mut self) {
unreachable!()
}
fn visit_serialized<T: serde::Serialize + serde::de::DeserializeOwned>(&mut self) {
unreachable!()
}
fn visit_bare_field<T: Datum>(&mut self) {
unreachable!()
}
fn visit_relation_map<E: Entity>(&mut self) {
self.0 = Some(("domain", "range"));
}
fn visit_relation_domain<R: Relation>(&mut self) {
self.0 = Some(("domain", "range"));
self.1 = Some(R::NAME);
}
fn visit_relation_range<R: Relation>(&mut self) {
self.0 = Some(("range", "domain"));
self.1 = Some(R::NAME);
}
fn visit_value<T: serde::de::DeserializeOwned>(&mut self) {
unreachable!()
}
}
let mut d = Discriminator(None, None);
<EP::Datum>::accept_discriminator(&mut d);
let (local_field, remote_field) = d.0.unwrap();
let relation_name = match AI::SIDE {
LocalSide::Range => {
format!(
"{remote_name}_{local_name}_relation_{}",
d.1.unwrap_or(EP::part_name())
)
},
LocalSide::Domain => {
format!(
"{local_name}_{remote_name}_relation_{}",
d.1.unwrap_or(EP::part_name())
)
},
};
Ok(self
.parent
.build()?
.attach(
QueryPart::Join,
format!(
"`{relation_name}` ON `{local_name}`.`id` = `{relation_name}`.`{local_field}`"
),
)
.attach(
QueryPart::Join,
format!(
"`{remote_name}` ON `{relation_name}`.`{remote_field}` = `{remote_name}`.`id`"
),
)
.replace(QueryPart::Columns, format!("`{remote_name}`.*")))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)
}
}
pub(crate) struct ForeignComponent<FE: Entity, EP: EntityPart, Parent: Queryable> {
parent: Parent,
_ghost: std::marker::PhantomData<(FE, EP)>,
}
impl<FE: Entity, EP: EntityPart, Parent: Queryable> ForeignComponent<FE, EP, Parent> {
pub fn new(parent: Parent, _part: EP) -> Self {
Self {
parent,
_ghost: Default::default(),
}
}
}
impl<FE: Entity, EP: EntityPart, Parent: Queryable> Clone for ForeignComponent<FE, EP, Parent> {
fn clone(&self) -> Self {
Self {
parent: self.parent.clone(),
_ghost: Default::default(),
}
}
}
impl<FE: Entity, EP: EntityPart, Parent: Queryable> Queryable for ForeignComponent<FE, EP, Parent> {
type EntityOutput = FE;
type StaticVersion = ForeignComponent<FE, EP, Parent::StaticVersion>;
type OutputContainer =
<Parent::OutputContainer as OutputContainer<Parent::EntityOutput>>::WithReplacedEntity<FE>;
fn build(&self) -> DBResult<Query<'_>> {
let current_name = EP::Entity::entity_name();
let current_field = EP::part_name();
let foreign_name = FE::entity_name();
Ok(self.parent.build()?.replace(
QueryPart::Columns,
format!("`{foreign_name}`.*")
).attach(
QueryPart::Join,
format!("`{foreign_name}` ON `{foreign_name}`.`id` = `{current_name}`.`{current_field}`")
))
}
fn bind(&self, stmt: &mut StatementContext, index: &mut i32) -> DBResult<()> {
self.parent.bind(stmt, index)
}
}