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 91 92 93 94 95 96 97 98 99 100 101 102
use super::SelectStatement;
use crate::query::select::WildCard;
use crate::query::Predicate;
use crate::Table;
use std::marker::PhantomData;
pub struct Inner;
pub trait JoinKind {
const KIND: &'static str;
}
impl JoinKind for Inner {
const KIND: &'static str = "INNER";
}
/// ```
/// use typed_sql::{Join, Query, Table, ToSql};
/// use typed_sql::query::Joined;
///
/// #[derive(Table)]
/// struct User {
/// id: i64
/// }
///
/// #[derive(Table)]
/// struct Post {
/// id: i64,
/// user_id: i64
/// }
///
/// #[derive(Join)]
/// struct UserPost {
/// user: User,
/// post: Post
/// }
///
/// let join = UserPost::join(|join| UserPostJoin {
/// post: Joined::new(join.user.id.eq(join.post.user_id)),
/// });
///
/// assert_eq!(
/// join.select().to_sql(),
/// "SELECT * FROM users INNER JOIN posts ON users.id = posts.user_id;"
/// );
/// ```
pub trait Join<P> {
type Table: Table;
type Fields: Default;
type Join: JoinSelect;
fn join<F>(f: F) -> Self::Join
where
F: FnOnce(Self::Fields) -> Self::Join,
{
f(Default::default())
}
}
pub trait JoinSelect {
type Table: Table;
type Fields: Default;
fn write_join_select(&self, sql: &mut String);
fn select(self) -> SelectStatement<Self, WildCard>
where
Self: Sized,
{
SelectStatement::new(self, WildCard)
}
}
pub struct Joined<P, K, T> {
predicate: P,
_kind: PhantomData<K>,
_table: PhantomData<T>,
}
impl<P, K, T> Joined<P, K, T>
where
P: Predicate,
K: JoinKind,
T: Table,
{
pub fn new(predicate: P) -> Self {
Self {
predicate,
_kind: PhantomData,
_table: PhantomData,
}
}
pub fn write_join(&self, sql: &mut String) {
sql.push(' ');
sql.push_str(K::KIND);
sql.push_str(" JOIN ");
sql.push_str(T::NAME);
sql.push_str(" ON ");
self.predicate.write_predicate(sql);
}
}