diesel/associations/
belongs_to.rs1use super::HasTable;
2use crate::dsl::{Eq, EqAny, Filter, FindBy};
3use crate::expression::array_comparison::AsInExpression;
4use crate::expression::AsExpression;
5use crate::prelude::*;
6use crate::query_dsl::methods::FilterDsl;
7use crate::sql_types::SqlType;
8
9use std::borrow::Borrow;
10use std::hash::Hash;
11
12pub trait BelongsTo<Parent> {
20 type ForeignKey: Hash + ::std::cmp::Eq;
22 type ForeignKeyColumn: Column;
25
26 fn foreign_key(&self) -> Option<&Self::ForeignKey>;
28 fn foreign_key_column() -> Self::ForeignKeyColumn;
30}
31
32pub trait GroupedBy<'a, Parent>: IntoIterator + Sized {
105 fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Self::Item>>;
107}
108
109type Id<T> = <T as Identifiable>::Id;
110
111impl<'a, Parent: 'a, Child, Iter> GroupedBy<'a, Parent> for Iter
112where
113 Iter: IntoIterator<Item = Child>,
114 Child: BelongsTo<Parent>,
115 &'a Parent: Identifiable,
116 Id<&'a Parent>: Borrow<Child::ForeignKey>,
117{
118 fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Child>> {
119 use std::collections::HashMap;
120
121 let id_indices: HashMap<_, _> = parents
122 .iter()
123 .enumerate()
124 .map(|(i, u)| (u.id(), i))
125 .collect();
126 let mut result = parents.iter().map(|_| Vec::new()).collect::<Vec<_>>();
127 for child in self {
128 if let Some(index) = child.foreign_key().map(|i| id_indices[i]) {
129 result[index].push(child);
130 }
131 }
132 result
133 }
134}
135
136impl<'a, Parent, Child> BelongingToDsl<&'a Parent> for Child
137where
138 &'a Parent: Identifiable,
139 Child: HasTable + BelongsTo<Parent>,
140 Id<&'a Parent>: AsExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
141 Child::Table: FilterDsl<Eq<Child::ForeignKeyColumn, Id<&'a Parent>>>,
142 Child::ForeignKeyColumn: ExpressionMethods,
143 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
144{
145 type Output = FindBy<Child::Table, Child::ForeignKeyColumn, Id<&'a Parent>>;
146
147 fn belonging_to(parent: &'a Parent) -> Self::Output {
148 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq(parent.id()))
149 }
150}
151
152impl<'a, Parent, Child> BelongingToDsl<&'a [Parent]> for Child
153where
154 &'a Parent: Identifiable,
155 Child: HasTable + BelongsTo<Parent>,
156 Vec<Id<&'a Parent>>: AsInExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
157 <Child as HasTable>::Table: FilterDsl<EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>,
158 Child::ForeignKeyColumn: ExpressionMethods,
159 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
160{
161 type Output = Filter<Child::Table, EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>;
162
163 fn belonging_to(parents: &'a [Parent]) -> Self::Output {
164 let ids = parents.iter().map(Identifiable::id).collect::<Vec<_>>();
165 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq_any(ids))
166 }
167}
168
169impl<'a, Parent, Child> BelongingToDsl<(&'a [Parent], &'a [Parent])> for Child
170where
171 &'a Parent: Identifiable,
172 Child: HasTable + BelongsTo<Parent>,
173 Vec<Id<&'a Parent>>: AsInExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
174 <Child as HasTable>::Table: FilterDsl<EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>,
175 Child::ForeignKeyColumn: ExpressionMethods,
176 <Child::ForeignKeyColumn as Expression>::SqlType: SqlType,
177{
178 type Output = Filter<Child::Table, EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>;
179
180 fn belonging_to(parents: (&'a [Parent], &'a [Parent])) -> Self::Output {
181 let ids = parents
182 .0
183 .iter()
184 .chain(parents.1.iter())
185 .map(Identifiable::id)
186 .collect::<Vec<_>>();
187 FilterDsl::filter(Child::table(), Child::foreign_key_column().eq_any(ids))
188 }
189}
190
191impl<'a, Parent, Child> BelongingToDsl<&'a Vec<Parent>> for Child
192where
193 Child: BelongingToDsl<&'a [Parent]>,
194{
195 type Output = Child::Output;
196
197 fn belonging_to(parents: &'a Vec<Parent>) -> Self::Output {
198 Self::belonging_to(&**parents)
199 }
200}