1use crate::traits::{CrudOps, FromRow, SqlCommand, SqlParams, SqlQuery, UpdateParams};
2use postgres::types::{FromSql, ToSql};
3use std::sync::OnceLock;
4use tokio_postgres::{Client, Error, Row, Transaction};
5
6#[async_trait::async_trait]
7impl CrudOps for Client {
8 async fn insert<T, P: for<'a> FromSql<'a> + Send + Sync>(&self, entity: T) -> Result<P, Error>
9 where
10 T: SqlCommand + SqlParams + Send + Sync + 'static,
11 {
12 insert(self, entity).await
13 }
14
15 async fn update<T>(&self, entity: T) -> Result<bool, Error>
16 where
17 T: SqlCommand + UpdateParams + Send + Sync + 'static,
18 {
19 update(self, entity).await
20 }
21
22 async fn delete<T>(&self, entity: T) -> Result<u64, Error>
23 where
24 T: SqlCommand + SqlParams + Send + Sync + 'static,
25 {
26 delete(self, entity).await
27 }
28
29 async fn fetch<P, R>(&self, params: P) -> Result<R, Error>
30 where
31 P: SqlQuery<R> + SqlParams + Send + Sync + 'static,
32 R: FromRow + Send + Sync + 'static,
33 {
34 fetch(self, params).await
35 }
36
37 async fn fetch_all<P, R>(&self, params: P) -> Result<Vec<R>, Error>
38 where
39 P: SqlQuery<R> + SqlParams + Send + Sync + 'static,
40 R: FromRow + Send + Sync + 'static,
41 {
42 fetch_all(self, params).await
43 }
44
45 async fn select<T, F, R>(&self, entity: T, to_model: F) -> Result<R, Error>
46 where
47 T: SqlQuery<T> + SqlParams + Send + Sync + 'static,
48 F: Fn(&Row) -> Result<R, Error> + Send + Sync + 'static,
49 R: Send + 'static,
50 {
51 select(self, entity, to_model).await
52 }
53
54 async fn select_all<T, F, R>(&self, entity: T, to_model: F) -> Result<Vec<R>, Error>
55 where
56 T: SqlQuery<T> + SqlParams + Send + Sync + 'static,
57 F: Fn(&Row) -> R + Send + Sync + 'static,
58 R: Send + 'static,
59 {
60 select_all(self, entity, to_model).await
61 }
62}
63
64pub async fn insert<T, P: for<'a> FromSql<'a> + Send + Sync>(
75 client: &Client,
76 entity: T,
77) -> Result<P, Error>
78where
79 T: SqlCommand + SqlParams + Send + Sync + 'static,
80{
81 let sql = T::query();
82
83 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
84 let is_trace_enabled =
85 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
86
87 if is_trace_enabled {
88 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
89 }
90
91 let params = entity.params();
92 let row = client.query_one(&sql, ¶ms).await?;
93 row.try_get::<_, P>(0)
94}
95
96pub async fn update<T>(client: &Client, entity: T) -> Result<bool, Error>
107where
108 T: SqlCommand + UpdateParams + Send + Sync + 'static,
109{
110 let sql = T::query();
111
112 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
113 let is_trace_enabled =
114 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
115
116 if is_trace_enabled {
117 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
118 }
119
120 let params = entity.params();
121 let result = client.execute(&sql, ¶ms).await?;
122 Ok(result > 0)
123}
124
125pub async fn delete<T>(client: &Client, entity: T) -> Result<u64, Error>
136where
137 T: SqlCommand + SqlParams + Send + Sync + 'static,
138{
139 let sql = T::query();
140
141 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
142 let is_trace_enabled =
143 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
144
145 if is_trace_enabled {
146 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
147 }
148
149 let params = entity.params();
150 client.execute(&sql, ¶ms).await
151}
152
153pub async fn fetch<P, R>(client: &Client, params: P) -> Result<R, Error>
164where
165 P: SqlQuery<R> + SqlParams + Send + Sync + 'static,
166 R: FromRow + Send + Sync + 'static,
167{
168 let sql = P::query();
169
170 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
171 let is_trace_enabled =
172 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
173
174 if is_trace_enabled {
175 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
176 }
177
178 let query_params = params.params();
179 let row = client.query_one(&sql, &query_params).await?;
180 R::from_row(&row)
181}
182
183pub async fn fetch_all<P, R>(client: &Client, params: P) -> Result<Vec<R>, Error>
194where
195 P: SqlQuery<R> + SqlParams + Send + Sync + 'static,
196 R: FromRow + Send + Sync + 'static,
197{
198 let sql = P::query();
199
200 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
201 let is_trace_enabled =
202 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
203
204 if is_trace_enabled {
205 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
206 }
207
208 let query_params = params.params();
209 let rows = client.query(&sql, &query_params).await?;
210
211 let mut results = Vec::with_capacity(rows.len());
212 for row in rows {
213 results.push(R::from_row(&row)?);
214 }
215
216 Ok(results)
217}
218
219pub async fn select<T, F, R>(client: &Client, entity: T, to_model: F) -> Result<R, Error>
232where
233 T: SqlQuery<T> + SqlParams + Send + Sync + 'static,
234 F: Fn(&Row) -> Result<R, Error> + Send + Sync + 'static,
235 R: Send + 'static,
236{
237 let sql = T::query();
238
239 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
240 let is_trace_enabled =
241 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
242
243 if is_trace_enabled {
244 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
245 }
246
247 let params = entity.params();
248 let row = client.query_one(&sql, ¶ms).await?;
249 to_model(&row)
250}
251
252pub async fn select_all<T, F, R>(client: &Client, entity: T, to_model: F) -> Result<Vec<R>, Error>
265where
266 T: SqlQuery<T> + SqlParams + Send + Sync + 'static,
267 F: Fn(&Row) -> R + Send + Sync + 'static,
268 R: Send + 'static,
269{
270 let sql = T::query();
271
272 static TRACE_ENABLED: OnceLock<bool> = OnceLock::new();
273 let is_trace_enabled =
274 *TRACE_ENABLED.get_or_init(|| std::env::var("PARSQL_TRACE").unwrap_or_default() == "1");
275
276 if is_trace_enabled {
277 println!("[PARSQL-TOKIO-POSTGRES] Execute SQL: {}", sql);
278 }
279
280 let params = entity.params();
281 let rows = client.query(&sql, ¶ms).await?;
282
283 let mut results = Vec::with_capacity(rows.len());
284 for row in rows {
285 results.push(to_model(&row));
286 }
287
288 Ok(results)
289}
290
291#[deprecated(
305 since = "0.2.0",
306 note = "Renamed to `fetch`. Please use `fetch` function instead."
307)]
308pub async fn get<T>(client: &Client, params: T) -> Result<T, Error>
309where
310 T: SqlQuery<T> + FromRow + SqlParams + Send + Sync + 'static,
311{
312 fetch(client, params).await
313}
314
315#[deprecated(
329 since = "0.2.0",
330 note = "Renamed to `fetch_all`. Please use `fetch_all` function instead."
331)]
332pub async fn get_all<T>(client: &Client, params: T) -> Result<Vec<T>, Error>
333where
334 T: SqlQuery<T> + FromRow + SqlParams + Send + Sync + 'static,
335{
336 fetch_all(client, params).await
337}