1use drizzle_core::prepared::prepare_render;
2pub use drizzle_core::{
4 OrderBy, SQL, ToSQL,
5 traits::{IsInSchema, SQLSchema, SQLTable},
6};
7
8use crate::values::SQLiteValue;
10use std::{fmt::Debug, marker::PhantomData};
11
12pub mod delete;
14pub mod insert;
15pub mod prepared;
16pub mod select;
17pub mod update;
18
19#[cfg(feature = "rusqlite")]
21pub mod rusqlite;
22
23#[cfg(feature = "turso")]
24pub mod turso;
25
26#[cfg(feature = "libsql")]
27pub mod libsql;
28
29pub use delete::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
31pub use insert::{
32 Conflict, InsertInitial, InsertOnConflictSet, InsertReturningSet, InsertValuesSet,
33};
34pub use select::{
35 SelectFromSet, SelectGroupSet, SelectInitial, SelectJoinSet, SelectLimitSet, SelectOffsetSet,
36 SelectOrderSet, SelectWhereSet,
37};
38pub use update::{UpdateInitial, UpdateReturningSet, UpdateSetClauseSet, UpdateWhereSet};
39
40#[derive(Debug, Clone)]
46pub struct OrderByClause<'a> {
47 pub expr: SQL<'a, SQLiteValue<'a>>,
49 pub direction: OrderBy,
51}
52
53impl<'a> OrderByClause<'a> {
54 pub const fn new(expr: SQL<'a, SQLiteValue<'a>>, direction: OrderBy) -> Self {
56 Self { expr, direction }
57 }
58}
59
60pub trait BuilderState {}
61
62#[derive(Debug, Clone)]
63pub struct BuilderInit;
64
65#[derive(Debug, Clone)]
66pub struct CTEInit;
67
68impl BuilderState for BuilderInit {}
69impl ExecutableState for BuilderInit {}
70
71impl ExecutableState for CTEInit {}
72
73#[derive(Debug, Clone, Default)]
78pub struct QueryBuilder<'a, Schema = (), State = (), Table = ()> {
79 pub sql: SQL<'a, SQLiteValue<'a>>,
80 schema: PhantomData<Schema>,
81 state: PhantomData<State>,
82 table: PhantomData<Table>,
83}
84
85impl<'a, Schema, State, Table> ToSQL<'a, SQLiteValue<'a>>
90 for QueryBuilder<'a, Schema, State, Table>
91{
92 fn to_sql(&self) -> SQL<'a, SQLiteValue<'a>> {
93 self.sql.clone()
94 }
95}
96
97impl<'a> QueryBuilder<'a> {
98 pub const fn new<S>() -> QueryBuilder<'a, S, BuilderInit> {
100 QueryBuilder {
101 sql: SQL::empty(),
102 schema: PhantomData,
103 state: PhantomData,
104 table: PhantomData,
105 }
106 }
107}
108
109impl<'a, Schema, State> QueryBuilder<'a, Schema, State>
110where
111 State: BuilderState,
112{
113 pub fn select<T>(&self, columns: T) -> select::SelectBuilder<'a, Schema, select::SelectInitial>
114 where
115 T: ToSQL<'a, SQLiteValue<'a>>,
116 {
117 let sql = crate::helpers::select(columns);
118 select::SelectBuilder {
119 sql,
120 schema: PhantomData,
121 state: PhantomData,
122 table: PhantomData,
123 }
124 }
125}
126
127impl<'a, Schema> QueryBuilder<'a, Schema, CTEInit> {
128 pub fn select<T>(&self, columns: T) -> select::SelectBuilder<'a, Schema, select::SelectInitial>
129 where
130 T: ToSQL<'a, SQLiteValue<'a>>,
131 {
132 let sql = self.sql.clone().append(crate::helpers::select(columns));
133 select::SelectBuilder {
134 sql,
135 schema: PhantomData,
136 state: PhantomData,
137 table: PhantomData,
138 }
139 }
140
141 pub fn with<Q, C>(&self, cte: C) -> QueryBuilder<'a, Schema, CTEInit>
142 where
143 Q: ToSQL<'a, SQLiteValue<'a>>,
144 C: AsRef<drizzle_core::expressions::DefinedCTE<'a, SQLiteValue<'a>, Q>>,
145 {
146 let sql = self
147 .sql
148 .clone()
149 .append_raw(", ")
150 .append(cte.as_ref().definition());
151 QueryBuilder {
152 sql,
153 schema: PhantomData,
154 state: PhantomData,
155 table: PhantomData,
156 }
157 }
158}
159
160impl<'a, Schema, State> QueryBuilder<'a, Schema, State>
161where
162 State: BuilderState,
163{
164 pub fn insert<Table>(
165 &self,
166 table: Table,
167 ) -> insert::InsertBuilder<'a, Schema, insert::InsertInitial, Table>
168 where
169 Table: IsInSchema<Schema> + SQLTable<'a, SQLiteValue<'a>>,
170 {
171 let sql = crate::helpers::insert(table);
172
173 insert::InsertBuilder {
174 sql,
175 schema: PhantomData,
176 state: PhantomData,
177 table: PhantomData,
178 }
179 }
180
181 pub fn update<Table>(
182 &self,
183 table: Table,
184 ) -> update::UpdateBuilder<'a, Schema, update::UpdateInitial, Table>
185 where
186 Table: IsInSchema<Schema> + SQLTable<'a, SQLiteValue<'a>>,
187 {
188 let sql = crate::helpers::update::<'a, Table, SQLiteValue<'a>>(table);
189
190 update::UpdateBuilder {
191 sql,
192 schema: PhantomData,
193 state: PhantomData,
194 table: PhantomData,
195 }
196 }
197
198 pub fn delete<T>(&self, table: T) -> delete::DeleteBuilder<'a, Schema, delete::DeleteInitial, T>
199 where
200 T: IsInSchema<Schema> + SQLTable<'a, SQLiteValue<'a>>,
201 {
202 let sql = crate::helpers::delete::<'a, T, SQLiteValue<'a>>(table);
203
204 delete::DeleteBuilder {
205 sql,
206 schema: PhantomData,
207 state: PhantomData,
208 table: PhantomData,
209 }
210 }
211
212 pub fn with<Q, C>(&self, cte: C) -> QueryBuilder<'a, Schema, CTEInit>
213 where
214 Q: ToSQL<'a, SQLiteValue<'a>>,
215 C: AsRef<drizzle_core::expressions::DefinedCTE<'a, SQLiteValue<'a>, Q>>,
216 {
217 let sql = SQL::raw("WITH").append(cte.as_ref().definition());
218 QueryBuilder {
219 sql,
220 schema: PhantomData,
221 state: PhantomData,
222 table: PhantomData,
223 }
224 }
225}
226
227pub trait ExecutableState {}
229
230impl<'a, Schema, State, Table> QueryBuilder<'a, Schema, State, Table>
231where
232 State: ExecutableState,
233{
234 pub fn prepare(&self) -> prepared::PreparedStatement<'a> {
236 let inner = prepare_render(self.sql.clone());
237
238 prepared::PreparedStatement { inner }
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn test_query_builder_new() {
248 let qb = QueryBuilder::new::<()>();
249 let sql = qb.to_sql();
250 assert_eq!(sql.sql(), "");
251 assert_eq!(sql.params().len(), 0);
252 }
253
254 #[test]
255 fn test_builder_state_trait() {
256 fn assert_builder_state<T: BuilderState>() {}
258
259 assert_builder_state::<BuilderInit>();
260 }
265}