Skip to main content

drizzle_core/
helpers.rs

1use crate::{
2    PaginationArg, SQL, SQLSchemaType, SQLTable, ToSQL, Token, expr::Expr, traits::SQLParam,
3    types::BooleanLike,
4};
5
6/// Helper function to create a SELECT statement with the given columns
7pub fn select<'a, Value, T>(columns: T) -> SQL<'a, Value>
8where
9    Value: SQLParam,
10    T: ToSQL<'a, Value>,
11{
12    SQL::from(Token::SELECT).append(columns.into_sql())
13}
14
15/// Helper function to create a SELECT DISTINCT statement with the given columns
16pub fn select_distinct<'a, Value, T>(columns: T) -> SQL<'a, Value>
17where
18    Value: SQLParam,
19    T: ToSQL<'a, Value>,
20{
21    SQL::from_iter([Token::SELECT, Token::DISTINCT]).append(columns.into_sql())
22}
23
24fn set_op<'a, Value, L, R>(left: L, op: Token, all: bool, right: R) -> SQL<'a, Value>
25where
26    Value: SQLParam,
27    L: ToSQL<'a, Value>,
28    R: ToSQL<'a, Value>,
29{
30    let left = left.into_sql();
31    let right = right.into_sql();
32    let op_sql = if all {
33        SQL::from(op).push(Token::ALL)
34    } else {
35        SQL::from(op)
36    };
37
38    left.append(op_sql).append(right)
39}
40
41/// Helper function to create a UNION statement
42pub fn union<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
43where
44    Value: SQLParam,
45    L: ToSQL<'a, Value>,
46    R: ToSQL<'a, Value>,
47{
48    set_op(left, Token::UNION, false, right)
49}
50
51/// Helper function to create a UNION ALL statement
52pub fn union_all<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
53where
54    Value: SQLParam,
55    L: ToSQL<'a, Value>,
56    R: ToSQL<'a, Value>,
57{
58    set_op(left, Token::UNION, true, right)
59}
60
61/// Helper function to create an INTERSECT statement
62pub fn intersect<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
63where
64    Value: SQLParam,
65    L: ToSQL<'a, Value>,
66    R: ToSQL<'a, Value>,
67{
68    set_op(left, Token::INTERSECT, false, right)
69}
70
71/// Helper function to create an INTERSECT ALL statement
72pub fn intersect_all<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
73where
74    Value: SQLParam,
75    L: ToSQL<'a, Value>,
76    R: ToSQL<'a, Value>,
77{
78    set_op(left, Token::INTERSECT, true, right)
79}
80
81/// Helper function to create an EXCEPT statement
82pub fn except<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
83where
84    Value: SQLParam,
85    L: ToSQL<'a, Value>,
86    R: ToSQL<'a, Value>,
87{
88    set_op(left, Token::EXCEPT, false, right)
89}
90
91/// Helper function to create an EXCEPT ALL statement
92pub fn except_all<'a, Value, L, R>(left: L, right: R) -> SQL<'a, Value>
93where
94    Value: SQLParam,
95    L: ToSQL<'a, Value>,
96    R: ToSQL<'a, Value>,
97{
98    set_op(left, Token::EXCEPT, true, right)
99}
100
101/// Creates an INSERT INTO statement with the specified table
102pub fn insert<'a, Table, Type, Value>(table: &Table) -> SQL<'a, Value>
103where
104    Type: SQLSchemaType,
105    Value: SQLParam,
106    Table: SQLTable<'a, Type, Value>,
107{
108    SQL::from_iter([Token::INSERT, Token::INTO]).append(table)
109}
110
111/// Helper function to create a FROM clause
112pub fn from<'a, T, Value>(query: T) -> SQL<'a, Value>
113where
114    T: ToSQL<'a, Value>,
115    Value: SQLParam,
116{
117    SQL::from(Token::FROM).append(query.into_sql())
118}
119
120/// Helper function to create a WHERE clause
121pub fn r#where<'a, V, E>(condition: E) -> SQL<'a, V>
122where
123    V: SQLParam + 'a,
124    E: Expr<'a, V>,
125    E::SQLType: BooleanLike,
126{
127    SQL::from(Token::WHERE).append(condition.into_sql())
128}
129
130/// Helper function to create a GROUP BY clause
131pub fn group_by<'a, V, I, T>(expressions: I) -> SQL<'a, V>
132where
133    V: SQLParam + 'a,
134    I: IntoIterator<Item = T>,
135    T: ToSQL<'a, V>,
136{
137    SQL::from_iter([Token::GROUP, Token::BY]).append(SQL::join(
138        expressions.into_iter().map(ToSQL::into_sql),
139        Token::COMMA,
140    ))
141}
142
143/// Helper function to create a GROUP BY clause from a single `ToSQL` item.
144///
145/// Unlike [`group_by`], this takes a single expression (which may be a
146/// column ZST or a tuple of columns whose `ToSQL` impl already produces
147/// comma-separated SQL).
148pub fn group_by_expr<'a, V, T>(expr: T) -> SQL<'a, V>
149where
150    V: SQLParam + 'a,
151    T: ToSQL<'a, V>,
152{
153    SQL::from_iter([Token::GROUP, Token::BY]).append(expr.into_sql())
154}
155
156/// Helper function to create a HAVING clause
157pub fn having<'a, V, E>(condition: E) -> SQL<'a, V>
158where
159    V: SQLParam + 'a,
160    E: Expr<'a, V>,
161    E::SQLType: BooleanLike,
162{
163    SQL::from(Token::HAVING).append(condition.into_sql())
164}
165
166/// Helper function to create an ORDER BY clause
167pub fn order_by<'a, T, V>(expressions: T) -> SQL<'a, V>
168where
169    T: ToSQL<'a, V>,
170    V: SQLParam + 'a,
171{
172    SQL::from_iter([Token::ORDER, Token::BY]).append(expressions.into_sql())
173}
174
175/// Helper function to create a LIMIT clause
176///
177/// # Panics
178///
179/// Panics when a signed numeric argument is negative or a numeric value does
180/// not fit in `usize`.
181#[must_use]
182#[track_caller]
183pub fn limit<'a, V, P>(value: P) -> SQL<'a, V>
184where
185    V: SQLParam + 'a,
186    P: PaginationArg<'a, V>,
187{
188    SQL::from(Token::LIMIT).append(value.into_pagination_sql())
189}
190
191/// Helper function to create an OFFSET clause
192///
193/// # Panics
194///
195/// Panics when a signed numeric argument is negative or a numeric value does
196/// not fit in `usize`.
197#[must_use]
198#[track_caller]
199pub fn offset<'a, V, P>(value: P) -> SQL<'a, V>
200where
201    V: SQLParam + 'a,
202    P: PaginationArg<'a, V>,
203{
204    SQL::from(Token::OFFSET).append(value.into_pagination_sql())
205}
206
207/// Helper function to create an UPDATE statement
208pub fn update<'a, Table, Type, Value>(table: &Table) -> SQL<'a, Value>
209where
210    Table: SQLTable<'a, Type, Value>,
211    Type: SQLSchemaType,
212    Value: SQLParam + 'a,
213{
214    SQL::from(Token::UPDATE).append(table)
215}
216
217/// Helper function to create a SET clause for UPDATE
218pub fn set<'a, Table, Type, Value>(assignments: &Table::Update) -> SQL<'a, Value>
219where
220    Value: SQLParam + 'a,
221    Table: SQLTable<'a, Type, Value>,
222    Type: SQLSchemaType,
223{
224    SQL::from(Token::SET).append(assignments.to_sql())
225}
226
227/// Helper function to create a DELETE FROM statement
228pub fn delete<'a, Table, Type, Value>(table: &Table) -> SQL<'a, Value>
229where
230    Table: SQLTable<'a, Type, Value>,
231    Type: SQLSchemaType,
232    Value: SQLParam + 'a,
233{
234    SQL::from_iter([Token::DELETE, Token::FROM]).append(table)
235}