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
//! Relation-key normalization for generated relationship loaders.
//!
//! A relation key may be a nullable foreign key (`Option<i32>`) on either side
//! of the relation. Generated loaders compare the inner value: a `None` key
//! matches no row, like SQL `NULL`. The field type is only known after macro
//! expansion, so the generated code selects the conversion by autoref
//! dispatch: `(&Key(&field)).__rullst_relation_key()` resolves to [`Nullable`]
//! for an `Option<T>` field and to [`Required`] for any other key type.
/// Borrows one relation key field for autoref dispatch.
pub struct Key<'a, T>(pub &'a T);
/// Unwraps a nullable key; `None` matches no row.
pub trait Nullable {
type Key;
fn __rullst_relation_key(&self) -> Option<Self::Key>;
}
impl<T: Clone> Nullable for Key<'_, Option<T>> {
type Key = T;
fn __rullst_relation_key(&self) -> Option<T> {
self.0.clone()
}
}
/// Keeps a non-nullable key as it is.
pub trait Required {
type Key;
fn __rullst_relation_key(&self) -> Option<Self::Key>;
}
impl<T: Clone> Required for &Key<'_, T> {
type Key = T;
fn __rullst_relation_key(&self) -> Option<T> {
Some(self.0.clone())
}
}
#[cfg(test)]
mod tests {
use super::{Key, Nullable as _, Required as _};
// Generated code borrows every key the same way, whatever its type.
#[allow(clippy::needless_borrow)]
#[test]
fn nullable_keys_unwrap_and_required_keys_pass_through() {
let present: Option<i32> = Some(7);
let missing: Option<i32> = None;
let required = 9_i32;
let text = String::from("slug");
assert_eq!((&Key(&present)).__rullst_relation_key(), Some(7));
assert_eq!((&Key(&missing)).__rullst_relation_key(), None);
assert_eq!((&Key(&required)).__rullst_relation_key(), Some(9));
assert_eq!(
(&Key(&text)).__rullst_relation_key(),
Some("slug".to_string())
);
}
}