typed_sql/query/select/
join.rs

1use super::SelectStatement;
2use crate::query::select::WildCard;
3use crate::query::Predicate;
4use crate::Table;
5use std::marker::PhantomData;
6
7pub struct Inner;
8
9pub trait JoinKind {
10    const KIND: &'static str;
11}
12
13impl JoinKind for Inner {
14    const KIND: &'static str = "INNER";
15}
16
17/// ```
18/// use typed_sql::{Join, Query, Table, ToSql};
19/// use typed_sql::query::Joined;
20///
21/// #[derive(Table)]
22/// struct User {
23///     id: i64   
24/// }
25///
26/// #[derive(Table)]
27/// struct Post {
28///     id: i64,
29///     user_id: i64
30/// }
31///
32/// #[derive(Join)]
33/// struct UserPost {
34///    user: User,
35///    post: Post
36/// }
37///
38/// let join = UserPost::join(|join| UserPostJoin {
39///     post: Joined::new(join.user.id.eq(join.post.user_id)),
40/// });
41///
42/// assert_eq!(
43///     join.select().to_sql(),
44///     "SELECT * FROM users INNER JOIN posts ON users.id = posts.user_id;"
45/// );
46/// ```
47pub trait Join<P> {
48    type Table: Table;
49    type Fields: Default;
50    type Join: JoinSelect;
51
52    fn join<F>(f: F) -> Self::Join
53    where
54        F: FnOnce(Self::Fields) -> Self::Join,
55    {
56        f(Default::default())
57    }
58}
59
60pub trait JoinSelect {
61    type Table: Table;
62    type Fields: Default;
63
64    fn write_join_select(&self, sql: &mut String);
65
66    fn select(self) -> SelectStatement<Self, WildCard>
67    where
68        Self: Sized,
69    {
70        SelectStatement::new(self, WildCard)
71    }
72}
73
74pub struct Joined<P, K, T> {
75    predicate: P,
76    _kind: PhantomData<K>,
77    _table: PhantomData<T>,
78}
79
80impl<P, K, T> Joined<P, K, T>
81where
82    P: Predicate,
83    K: JoinKind,
84    T: Table,
85{
86    pub fn new(predicate: P) -> Self {
87        Self {
88            predicate,
89            _kind: PhantomData,
90            _table: PhantomData,
91        }
92    }
93
94    pub fn write_join(&self, sql: &mut String) {
95        sql.push(' ');
96        sql.push_str(K::KIND);
97        sql.push_str(" JOIN ");
98        sql.push_str(T::NAME);
99        sql.push_str(" ON ");
100        self.predicate.write_predicate(sql);
101    }
102}