1use super::{Arg, builder, condition::Kwargs};
2use crate::{
3 Error,
4 db::{Connection, model::Model},
5};
6
7pub enum JoinType {
8 Inner,
9 Left,
10 Right,
11 Full,
12}
13
14impl std::fmt::Display for JoinType {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 let join_type_name = match self {
17 JoinType::Inner => "INNER",
18 JoinType::Left => "LEFT",
19 JoinType::Right => "RIGHT",
20 JoinType::Full => "FULL",
21 };
22 std::write!(f, "{}", join_type_name)
23 }
24}
25
26pub struct SelectBuilder {
27 select_clause: String,
28 from_table: Option<&'static str>,
29 joins: Vec<JoinClause>,
30 where_conditions: Option<Vec<Kwargs>>,
31}
32
33struct JoinClause {
34 join_type: JoinType,
35 table: &'static str,
36 on_conditions: Vec<Kwargs>,
37}
38
39impl SelectBuilder {
40 pub fn new(select_clause: String, from_table: Option<&'static str>) -> Self {
41 Self {
42 select_clause,
43 from_table,
44 joins: Vec::new(),
45 where_conditions: None,
46 }
47 }
48
49 pub fn inner_join<Base: Model, Join: Model>(mut self, on: Vec<Kwargs>) -> Self {
50 if self.from_table.is_none() {
51 self.from_table = Some(Base::NAME);
52 }
53
54 self.joins.push(JoinClause {
55 join_type: JoinType::Inner,
56 table: Join::NAME,
57 on_conditions: on,
58 });
59
60 self
61 }
62
63 pub fn left_join<Base: Model, Join: Model>(mut self, on: Vec<Kwargs>) -> Self {
64 if self.from_table.is_none() {
65 self.from_table = Some(Base::NAME);
66 }
67
68 self.joins.push(JoinClause {
69 join_type: JoinType::Left,
70 table: Join::NAME,
71 on_conditions: on,
72 });
73
74 self
75 }
76
77 pub fn right_join<Base: Model, Join: Model>(mut self, on: Vec<Kwargs>) -> Self {
78 if self.from_table.is_none() {
79 self.from_table = Some(Base::NAME);
80 }
81
82 self.joins.push(JoinClause {
83 join_type: JoinType::Right,
84 table: Join::NAME,
85 on_conditions: on,
86 });
87
88 self
89 }
90
91 pub fn r#where(mut self, conditions: Vec<Kwargs>) -> Self {
92 self.where_conditions = Some(conditions);
93 self
94 }
95
96 fn build_query(&self) -> (String, Vec<Arg>) {
97 let mut query = format!("SELECT {}", self.select_clause);
98 let mut args = Vec::new();
99
100 if let Some(from_table) = &self.from_table {
101 query.push_str(&format!(" FROM {}", from_table));
102 }
103
104 for join in &self.joins {
105 let select_query = builder::to_select_query(join.on_conditions.clone());
106 query.push_str(&format!(
107 " {} JOIN {} ON {}",
108 join.join_type, join.table, select_query.placeholders
109 ));
110 args.extend(select_query.args);
111 }
112
113 if let Some(conditions) = &self.where_conditions {
114 let select_query = builder::to_select_query(conditions.clone());
115 query.push_str(&format!(" WHERE {}", select_query.placeholders));
116 args.extend(select_query.args);
117 }
118
119 query.push(';');
120
121 (query, args)
122 }
123
124 #[cfg(not(feature = "turso"))]
125 pub async fn fetch_one<Output>(self, conn: &Connection) -> Result<Output, Error>
126 where
127 Output: Unpin + Send + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow>,
128 {
129 let (query, args) = self.build_query();
130
131 let mut stream = sqlx::query_as::<_, Output>(&query);
132 binds!(args, stream);
133
134 Ok(stream.fetch_one(conn).await?)
135 }
136
137 #[cfg(feature = "turso")]
138 pub async fn fetch_one<Output>(self, conn: &Connection) -> Result<Output, Error>
139 where
140 Output: for<'de> serde::Deserialize<'de>,
141 {
142 let (query, args) = self.build_query();
143 let params = binds!(args.iter());
144
145 let row = conn
146 .query(&query, params)
147 .await?
148 .next()
149 .await?
150 .ok_or("No rows returned")?;
151
152 Ok(libsql::de::from_row::<Output>(&row)?)
153 }
154
155 #[cfg(not(feature = "turso"))]
156 pub async fn fetch_all<Output>(self, conn: &Connection) -> Result<Vec<Output>, Error>
157 where
158 Output: Unpin + Send + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow>,
159 {
160 let (query, args) = self.build_query();
161
162 let mut stream = sqlx::query_as::<_, Output>(&query);
163 binds!(args, stream);
164
165 Ok(stream.fetch_all(conn).await?)
166 }
167
168 #[cfg(feature = "turso")]
169 pub async fn fetch_all<Output>(self, conn: &Connection) -> Result<Vec<Output>, Error>
170 where
171 Output: for<'de> serde::Deserialize<'de>,
172 {
173 let (query, args) = self.build_query();
174 let params = binds!(args.iter());
175
176 let rows = conn.query(&query, params).await?;
177 let results = crate::utils::libsql_from_row(rows).await?;
178 Ok(results)
179 }
180
181 #[cfg(not(feature = "turso"))]
182 pub async fn fetch_optional<Output>(self, conn: &Connection) -> Result<Option<Output>, Error>
183 where
184 Output: Unpin + Send + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow>,
185 {
186 let (query, args) = self.build_query();
187
188 let mut stream = sqlx::query_as::<_, Output>(&query);
189 binds!(args, stream);
190
191 Ok(stream.fetch_optional(conn).await?)
192 }
193
194 #[cfg(feature = "turso")]
195 pub async fn fetch_optional<Output>(self, conn: &Connection) -> Result<Option<Output>, Error>
196 where
197 Output: for<'de> serde::Deserialize<'de>,
198 {
199 let (query, args) = self.build_query();
200 let params = binds!(args.iter());
201
202 let mut rows = conn.query(&query, params).await?;
203
204 if let Some(row) = rows.next().await? {
205 Ok(Some(libsql::de::from_row::<Output>(&row)?))
206 } else {
207 Ok(None)
208 }
209 }
210}