use crate::{traits::PostgresTable, values::PostgresValue};
use drizzle_core::{
Join, SQL, ToSQL, Token, helpers,
traits::{SQLColumnInfo, SQLModel},
};
pub(crate) use helpers::{
delete, except, except_all, from, group_by, having, intersect, intersect_all, limit, offset,
order_by, select, select_distinct, set, union, union_all, update, r#where,
};
fn columns_info_to_sql<'a>(columns: &[&'static dyn SQLColumnInfo]) -> SQL<'a, PostgresValue<'a>> {
SQL::join(
columns.iter().map(|col| SQL::ident(col.name())),
Token::COMMA,
)
}
drizzle_core::impl_join_helpers!(
table_trait: PostgresTable<'a>,
condition_trait: ToSQL<'a, PostgresValue<'a>>,
sql_type: SQL<'a, PostgresValue<'a>>,
);
pub(crate) fn select_distinct_on<'a, On, Columns>(
on: On,
columns: Columns,
) -> SQL<'a, PostgresValue<'a>>
where
On: ToSQL<'a, PostgresValue<'a>>,
Columns: ToSQL<'a, PostgresValue<'a>>,
{
SQL::from_iter([Token::SELECT, Token::DISTINCT, Token::ON, Token::LPAREN])
.append(on.to_sql())
.push(Token::RPAREN)
.append(columns.to_sql())
}
fn join_using_internal<'a, Table>(
table: Table,
join: Join,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join.to_sql()
.append(table.to_sql())
.push(Token::USING)
.push(Token::LPAREN)
.append(columns.to_sql())
.push(Token::RPAREN)
}
pub fn join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new(), columns)
}
pub fn inner_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().inner(), columns)
}
pub fn left_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().left(), columns)
}
pub fn left_outer_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().left().outer(), columns)
}
pub fn right_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().right(), columns)
}
pub fn right_outer_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().right().outer(), columns)
}
pub fn full_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().full(), columns)
}
pub fn full_outer_join_using<'a, Table>(
table: Table,
columns: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
join_using_internal(table, Join::new().full().outer(), columns)
}
pub(crate) fn insert<'a, Table>(table: Table) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
SQL::from_iter([Token::INSERT, Token::INTO]).append(&table)
}
pub(crate) fn values<'a, Table, T>(
rows: impl IntoIterator<Item = Table::Insert<T>>,
) -> SQL<'a, PostgresValue<'a>>
where
Table: PostgresTable<'a>,
{
let rows: Vec<_> = rows.into_iter().collect();
if rows.is_empty() {
return SQL::from(Token::VALUES);
}
let columns_info = rows[0].columns();
let columns_slice = columns_info.as_ref();
if columns_slice.is_empty() {
return SQL::from_iter([Token::DEFAULT, Token::VALUES]);
}
let columns_sql = columns_info_to_sql(columns_slice);
let value_clauses: Vec<_> = rows.iter().map(|row| row.values().parens()).collect();
columns_sql
.parens()
.push(Token::VALUES)
.append(SQL::join(value_clauses, Token::COMMA))
}
pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQL<'a, PostgresValue<'a>>
where
I: ToSQL<'a, PostgresValue<'a>>,
{
SQL::from(Token::RETURNING).append(columns.to_sql())
}
#[allow(dead_code)]
pub(crate) fn on_conflict<'a>(
conflict_target: Option<SQL<'a, PostgresValue<'a>>>,
action: impl ToSQL<'a, PostgresValue<'a>>,
) -> SQL<'a, PostgresValue<'a>> {
let mut sql = SQL::from_iter([Token::ON, Token::CONFLICT]);
if let Some(target) = conflict_target {
sql = sql.push(Token::LPAREN).append(target).push(Token::RPAREN);
}
sql.append(action.to_sql())
}
pub(crate) fn for_update<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::UPDATE])
}
pub(crate) fn for_share<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::SHARE])
}
pub(crate) fn for_no_key_update<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::NO, Token::KEY, Token::UPDATE])
}
pub(crate) fn for_key_share<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::KEY, Token::SHARE])
}
pub(crate) fn for_update_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::UPDATE, Token::OF]).append(SQL::ident(table_name.to_owned()))
}
pub(crate) fn for_share_of<'a>(table_name: &str) -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::FOR, Token::SHARE, Token::OF]).append(SQL::ident(table_name.to_owned()))
}
pub(crate) fn nowait<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from(Token::NOWAIT)
}
pub(crate) fn skip_locked<'a>() -> SQL<'a, PostgresValue<'a>> {
SQL::from_iter([Token::SKIP, Token::LOCKED])
}