Skip to main content

rusql_alchemy/db/query/
statement.rs

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}