use crate::traits::SQLiteTable;
use crate::values::SQLiteValue;
use core::marker::PhantomData;
use drizzle_core::builder::{
ConflictColumnsTarget, OnConflictBuilder as CoreOnConflictBuilder, OnConflictOutput,
};
use drizzle_core::{
ConflictTarget, InsertSelectCompatible, InsertSelectTable, InsertTargetColumns,
PartialInsertSelectCompatible, SQL, SQLModel, ToSQL, Token,
};
use super::select::{CompletedSelect, IntoSelectQuery};
pub use drizzle_core::builder::{
InsertColumnsSet, InsertDoUpdateSet, InsertInitial, InsertOnConflictSet, InsertReturningSet,
InsertValuesSet,
};
pub type OnConflictBuilder<'a, S, T> = CoreOnConflictBuilder<
'a,
SQLiteValue<'a>,
S,
T,
ConflictColumnsTarget<'a, SQLiteValue<'a>>,
SQLiteOnConflictOutput,
>;
#[doc(hidden)]
#[derive(Debug, Clone, Copy, Default)]
pub struct SQLiteOnConflictOutput;
impl<'a, S, T> OnConflictOutput<'a, SQLiteValue<'a>, S, T> for SQLiteOnConflictOutput {
type OnConflictSet = InsertBuilder<'a, S, InsertOnConflictSet, T>;
type DoUpdateSet = InsertBuilder<'a, S, InsertDoUpdateSet, T>;
fn on_conflict(sql: SQL<'a, SQLiteValue<'a>>) -> Self::OnConflictSet {
InsertBuilder {
sql,
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
fn do_update(sql: SQL<'a, SQLiteValue<'a>>) -> Self::DoUpdateSet {
InsertBuilder {
sql,
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}
pub type InsertBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
<Columns as drizzle_core::IntoSelectTarget>::Marker,
drizzle_core::Cons<Table, drizzle_core::Nil>,
>;
type ReturningRow<Table, Columns> =
<<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
type ReturningBuilder<'a, S, T, Columns> = InsertBuilder<
'a,
S,
InsertReturningSet,
T,
ReturningMarker<T, Columns>,
ReturningRow<T, Columns>,
>;
impl<'a, Schema, Table> InsertBuilder<'a, Schema, InsertInitial, Table>
where
Table: SQLiteTable<'a>,
{
#[inline]
pub fn value<T>(
self,
value: Table::Insert<T>,
) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
Table::Insert<T>: SQLModel<'a, SQLiteValue<'a>>,
{
self.values([value])
}
#[inline]
pub fn values<I, T>(self, values: I) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
I: IntoIterator<Item = Table::Insert<T>>,
Table::Insert<T>: SQLModel<'a, SQLiteValue<'a>>,
{
let sql = crate::helpers::values::<'a, Table, T>(values);
InsertBuilder {
sql: self.sql.append(sql),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn columns<Columns>(
self,
columns: Columns,
) -> InsertBuilder<'a, Schema, InsertColumnsSet<Columns::Columns>, Table>
where
Columns: InsertTargetColumns<'a, SQLiteValue<'a>, Table>,
{
InsertBuilder {
sql: self.sql.append(columns.into_target_columns_sql()),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn select<Q, R, ScopeProof, AggProof>(
self,
query: Q,
) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
Table: InsertSelectTable,
Q: IntoSelectQuery<'a, Schema, R>,
Q::Marker: InsertSelectCompatible<'a, SQLiteValue<'a>, Table, R>
+ drizzle_core::InsertSourceInScope<ScopeProof>
+ drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
{
let select = query.into_select_query().into_select_sql();
InsertBuilder {
sql: self
.sql
.append(Table::insert_columns_sql::<SQLiteValue<'a>>())
.append(select),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn select_raw<Q>(self, query: Q) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
Q: ToSQL<'a, SQLiteValue<'a>>,
{
InsertBuilder {
sql: self.sql.append(query.into_sql()),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}
impl<'a, Schema, Table, Targets> InsertBuilder<'a, Schema, InsertColumnsSet<Targets>, Table>
where
Table: SQLiteTable<'a> + InsertSelectTable,
{
#[inline]
pub fn select<Q, R, RequiredProof, ScopeProof, AggProof>(
self,
query: Q,
) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
Q: IntoSelectQuery<'a, Schema, R>,
Q::Marker: PartialInsertSelectCompatible<'a, SQLiteValue<'a>, Targets>
+ drizzle_core::InsertSourceInScope<ScopeProof>
+ drizzle_core::MarkerAggValidFor<Q::Grouped, AggProof>,
{
let select = query.into_select_query().into_select_sql();
InsertBuilder {
sql: self.sql.append(select),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn select_raw<Q, RequiredProof>(
self,
query: Q,
) -> InsertBuilder<'a, Schema, InsertValuesSet, Table>
where
Targets: drizzle_core::IncludesRequired<Table::RequiredColumns, RequiredProof>,
Q: ToSQL<'a, SQLiteValue<'a>>,
{
InsertBuilder {
sql: self.sql.append(query.into_sql()),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}
impl<'a, S, T> InsertBuilder<'a, S, InsertValuesSet, T> {
pub fn on_conflict<C: ConflictTarget<T>>(self, target: C) -> OnConflictBuilder<'a, S, T> {
let columns = target.conflict_columns();
let target_where = target.conflict_where_clause().map(SQL::raw);
let target_sql = SQL::join(columns.iter().map(|c| SQL::ident(*c)), Token::COMMA);
OnConflictBuilder::new(
crate::helpers::before_upsert(self.sql),
ConflictColumnsTarget::new(target_sql),
)
.with_target_where_sql(target_where)
}
#[must_use]
pub fn on_conflict_do_nothing(self) -> InsertBuilder<'a, S, InsertOnConflictSet, T> {
let conflict_sql = SQL::from_iter([Token::ON, Token::CONFLICT, Token::DO, Token::NOTHING]);
InsertBuilder {
sql: crate::helpers::before_upsert(self.sql).append(conflict_sql),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
where
Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
Columns::Marker: drizzle_core::ResolveRow<T>,
{
let returning_sql = crate::helpers::returning(columns);
InsertBuilder {
sql: self.sql.append(returning_sql),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}
impl<'a, S, T> InsertBuilder<'a, S, InsertOnConflictSet, T> {
#[inline]
pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
where
Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
Columns::Marker: drizzle_core::ResolveRow<T>,
{
let returning_sql = crate::helpers::returning(columns);
InsertBuilder {
sql: self.sql.append(returning_sql),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}
impl<'a, S, T> InsertBuilder<'a, S, InsertDoUpdateSet, T> {
pub fn r#where<E>(self, condition: E) -> InsertBuilder<'a, S, InsertOnConflictSet, T>
where
E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
E::SQLType: drizzle_core::types::BooleanLike,
{
let sql = self
.sql
.push(Token::WHERE)
.append(condition.into_expr_sql());
InsertBuilder {
sql,
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
#[inline]
pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
where
Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
Columns::Marker: drizzle_core::ResolveRow<T>,
{
let returning_sql = crate::helpers::returning(columns);
InsertBuilder {
sql: self.sql.append(returning_sql),
schema: PhantomData,
state: PhantomData,
table: PhantomData,
marker: PhantomData,
row: PhantomData,
grouped: PhantomData,
}
}
}