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
use associations::{HasTable, Identifiable};
use dsl::Find;
use query_dsl::methods::FindDsl;
use query_source::Table;

#[doc(hidden)]
#[derive(Debug)]
pub struct UpdateTarget<Table, WhereClause> {
    pub table: Table,
    pub where_clause: WhereClause,
}

/// A type which can be passed to [`update`] or [`delete`].
///
/// Apps will never need to implement this type directly. There are three kinds
/// which implement this trait. Tables, queries which have only had `filter`
/// called on them, and types which implement `Identifiable`.
///
/// When a table is passed to `update`, every row in the table will be updated.
/// You can scope this down by calling [`filter`] which will
/// result in `UPDATE your_table SET ... WHERE args_to_filter`. Passing a type
/// which implements `Identifiable` is the same as passing
/// `SomeStruct::table().find(some_struct)`.
///
/// [`update`]: ../fn.update.html
/// [`delete`]: ../fn.delete.html
/// [`filter`]: struct.UpdateStatement.html#method.filter
pub trait IntoUpdateTarget: HasTable {
    /// What is the `WHERE` clause of this target?
    type WhereClause;

    /// Decomposes `self` into the table and where clause.
    fn into_update_target(self) -> UpdateTarget<Self::Table, Self::WhereClause>;
}

impl<T, Tab, V> IntoUpdateTarget for T
where
    T: Identifiable<Table = Tab>,
    Tab: Table + FindDsl<T::Id>,
    Find<Tab, T::Id>: IntoUpdateTarget<Table = Tab, WhereClause = V>,
{
    type WhereClause = V;

    fn into_update_target(self) -> UpdateTarget<Self::Table, Self::WhereClause> {
        T::table().find(self.id()).into_update_target()
    }
}