use super::{Deferred, Load};
use crate::stmt::{Association, List, Path, Query};
use toasty_core::schema::Name;
use toasty_core::schema::app::{self, FieldTy, ModelId, Via};
use toasty_core::stmt;
const UNRESOLVED_TARGET: ModelId = ModelId(usize::MAX);
pub trait ViaManyField {
type Target: ViaTarget;
const DEFERRED: bool;
}
impl<E: ViaTarget> ViaManyField for Vec<E> {
type Target = E;
const DEFERRED: bool = false;
}
impl<E: ViaTarget> ViaManyField for Deferred<Vec<E>> {
type Target = E;
const DEFERRED: bool = true;
}
pub type ViaMany<F> = <<F as ViaManyField>::Target as ViaTarget>::Query;
pub type ViaPath<F, Origin> = <<F as ViaManyField>::Target as ViaTarget>::Path<Origin>;
pub trait ViaTarget {
type Query;
type Path<Origin>;
fn via_field_ty(singular: Name, path: stmt::Path) -> FieldTy;
fn new_path<Origin>(path: Path<Origin, List<Self>>) -> Self::Path<Origin>
where
Self: Sized;
fn make_via_query(assoc: Association<List<Self>>) -> Self::Query
where
Self: Sized;
}
macro_rules! impl_via_many_scalar {
( $( $t:ty ),* $(,)? ) => {
$(
impl ViaTarget for $t {
type Query = Query<List<$t>>;
type Path<Origin> = Path<Origin, List<$t>>;
fn new_path<Origin>(path: Path<Origin, List<$t>>) -> Self::Path<Origin> {
path
}
fn via_field_ty(singular: Name, path: stmt::Path) -> FieldTy {
let terminal = *path
.projection
.as_slice()
.last()
.expect("via path has at least one step");
let expr_ty = stmt::Type::List(Box::new(<$t as Load>::ty()));
FieldTy::Via(Via::new(
UNRESOLVED_TARGET,
expr_ty,
app::Cardinality::Many { singular },
path,
Some(terminal),
))
}
fn make_via_query(assoc: Association<List<$t>>) -> Self::Query {
let mut query = stmt::Query::builder(stmt::SourceModel {
id: UNRESOLVED_TARGET,
via: Some(assoc.untyped),
})
.build();
query.body.as_select_mut_unwrap().distinct = true;
Query::from_untyped(query)
}
}
)*
};
}
impl_via_many_scalar!(
String,
bool,
i8,
i16,
i32,
i64,
u16,
u32,
u64,
isize,
usize,
f32,
f64,
uuid::Uuid,
);
#[cfg(feature = "rust_decimal")]
impl_via_many_scalar!(rust_decimal::Decimal);
#[cfg(feature = "bigdecimal")]
impl_via_many_scalar!(bigdecimal::BigDecimal);