1use crate::{
2 PaginationArg, SQL, SQLSchemaType, SQLTable, ToSQL, Token, expr::Expr, traits::SQLParam,
3 types::BooleanLike,
4};
5
6pub 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
15pub 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
41pub 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
51pub 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
61pub 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
71pub 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
81pub 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
91pub 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
101pub 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
111pub 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
120pub 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
130pub 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
143pub 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
156pub 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
166pub 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#[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#[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
207pub 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
217pub 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
227pub 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}