1use super::HasTable;
2use crate::dsl::{Eq, EqAny, Filter, FindBy};
3use crate::expression::AsExpression;
4use crate::expression::array_comparison::AsInExpression;
5use crate::prelude::*;
6use crate::query_dsl::methods::FilterDsl;
7use crate::sql_types::SqlType;
8use alloc::vec::Vec;
910use core::borrow::Borrow;
11use core::hash::Hash;
1213/// Indicates that a type belongs to `Parent`
14///
15/// Specifically, this means that this struct has fields
16/// which correspond to the primary key of `Parent`.
17/// This implies that a foreign key relationship exists on the tables.
18///
19/// This trait is not capable of supporting composite foreign keys
20pub trait BelongsTo<Parent> {
21/// The foreign key of this struct
22type ForeignKey: Hash + ::core::cmp::Eq;
23/// The database column representing the foreign key
24 /// of the table this struct represents
25type ForeignKeyColumn: Column;
2627/// Returns the foreign key for `self`
28fn foreign_key(&self) -> Option<&Self::ForeignKey>;
29/// Returns the foreign key column of this struct's table
30fn foreign_key_column() -> Self::ForeignKeyColumn;
31}
3233/// The `grouped_by` function groups records by their parent.
34///
35/// `grouped_by` is called on a `Vec<Child>` with a `&[Parent]`.
36/// The return value will be `Vec<Vec<Child>>` indexed to match their parent.
37/// Or to put it another way, the returned data can be passed to `zip`,
38/// and it will be combined with its parent.
39/// This function does not generate a `GROUP BY` SQL statement,
40/// as it operates on data structures already loaded from the database
41///
42/// **Child** refers to the "many" part of a "one to many" relationship. It "belongs to" its parent
43/// **Parent** refers to the "one" part of a "one to many" relationship and can "have many" children.
44/// The child always has a foreign key, which refers to its parent's primary key.
45/// In the following relationship, User has many Posts,
46/// so User is the parent and Posts are children.
47///
48/// # Unrelated Rows
49///
50/// When using [`GroupedBy::grouped_by`], if the child rows were not queried
51/// using the provided parent rows, it is not guaranteed a parent row
52/// will be found for a given child row.
53/// This is possible, if the foreign key in the relationship is nullable,
54/// or if a child row's parent was not present in the provided slice,
55/// in which case, unrelated child rows will be discarded.
56///
57/// If discarding these rows is undesirable, it may be preferable to use
58/// [`GroupedBy::try_grouped_by`].
59///
60/// # Handling Duplicate Parent Rows
61///
62/// Both [`GroupedBy::grouped_by`] and [`GroupedBy::try_grouped_by`]
63/// expect all of the elements of `parents` to produce a unique value
64/// when calling [`Identifiable::id`].
65/// If this is not true, child rows may be added to an unexpected index.
66///
67/// As a result, it is recommended to use [`QueryDsl::distinct`]
68/// or [`slice::sort`] and [`Vec::dedup`],
69/// to ensure the elements of `parents` are unique.
70///
71/// # Example
72///
73/// ```rust
74/// # include!("../doctest_setup.rs");
75/// # use schema::{posts, users};
76/// #
77/// # #[derive(Identifiable, Queryable, PartialEq, Debug)]
78/// # pub struct User {
79/// # id: i32,
80/// # name: String,
81/// # }
82/// #
83/// # #[derive(Debug, PartialEq)]
84/// # #[derive(Identifiable, Queryable, Associations)]
85/// # #[diesel(belongs_to(User))]
86/// # pub struct Post {
87/// # id: i32,
88/// # user_id: i32,
89/// # title: String,
90/// # }
91/// #
92/// # fn main() {
93/// # run_test();
94/// # }
95/// #
96/// # fn run_test() -> QueryResult<()> {
97/// # let connection = &mut establish_connection();
98/// let users = users::table.load::<User>(connection)?;
99/// let posts = Post::belonging_to(&users)
100/// .load::<Post>(connection)?
101/// .grouped_by(&users);
102/// let data = users.into_iter().zip(posts).collect::<Vec<_>>();
103///
104/// let expected_data = vec![
105/// (
106/// User {
107/// id: 1,
108/// name: "Sean".into(),
109/// },
110/// vec![
111/// Post {
112/// id: 1,
113/// user_id: 1,
114/// title: "My first post".into(),
115/// },
116/// Post {
117/// id: 2,
118/// user_id: 1,
119/// title: "About Rust".into(),
120/// },
121/// ],
122/// ),
123/// (
124/// User {
125/// id: 2,
126/// name: "Tess".into(),
127/// },
128/// vec![Post {
129/// id: 3,
130/// user_id: 2,
131/// title: "My first post too".into(),
132/// }],
133/// ),
134/// ];
135///
136/// assert_eq!(expected_data, data);
137/// # Ok(())
138/// # }
139/// ```
140///
141/// See [the module documentation] for more examples
142///
143/// [the module documentation]: super
144pub trait GroupedBy<'a, Parent>: IntoIterator + Sized {
145/// See the trait documentation.
146fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Self::Item>>;
147148/// A fallible alternative to [`GroupedBy::grouped_by`].
149 ///
150 /// If any child record could not be grouped,
151 /// either because of a `NULL` foreign key,
152 /// or a parent record with a matching key could not be found,
153 /// this function should return `Err`,
154 /// with all successfully grouped records, as well as any ungrouped records.
155 ///
156 /// # Errors
157 ///
158 /// If a parent record could not be found for any of the child records,
159 /// this function should return the `TryGroupedByError`.
160 /// Every supplied record should be contained in the returned error,
161 /// either in the `grouped` field, if it was successfully grouped,
162 /// or the `ungrouped` field, if it was not possible to associate
163 /// with a parent record.
164 ///
165 /// # Examples
166 ///
167 /// ```rust
168 /// # include!("../doctest_setup.rs");
169 /// # use diesel::associations::TryGroupedByError;
170 /// # use schema::{posts, users};
171 /// #
172 /// # #[derive(Identifiable, Queryable, PartialEq, Debug)]
173 /// # pub struct User {
174 /// # id: i32,
175 /// # name: String,
176 /// # }
177 /// #
178 /// # #[derive(Debug, PartialEq)]
179 /// # #[derive(Identifiable, Queryable, Associations)]
180 /// # #[diesel(belongs_to(User))]
181 /// # pub struct Post {
182 /// # id: i32,
183 /// # user_id: i32,
184 /// # title: String,
185 /// # }
186 /// #
187 /// # fn main() {
188 /// # run_test();
189 /// # }
190 /// #
191 /// # fn run_test() -> QueryResult<()> {
192 /// # let connection = &mut establish_connection();
193 /// let users = users::table.load::<User>(connection)?;
194 /// let mut posts = Post::belonging_to(&users).load::<Post>(connection)?;
195 /// posts.push(Post {
196 /// id: 9,
197 /// user_id: 42,
198 /// title: "A post returned from another query".into(),
199 /// });
200 /// let TryGroupedByError {
201 /// grouped, ungrouped, ..
202 /// } = posts.try_grouped_by(&users).unwrap_err();
203 ///
204 /// let grouped_data = users.into_iter().zip(grouped).collect::<Vec<_>>();
205 ///
206 /// let expected_grouped_data = vec![
207 /// (
208 /// User {
209 /// id: 1,
210 /// name: "Sean".into(),
211 /// },
212 /// vec![
213 /// Post {
214 /// id: 1,
215 /// user_id: 1,
216 /// title: "My first post".into(),
217 /// },
218 /// Post {
219 /// id: 2,
220 /// user_id: 1,
221 /// title: "About Rust".into(),
222 /// },
223 /// ],
224 /// ),
225 /// (
226 /// User {
227 /// id: 2,
228 /// name: "Tess".into(),
229 /// },
230 /// vec![Post {
231 /// id: 3,
232 /// user_id: 2,
233 /// title: "My first post too".into(),
234 /// }],
235 /// ),
236 /// ];
237 ///
238 /// let expected_ungrouped_data = vec![Post {
239 /// id: 9,
240 /// user_id: 42,
241 /// title: "A post returned from another query".into(),
242 /// }];
243 ///
244 /// assert_eq!(expected_grouped_data, grouped_data);
245 /// assert_eq!(expected_ungrouped_data, ungrouped);
246 /// # Ok(())
247 /// # }
248 /// ```
249fn try_grouped_by(
250self,
251 parents: &'a [Parent],
252 ) -> Result<Vec<Vec<Self::Item>>, TryGroupedByError<Self::Item>> {
253Ok(self.grouped_by(parents))
254 }
255}
256257/// A type of error which can be returned when attempting to group
258/// a list of records.
259///
260/// If a child record has a nullable foreign key, or is being grouped
261/// using a different relationship to the one that was used to query it,
262/// it may not be possible to find a parent record it should be grouped by.
263///
264/// When encountering these missing relationships,
265/// it may still be possible to group remaining records,
266/// but would affect the contents of the returned values.
267/// By extracting the contents of this struct, it is still possible
268/// to use these resulting groups, as well as any records
269/// that could not be grouped.
270#[derive(#[automatically_derived]
impl<Child: ::core::fmt::Debug> ::core::fmt::Debug for
TryGroupedByError<Child> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"TryGroupedByError", "grouped", &self.grouped, "ungrouped",
&&self.ungrouped)
}
}Debug, #[automatically_derived]
impl<Child: ::core::clone::Clone> ::core::clone::Clone for
TryGroupedByError<Child> {
#[inline]
fn clone(&self) -> TryGroupedByError<Child> {
TryGroupedByError {
grouped: ::core::clone::Clone::clone(&self.grouped),
ungrouped: ::core::clone::Clone::clone(&self.ungrouped),
}
}
}Clone, #[automatically_derived]
impl<Child: ::core::cmp::PartialEq> ::core::cmp::PartialEq for
TryGroupedByError<Child> {
#[inline]
fn eq(&self, other: &TryGroupedByError<Child>) -> bool {
self.grouped == other.grouped && self.ungrouped == other.ungrouped
}
}PartialEq, #[automatically_derived]
impl<Child: ::core::cmp::PartialOrd> ::core::cmp::PartialOrd for
TryGroupedByError<Child> {
#[inline]
fn partial_cmp(&self, other: &TryGroupedByError<Child>)
-> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.grouped,
&other.grouped) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
::core::cmp::PartialOrd::partial_cmp(&self.ungrouped,
&other.ungrouped),
cmp => cmp,
}
}
}PartialOrd, #[automatically_derived]
impl<Child: ::core::cmp::Eq> ::core::cmp::Eq for TryGroupedByError<Child> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Vec<Vec<Child>>>;
let _: ::core::cmp::AssertParamIsEq<Vec<Child>>;
}
}Eq, #[automatically_derived]
impl<Child: ::core::cmp::Ord> ::core::cmp::Ord for TryGroupedByError<Child> {
#[inline]
fn cmp(&self, other: &TryGroupedByError<Child>) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.grouped, &other.grouped) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.ungrouped, &other.ungrouped),
cmp => cmp,
}
}
}Ord, #[automatically_derived]
impl<Child: ::core::hash::Hash> ::core::hash::Hash for
TryGroupedByError<Child> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.grouped, state);
::core::hash::Hash::hash(&self.ungrouped, state)
}
}Hash)]
271#[non_exhaustive]
272pub struct TryGroupedByError<Child> {
273/// The collection of records which were successfully indexed
274 /// against a parent record.
275pub grouped: Vec<Vec<Child>>,
276/// The collection of records that could not be indexed
277 /// against a parent record.
278pub ungrouped: Vec<Child>,
279}
280281type Id<T> = <T as Identifiable>::Id;
282283impl<Child> TryGroupedByError<Child> {
284/// Creates a `TryGroupedByError`.
285 ///
286 /// This is generally used by methods like [`GroupedBy::try_grouped_by`].
287pub fn new(grouped: Vec<Vec<Child>>, ungrouped: Vec<Child>) -> Self {
288Self { grouped, ungrouped }
289 }
290}
291292impl<'a, Parent: 'a, Child, Iter> GroupedBy<'a, Parent> for Iter
293where
294Iter: IntoIterator<Item = Child>,
295 Child: BelongsTo<Parent>,
296&'a Parent: Identifiable,
297Id<&'a Parent>: Borrow<Child::ForeignKey>,
298{
299fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Child>> {
300use crate::util::std_compat::HashMap;
301use core::iter;
302303let mut grouped: Vec<_> = iter::repeat_with(Vec::new).take(parents.len()).collect();
304305let id_indices: HashMap<_, _> = parents306 .iter()
307 .enumerate()
308 .map(|(i, u)| (u.id(), i))
309 .collect();
310311self.into_iter()
312 .filter_map(|child| {
313let fk = child.foreign_key()?;
314let i = id_indices.get(fk)?;
315316Some((i, child))
317 })
318 .for_each(|(i, child)| grouped[*i].push(child));
319320grouped321 }
322323fn try_grouped_by(
324self,
325 parents: &'a [Parent],
326 ) -> Result<Vec<Vec<Child>>, TryGroupedByError<Child>> {
327use crate::util::std_compat::HashMap;
328use core::iter;
329330let mut grouped: Vec<_> = iter::repeat_with(Vec::new).take(parents.len()).collect();
331let mut ungrouped: Vec<_> = Vec::new();
332333let id_indices: HashMap<_, _> = parents334 .iter()
335 .enumerate()
336 .map(|(i, u)| (u.id(), i))
337 .collect();
338339for child in self {
340 child
341 .foreign_key()
342 .and_then(|i| id_indices.get(i))
343 .map_or(&mut ungrouped, |i| &mut grouped[*i])
344 .push(child);
345 }
346347if ungrouped.is_empty() {
348Ok(grouped)
349 } else {
350Err(TryGroupedByError::new(grouped, ungrouped))
351 }
352 }
353}
354355impl<'a, Parent, Child> BelongingToDsl<&'a Parent> for Child
356where
357&'a Parent: Identifiable,
358 Child: HasTable + BelongsTo<Parent>,
359Id<&'a Parent>: AsExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
360 Child::Table: FilterDsl<Eq<Child::ForeignKeyColumn, Id<&'a Parent>>>,
361 Child::ForeignKeyColumn: ExpressionMethods,
362 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
363{
364type Output = FindBy<Child::Table, Child::ForeignKeyColumn, Id<&'a Parent>>;
365366fn belonging_to(parent: &'a Parent) -> Self::Output {
367 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq(parent.id()))
368 }
369}
370371impl<'a, Parent, Child> BelongingToDsl<&'a [Parent]> for Child
372where
373&'a Parent: Identifiable,
374 Child: HasTable + BelongsTo<Parent>,
375Vec<Id<&'a Parent>>: AsInExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
376 <Child as HasTable>::Table: FilterDsl<EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>,
377 Child::ForeignKeyColumn: ExpressionMethods,
378 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
379{
380type Output = Filter<Child::Table, EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>;
381382fn belonging_to(parents: &'a [Parent]) -> Self::Output {
383let ids = parents.iter().map(Identifiable::id).collect::<Vec<_>>();
384 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq_any(ids))
385 }
386}
387388impl<'a, Parent, Child> BelongingToDsl<(&'a [Parent], &'a [Parent])> for Child
389where
390&'a Parent: Identifiable,
391 Child: HasTable + BelongsTo<Parent>,
392Vec<Id<&'a Parent>>: AsInExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
393 <Child as HasTable>::Table: FilterDsl<EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>,
394 Child::ForeignKeyColumn: ExpressionMethods,
395 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
396{
397type Output = Filter<Child::Table, EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>;
398399fn belonging_to(parents: (&'a [Parent], &'a [Parent])) -> Self::Output {
400let ids = parents401 .0
402.iter()
403 .chain(parents.1.iter())
404 .map(Identifiable::id)
405 .collect::<Vec<_>>();
406 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq_any(ids))
407 }
408}
409410impl<'a, Parent, Child> BelongingToDsl<&'a Vec<Parent>> for Child
411where
412Child: BelongingToDsl<&'a [Parent]>,
413{
414type Output = Child::Output;
415416fn belonging_to(parents: &'a Vec<Parent>) -> Self::Output {
417Self::belonging_to(&**parents)
418 }
419}