use super::{Deferred, Load, Model, QueryMany, QueryOne, QueryOptionOne};
use toasty_core::schema::app::ModelId;
use toasty_core::schema::app::{self, FieldId, FieldTy, ForeignKey};
use toasty_core::stmt;
pub trait RelationOneField: Load<Output = Self> {
type Target: Model;
type One;
type Expr;
const DEFERRED: bool;
const NULLABLE: bool;
fn reload(target: &mut Self, value: stmt::Value) -> crate::Result<()>;
fn make_one(query: QueryMany<Self::Target>) -> Self::One;
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy;
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy;
}
impl<M: Model> RelationOneField for M {
type Target = M;
type One = QueryOne<M>;
type Expr = M;
const DEFERRED: bool = false;
const NULLABLE: bool = false;
fn reload(target: &mut Self, value: stmt::Value) -> crate::Result<()> {
<Self as Load>::reload(target, value)
}
fn make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_one(query)
}
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
has_one_relation_field_ty::<M>(pair, via)
}
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy {
belongs_to_relation_field_ty::<M>(foreign_key)
}
}
impl<M: Model> RelationOneField for Option<M> {
type Target = M;
type One = QueryOptionOne<M>;
type Expr = Option<M>;
const DEFERRED: bool = false;
const NULLABLE: bool = true;
fn reload(target: &mut Self, value: stmt::Value) -> crate::Result<()> {
<Self as Load>::reload(target, value)
}
fn make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_first(query)
}
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
has_one_relation_field_ty::<M>(pair, via)
}
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy {
belongs_to_relation_field_ty::<M>(foreign_key)
}
}
impl<M: Model> RelationOneField for Deferred<M> {
type Target = M;
type One = QueryOne<M>;
type Expr = M;
const DEFERRED: bool = true;
const NULLABLE: bool = false;
fn reload(target: &mut Self, _value: stmt::Value) -> crate::Result<()> {
target.unload();
Ok(())
}
fn make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_one(query)
}
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
has_one_relation_field_ty::<M>(pair, via)
}
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy {
belongs_to_relation_field_ty::<M>(foreign_key)
}
}
impl<M: Model> RelationOneField for Deferred<Option<M>> {
type Target = M;
type One = QueryOptionOne<M>;
type Expr = Option<M>;
const DEFERRED: bool = true;
const NULLABLE: bool = true;
fn reload(target: &mut Self, _value: stmt::Value) -> crate::Result<()> {
target.unload();
Ok(())
}
fn make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_first(query)
}
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
has_one_relation_field_ty::<M>(pair, via)
}
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy {
belongs_to_relation_field_ty::<M>(foreign_key)
}
}
fn has_one_relation_field_ty<M: Model>(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
let target = <M as Model>::id();
let expr_ty = stmt::Type::Model(target);
let cardinality = app::Cardinality::One;
match via {
Some(path) => FieldTy::Via(app::Via::new(target, expr_ty, cardinality, path, None)),
None => FieldTy::Has(app::Has {
target,
expr_ty,
cardinality,
pair_id: pair.unwrap_or(FieldId {
model: ModelId(usize::MAX),
index: usize::MAX,
}),
}),
}
}
fn belongs_to_relation_field_ty<M: Model>(foreign_key: ForeignKey) -> FieldTy {
let target = <M as Model>::id();
FieldTy::BelongsTo(app::BelongsTo {
target,
expr_ty: stmt::Type::Model(target),
pair: None,
foreign_key,
})
}