sqlb/
select.rs

1use crate::core::{add_to_where, sql_where_items, Whereable};
2use crate::core::{OrderItem, WhereItem};
3use crate::sqlx_exec;
4use crate::utils::{x_column_name, x_table_name};
5use crate::{SqlBuilder, SqlxBindable};
6use async_trait::async_trait;
7use sqlx::{Executor, FromRow, Postgres};
8
9pub fn select<'a>() -> SelectSqlBuilder<'a> {
10	SelectSqlBuilder {
11		table: None,
12		columns: None,
13		and_wheres: Vec::new(),
14		order_bys: None,
15		limit: None,
16		offset: None,
17	}
18}
19
20pub struct SelectSqlBuilder<'a> {
21	table: Option<String>,
22	columns: Option<Vec<String>>,
23	and_wheres: Vec<WhereItem<'a>>,
24	order_bys: Option<Vec<OrderItem>>,
25	limit: Option<i64>,
26	offset: Option<i64>,
27}
28
29impl<'a> SelectSqlBuilder<'a> {
30	pub fn and_where_eq<T: 'a + SqlxBindable + Send + Sync>(mut self, name: &str, val: T) -> Self {
31		add_to_where(&mut self.and_wheres, name, "=", val);
32		self
33	}
34
35	pub fn and_where<T: 'a + SqlxBindable + Send + Sync>(mut self, name: &str, op: &'static str, val: T) -> Self {
36		add_to_where(&mut self.and_wheres, name, op, val);
37		self
38	}
39
40	pub fn table(mut self, table: &str) -> Self {
41		self.table = Some(table.to_string());
42		self
43	}
44
45	pub fn columns(mut self, names: &[&str]) -> Self {
46		self.columns = Some(names.iter().map(|s| s.to_string()).collect());
47		self
48	}
49
50	pub fn order_bys(mut self, odrs: &[&str]) -> Self {
51		self.order_bys = Some(odrs.iter().copied().map(|o| o.into()).collect());
52		self
53	}
54
55	pub fn order_by(mut self, odr: &str) -> Self {
56		self.order_bys = Some(vec![odr.into()]);
57		self
58	}
59
60	pub fn limit(mut self, limit: i64) -> Self {
61		self.limit = Some(limit);
62		self
63	}
64
65	pub fn offset(mut self, offset: i64) -> Self {
66		self.offset = Some(offset);
67		self
68	}
69
70	pub async fn exec<'q, DB>(&'a self, db_pool: DB) -> Result<u64, sqlx::Error>
71	where
72		DB: Executor<'q, Database = Postgres>,
73	{
74		sqlx_exec::exec(db_pool, self).await
75	}
76
77	pub async fn fetch_one<'e, DB, D>(&'a self, db_pool: DB) -> Result<D, sqlx::Error>
78	where
79		DB: Executor<'e, Database = Postgres>,
80		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
81	{
82		sqlx_exec::fetch_as_one::<DB, D, _>(db_pool, self).await
83	}
84
85	pub async fn fetch_optional<'e, DB, D>(&'a self, db_pool: DB) -> Result<Option<D>, sqlx::Error>
86	where
87		DB: Executor<'e, Database = Postgres>,
88		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
89	{
90		sqlx_exec::fetch_as_optional::<DB, D, _>(db_pool, self).await
91	}
92
93	pub async fn fetch_all<'e, DB, D>(&'a self, db_pool: DB) -> Result<Vec<D>, sqlx::Error>
94	where
95		DB: Executor<'e, Database = Postgres>,
96		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
97	{
98		sqlx_exec::fetch_as_all::<DB, D, _>(db_pool, self).await
99	}
100}
101
102impl<'a> Whereable<'a> for SelectSqlBuilder<'a> {
103	fn and_where_eq<V: 'a + SqlxBindable + Send + Sync>(self, name: &str, val: V) -> Self {
104		SelectSqlBuilder::and_where_eq(self, name, val)
105	}
106
107	fn and_where<V: 'a + SqlxBindable + Send + Sync>(self, name: &str, op: &'static str, val: V) -> Self {
108		SelectSqlBuilder::and_where(self, name, op, val)
109	}
110}
111
112#[async_trait]
113impl<'a> SqlBuilder<'a> for SelectSqlBuilder<'a> {
114	fn sql(&self) -> String {
115		// SELECT name1, name2 FROM table_name WHERE w1 < r1, w2 = r2
116
117		// SQL: SELECT
118		let mut sql = String::from("SELECT ");
119
120		// SQL: name1, name2,
121		// For now, if no column, will do a "*"
122		match &self.columns {
123			Some(columns) => {
124				let names = columns.iter().map(|c| x_column_name(c)).collect::<Vec<String>>().join(", ");
125				sql.push_str(&format!("{} ", names));
126			}
127			None => sql.push_str(&format!("{} ", "*")),
128		};
129
130		// SQL: FROM table_name
131		if let Some(table) = &self.table {
132			sql.push_str("FROM ");
133			sql.push_str(&x_table_name(table));
134		}
135
136		// SQL: WHERE w1 < $1, ...
137		if !self.and_wheres.is_empty() {
138			let sql_where = sql_where_items(&self.and_wheres, 1);
139			sql.push_str(&format!("WHERE {} ", &sql_where));
140		}
141
142		// SQL: ORDER BY
143		if let Some(order_bys) = &self.order_bys {
144			let sql_order_bys = order_bys
145				.iter()
146				.map::<String, _>(|o| o.into())
147				.collect::<Vec<String>>()
148				.join(", ");
149			sql.push_str(&format!("ORDER BY {} ", sql_order_bys))
150		}
151
152		// SQL: LIMIT
153		if let Some(limit) = &self.limit {
154			sql.push_str(&format!("LIMIT {limit} "))
155		}
156
157		// SQL: OFFSET
158		if let Some(offset) = &self.offset {
159			sql.push_str(&format!("OFFSET {offset} "))
160		}
161
162		sql
163	}
164
165	fn vals(&'a self) -> Box<dyn Iterator<Item = &Box<dyn SqlxBindable + 'a + Send + Sync>> + 'a + Send> {
166		let iter = self.and_wheres.iter().map(|wi| &wi.val);
167		Box::new(iter)
168	}
169
170	async fn exec<'q, DB>(&'a self, db_pool: DB) -> Result<u64, sqlx::Error>
171	where
172		DB: Executor<'q, Database = Postgres>,
173	{
174		Self::exec(self, db_pool).await
175	}
176
177	async fn fetch_one<'e, DB, D>(&'a self, db_pool: DB) -> Result<D, sqlx::Error>
178	where
179		DB: Executor<'e, Database = Postgres>,
180		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
181	{
182		Self::fetch_one::<DB, D>(self, db_pool).await
183	}
184
185	async fn fetch_optional<'e, DB, D>(&'a self, db_pool: DB) -> Result<Option<D>, sqlx::Error>
186	where
187		DB: Executor<'e, Database = Postgres>,
188		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
189	{
190		Self::fetch_optional::<DB, D>(self, db_pool).await
191	}
192
193	async fn fetch_all<'e, DB, D>(&'a self, db_pool: DB) -> Result<Vec<D>, sqlx::Error>
194	where
195		DB: Executor<'e, Database = Postgres>,
196		D: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send,
197	{
198		Self::fetch_all::<DB, D>(self, db_pool).await
199	}
200}