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
use expression::AsExpression;
use expression::helper_types::{Eq, EqAny};
use expression::array_comparison::AsInExpression;
use helper_types::{FindBy, Filter};
use prelude::*;
use super::{Identifiable, HasTable};

use std::borrow::Borrow;
use std::hash::Hash;

pub trait BelongsTo<Parent> {
    type ForeignKey: Hash + ::std::cmp::Eq;
    type ForeignKeyColumn: Column;

    fn foreign_key(&self) -> Option<&Self::ForeignKey>;
    fn foreign_key_column() -> Self::ForeignKeyColumn;
}

pub trait GroupedBy<'a, Parent>: IntoIterator + Sized {
    fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Self::Item>>;
}

type Id<T> = <T as Identifiable>::Id;

impl<'a, Parent: 'a, Child, Iter> GroupedBy<'a, Parent> for Iter where
    Iter: IntoIterator<Item=Child>,
    Child: BelongsTo<Parent>,
    &'a Parent: Identifiable,
    Id<&'a Parent>: Borrow<Child::ForeignKey>,
{
    fn grouped_by(self, parents: &'a [Parent]) -> Vec<Vec<Child>> {
        use std::collections::HashMap;

        let id_indices: HashMap<_, _> = parents.iter().enumerate().map(|(i, u)| (u.id(), i)).collect();
        let mut result = parents.iter().map(|_| Vec::new()).collect::<Vec<_>>();
        for child in self {
            if let Some(index) = child.foreign_key().map(|i| id_indices[i]) {
                result[index].push(child);
            }
        }
        result
    }
}

impl<'a, Parent, Child> BelongingToDsl<&'a Parent> for Child where
    &'a Parent: Identifiable,
    Child: HasTable + BelongsTo<Parent>,
    Id<&'a Parent>: AsExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
    <Child as HasTable>::Table: FilterDsl<Eq<Child::ForeignKeyColumn, Id<&'a Parent>>>,
{
    type Output = FindBy<
        Child::Table,
        Child::ForeignKeyColumn,
        Id<&'a Parent>,
    >;

    fn belonging_to(parent: &'a Parent) -> Self::Output {
        Child::table().filter(Child::foreign_key_column().eq(parent.id()))
    }
}

impl<'a, Parent, Child> BelongingToDsl<&'a [Parent]> for Child where
    &'a Parent: Identifiable,
    Child: HasTable + BelongsTo<Parent>,
    Vec<Id<&'a Parent>>: AsInExpression<<Child::ForeignKeyColumn as Expression>::SqlType>,
    <Child as HasTable>::Table: FilterDsl<EqAny<Child::ForeignKeyColumn, Vec<Id<&'a Parent>>>>,
{
    type Output = Filter<
        Child::Table,
        EqAny<
            Child::ForeignKeyColumn,
            Vec<Id<&'a Parent>>,
        >,
    >;

    fn belonging_to(parents: &'a [Parent]) -> Self::Output {
        let ids = parents.iter().map(Identifiable::id).collect::<Vec<_>>();
        Child::table().filter(Child::foreign_key_column().eq_any(ids))
    }
}

impl<'a, Parent, Child> BelongingToDsl<&'a Vec<Parent>> for Child where
    Child: BelongingToDsl<&'a [Parent]>,
{
    type Output = Child::Output;

    fn belonging_to(parents: &'a Vec<Parent>) -> Self::Output {
        Self::belonging_to(&**parents)
    }
}