toql_core/
join.rs

1//! [Join] enum to simplify update handling of joins.
2/// A join struct can contain either the full entity or just its key.
3/// This allows to load the full entity.
4/// For updates however you are not forced to set a full entity,
5/// if you only want to  updating a foreign key.
6///
7/// ### Compare both
8///
9/// ```ignore
10/// use toql::prelude::Join;
11///
12/// #[derive(Toql)]
13/// struct User {
14///    #[toql(key)]
15///     id: u64,
16
17///     #[toql(join())]
18///     language: Join<Language>,
19
20///     #[toql(join())]
21///     country: Country
22///  }
23/// ```
24/// For loading both `language` and `country` behave the same.
25/// The difference comes on updating: Let's assume a web interface
26/// that can change both `language` and `country`.
27/// For `language`, the web client can only send back the key. It will deserialize into Join::Key.
28/// To change `country` however the client needs to send back a full valid country,
29/// otherwise the deserializer (serde) will fail.
30/// Likewise when programming `Join` is more ergonomic in update situations.
31///
32pub mod from_row;
33pub mod keyed;
34
35pub mod tree_identity;
36pub mod tree_index;
37pub mod tree_insert;
38pub mod tree_merge;
39pub mod tree_predicate;
40pub mod tree_update;
41
42use crate::error::ToqlError;
43use crate::keyed::Keyed;
44
45use std::boxed::Box;
46
47/// The Join struct that hold either an entity or its key.
48#[derive(Debug, PartialEq, Eq)]
49#[cfg_attr(
50    feature = "serde_feature",
51    derive(serde::Serialize, serde::Deserialize)
52)]
53#[cfg_attr(feature = "serde_feature", serde(untagged))]
54pub enum Join<E: Keyed> {
55    /// Full entity is held. The entity is wrapped inside a `Box`. That does allow
56    /// circular dependencies, in theory. In practice the compiler goes wild :(
57    Entity(Box<E>),
58    /// The entities key
59    Key(E::Key),
60}
61
62impl<E> Default for Join<E>
63where
64    E: Default + Keyed,
65{
66    fn default() -> Self {
67        Join::Entity(Box::new(E::default()))
68    }
69}
70
71// TODO decide on how to display keys to user
72/* impl<E> std::fmt::Display for Join<E>
73where
74    E:  std::fmt::Display + Keyed,
75    <E as Keyed>::Key:  std::fmt::Display,
76{
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78       match self {
79            Join::Key(k) => k.fmt(f),
80            Join::Entity(e) => e.fmt(f),
81        }
82    }
83} */
84
85impl<E> Clone for Join<E>
86where
87    E: Clone + Keyed,
88    <E as Keyed>::Key: Clone,
89{
90    fn clone(&self) -> Self {
91        match self {
92            Join::Key(k) => Join::Key(k.clone()),
93            Join::Entity(e) => Join::Entity(e.clone()),
94        }
95    }
96}
97
98impl<T> Join<T>
99where
100    T: Keyed,
101{
102    /// Constructs join for entity
103    pub fn with_entity(entity: T) -> Self {
104        Join::Entity(Box::new(entity))
105    }
106
107    /// Constructs join for key
108    pub fn with_key(key: impl Into<<T as Keyed>::Key>) -> Self {
109        Join::Key(key.into())
110    }
111
112    /// Returns entity or `None`, if key is held.
113    pub fn entity(&self) -> Option<&T> {
114        match self {
115            Join::Key(_) => None,
116            Join::Entity(e) => Some(&e),
117        }
118    }
119
120    /// Returns mutable entity or `None`, if key is held.
121    pub fn entity_mut(&mut self) -> Option<&mut T> {
122        match self {
123            Join::Key(_) => None,
124            Join::Entity(e) => Some(e.as_mut()),
125        }
126    }
127
128    /// Returns entity or error `E`, if key is held.
129    pub fn entity_or_err<E>(&self, err: E) -> std::result::Result<&T, E> {
130        match self {
131            Join::Key(_) => Err(err),
132            Join::Entity(e) => Ok(&e),
133        }
134    }
135    /// Returns mut entity or error `E`, if key is held.
136    pub fn entity_mut_or_err<E>(&mut self, err: E) -> std::result::Result<&mut T, E> {
137        match self {
138            Join::Key(_) => Err(err),
139            Join::Entity(e) => Ok(e.as_mut()),
140        }
141    }
142
143    /// Returns a key. If entity is held, key is taken from that entity
144    pub fn key(&self) -> <T as Keyed>::Key
145    where
146        <T as Keyed>::Key: std::clone::Clone,
147    {
148        match self {
149            Join::Entity(e) => e.key(),
150            Join::Key(k) => k.to_owned(),
151        }
152    }
153
154    /// Unwraps join into its entity. Can fail
155    pub fn into_entity(self) -> std::result::Result<T, ToqlError> {
156        match self {
157            Join::Key(_) => Err(ToqlError::NotFound),
158            Join::Entity(e) => Ok(*e),
159        }
160    }
161}
162
163#[cfg(test)]
164mod test {
165    use super::Join;
166    use crate::error::ToqlError;
167    use crate::key::Key;
168    use crate::keyed::Keyed;
169    use crate::sql_arg::SqlArg;
170
171    #[test]
172    fn build() {
173        #[derive(Debug, Clone, PartialEq)]
174        struct User {
175            id: u64,
176            name: String,
177        }
178        #[derive(Debug, Clone, Hash, PartialEq, Eq)]
179        struct UserKey {
180            id: u64,
181        }
182
183        impl Keyed for User {
184            type Key = UserKey;
185
186            fn key(&self) -> Self::Key {
187                UserKey { id: self.id }
188            }
189        }
190        impl Key for UserKey {
191            type Entity = User;
192            fn columns() -> Vec<String> {
193                vec!["id".to_string()]
194            }
195            fn default_inverse_columns() -> Vec<String> {
196                vec!["user_id".to_string()]
197            }
198            fn params(&self) -> Vec<SqlArg> {
199                vec![SqlArg::U64(self.id)]
200            }
201        }
202
203        impl Default for User {
204            fn default() -> Self {
205                User {
206                    id: 0,
207                    name: "new_user".to_string(),
208                }
209            }
210        }
211
212        let mut u = User {
213            id: 1,
214            name: "user1".to_string(),
215        };
216
217        let mut j = Join::with_entity(u.clone());
218        assert_eq!(j.entity(), Some(&u));
219        assert_eq!(j.entity_mut(), Some(&mut u));
220        assert!(j
221            .entity_or_err(ToqlError::NoneError("expected entity".to_string()))
222            .is_ok());
223        assert!(j
224            .entity_mut_or_err(ToqlError::NoneError("expected entity".to_string()))
225            .is_ok());
226        assert_eq!(j.key(), u.key());
227        assert!(j.into_entity().is_ok());
228
229        let j: Join<User> = Join::with_key(u.key());
230        let mut j = j.clone();
231        assert_eq!(j.entity(), None);
232        assert_eq!(j.entity_mut(), None);
233        assert!(j
234            .entity_or_err(ToqlError::NoneError("expected entity".to_string()))
235            .is_err());
236        assert!(j
237            .entity_mut_or_err(ToqlError::NoneError("expected entity".to_string()))
238            .is_err());
239        assert_eq!(j.key(), u.key());
240        assert!(j.into_entity().is_err());
241
242        let j = Join::default();
243        let u = User::default();
244        assert_eq!(j.entity(), Some(&u));
245
246        // satisfy line coverage
247        let j = User::default().key();
248        assert_eq!(UserKey::columns(), vec!["id".to_string()]);
249        assert_eq!(
250            UserKey::default_inverse_columns(),
251            vec!["user_id".to_string()]
252        );
253        assert_eq!(j.params(), vec![SqlArg::U64(0)]);
254    }
255}