drizzle_sqlite/
helpers.rs

1use crate::traits::{SQLiteSQL, SQLiteTable};
2use crate::values::SQLiteValue;
3use drizzle_core::{
4    SQL, Token, helpers as core_helpers,
5    traits::{SQLColumnInfo, SQLModel, ToSQL},
6};
7
8// Re-export core helpers with SQLiteValue type for convenience
9pub(crate) use core_helpers::{
10    delete, except, except_all, from, group_by, having, insert, intersect, intersect_all, limit,
11    offset, order_by, select, select_distinct, set, union, union_all, update, r#where,
12};
13
14// Re-export Join from core
15pub use drizzle_core::Join;
16
17/// Helper to convert column info to SQL for joining (column names only for INSERT)
18fn columns_info_to_sql<'a>(columns: &[&'static dyn SQLColumnInfo]) -> SQLiteSQL<'a> {
19    // For INSERT statements, use quoted column names only (no table qualifiers)
20    SQL::join(
21        columns.iter().map(|col| SQL::ident(col.name())),
22        Token::COMMA,
23    )
24}
25
26// Generate all join helper functions using the shared macro
27drizzle_core::impl_join_helpers!(
28    table_trait: SQLiteTable<'a>,
29    condition_trait: ToSQL<'a, SQLiteValue<'a>>,
30    sql_type: SQLiteSQL<'a>,
31);
32
33/// Helper function to create VALUES clause for INSERT with pattern validation
34/// All rows must have the same column pattern (enforced by type parameter)
35pub(crate) fn values<'a, Table, T>(
36    rows: impl IntoIterator<Item = Table::Insert<T>>,
37) -> SQLiteSQL<'a>
38where
39    Table: SQLiteTable<'a> + Default,
40{
41    let rows: Vec<_> = rows.into_iter().collect();
42
43    if rows.is_empty() {
44        return SQL::from(Token::VALUES);
45    }
46
47    // Since all rows have the same PATTERN, they all have the same columns
48    // Get column info from the first row (all rows will have the same columns)
49    let columns_info = rows[0].columns();
50    let columns_slice = columns_info.as_ref();
51
52    // Check if this is a DEFAULT VALUES case (no columns)
53    if columns_slice.is_empty() {
54        return SQL::from_iter([Token::DEFAULT, Token::VALUES]);
55    }
56
57    let columns_sql = columns_info_to_sql(columns_slice);
58    let value_clauses = rows.iter().map(|row| {
59        SQL::from(Token::LPAREN)
60            .append(row.values())
61            .push(Token::RPAREN)
62    });
63
64    columns_sql
65        .parens()
66        .push(Token::VALUES)
67        .append(SQL::join(value_clauses, Token::COMMA))
68}
69
70/// Helper function to create a RETURNING clause - SQLite specific
71pub(crate) fn returning<'a, 'b, I>(columns: I) -> SQLiteSQL<'a>
72where
73    I: ToSQL<'a, SQLiteValue<'a>>,
74{
75    SQL::from(Token::RETURNING).append(&columns)
76}