1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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;
/// A Rust field type that represents a `#[has_one]` or `#[belongs_to]`
/// relation.
///
/// Implemented by `M`, `Option<M>`, `Deferred<M>`, and `Deferred<Option<M>>`
/// where `M: Model`. The `Option<...>` wrappers carry nullability; the
/// `Deferred<...>` wrappers carry deferred loading. Anything outside this
/// shape does not satisfy the trait.
pub trait RelationOneField: Load<Output = Self> {
/// The target model that this field references.
type Target: Model;
/// The query type produced by the relation accessor. For non-nullable
/// impls this is `<Target as Model>::Query<Target>`; for nullable impls it is
/// `<Target as Model>::Query<Option<Target>>`.
type One;
/// The path target and expression type used in create/update setters.
/// Resolves to `Self::Target` for non-nullable impls and
/// `Option<Self::Target>` for nullable impls.
type Expr;
/// Whether the field stores its value in a deferred load slot.
const DEFERRED: bool;
/// Whether the field is nullable (i.e. wrapped in `Option`).
const NULLABLE: bool;
/// Reloads this relation field from a returned value.
fn reload(target: &mut Self, value: stmt::Value) -> crate::Result<()> {
<Self as Load>::reload(target, value)
}
/// Narrow a list query targeting the related model into the appropriate
/// "one" query — `Query<Model>` for non-nullable impls and
/// `Query<Option<Model>>` for nullable impls.
///
/// Relation accessors build the list query (from a filter or by wrapping a
/// singular association via [`Model::wrap_query`]) and pass it here; the
/// association's path is preserved through the wrap so generated mutators
/// (insert, remove, create) can read it.
fn make_one(query: QueryMany<Self::Target>) -> Self::One;
/// Build the [`FieldTy`] for a `HasOne` relation field, given an
/// optional paired `BelongsTo` field on the target model resolved
/// from `#[has_one(pair = <field>)]`. When `None`, the linker selects
/// the pair by searching the target for a unique `BelongsTo` back to
/// the source.
///
/// `via` carries the fully resolved [`stmt::Path`] of a
/// `#[has_one(via = a.b)]` multi-step relation, rooted at the declaring
/// model. A `via` relation has no pair.
fn has_one_relation_field_ty(pair: Option<FieldId>, via: Option<stmt::Path>) -> FieldTy {
let target = <Self::Target 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,
}),
}),
}
}
/// Build the [`FieldTy`] for a `BelongsTo` relation field, given the
/// foreign key resolved from the field's `#[belongs_to(...)]` attribute.
fn belongs_to_relation_field_ty(foreign_key: ForeignKey) -> FieldTy {
let target = <Self::Target as Model>::id();
FieldTy::BelongsTo(app::BelongsTo {
target,
expr_ty: stmt::Type::Model(target),
// The pair is populated at runtime.
pair: None,
foreign_key,
})
}
}
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 make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_one(query)
}
}
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 make_one(query: QueryMany<Self::Target>) -> Self::One {
<M as Model>::query_first(query)
}
}
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)
}
}
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)
}
}