1use async_trait::async_trait;
2use hydracache_core::CacheCodec;
3use hydracache_db::{DbAdapterKind, DbQuery, DbResultShape};
4use serde::{de::DeserializeOwned, Serialize};
5use sqlx::{query::QueryAs, Database, Executor, FromRow, IntoArguments};
6
7use crate::Result;
8
9#[async_trait]
16pub trait SqlxQueryExt<T, C>
17where
18 C: CacheCodec,
19{
20 async fn sqlx_one<'q, DB, A, E>(self, executor: E, query: QueryAs<'q, DB, T, A>) -> Result<T>
22 where
23 'q: 'static,
24 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
25 DB: Database + Send + Sync + 'static,
26 A: IntoArguments<'q, DB> + Send + 'static,
27 E: Send + Sync + 'static,
28 for<'c> &'c E: Executor<'c, Database = DB>;
29
30 async fn sqlx_optional<'q, DB, A, E>(
32 self,
33 executor: E,
34 query: QueryAs<'q, DB, T, A>,
35 ) -> Result<Option<T>>
36 where
37 'q: 'static,
38 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
39 DB: Database + Send + Sync + 'static,
40 A: IntoArguments<'q, DB> + Send + 'static,
41 E: Send + Sync + 'static,
42 for<'c> &'c E: Executor<'c, Database = DB>;
43
44 async fn sqlx_all<'q, DB, A, E>(
46 self,
47 executor: E,
48 query: QueryAs<'q, DB, T, A>,
49 ) -> Result<Vec<T>>
50 where
51 'q: 'static,
52 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
53 DB: Database + Send + Sync + 'static,
54 A: IntoArguments<'q, DB> + Send + 'static,
55 E: Send + Sync + 'static,
56 for<'c> &'c E: Executor<'c, Database = DB>;
57}
58
59#[async_trait]
60impl<T, C> SqlxQueryExt<T, C> for DbQuery<T, C>
61where
62 C: CacheCodec,
63{
64 async fn sqlx_one<'q, DB, A, E>(self, executor: E, query: QueryAs<'q, DB, T, A>) -> Result<T>
65 where
66 'q: 'static,
67 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
68 DB: Database + Send + Sync + 'static,
69 A: IntoArguments<'q, DB> + Send + 'static,
70 E: Send + Sync + 'static,
71 for<'c> &'c E: Executor<'c, Database = DB>,
72 {
73 self.adapter_context(DbAdapterKind::Sqlx, DbResultShape::One)
74 .fetch_value_with(move || async move { query.fetch_one(&executor).await })
75 .await
76 .map_err(Into::into)
77 }
78
79 async fn sqlx_optional<'q, DB, A, E>(
80 self,
81 executor: E,
82 query: QueryAs<'q, DB, T, A>,
83 ) -> Result<Option<T>>
84 where
85 'q: 'static,
86 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
87 DB: Database + Send + Sync + 'static,
88 A: IntoArguments<'q, DB> + Send + 'static,
89 E: Send + Sync + 'static,
90 for<'c> &'c E: Executor<'c, Database = DB>,
91 {
92 self.adapter_context(DbAdapterKind::Sqlx, DbResultShape::Optional)
93 .fetch_value_with(move || async move { query.fetch_optional(&executor).await })
94 .await
95 .map_err(Into::into)
96 }
97
98 async fn sqlx_all<'q, DB, A, E>(
99 self,
100 executor: E,
101 query: QueryAs<'q, DB, T, A>,
102 ) -> Result<Vec<T>>
103 where
104 'q: 'static,
105 T: Serialize + DeserializeOwned + Send + Unpin + for<'r> FromRow<'r, DB::Row> + 'static,
106 DB: Database + Send + Sync + 'static,
107 A: IntoArguments<'q, DB> + Send + 'static,
108 E: Send + Sync + 'static,
109 for<'c> &'c E: Executor<'c, Database = DB>,
110 {
111 self.adapter_context(DbAdapterKind::Sqlx, DbResultShape::All)
112 .fetch_value_with(move || async move { query.fetch_all(&executor).await })
113 .await
114 .map_err(Into::into)
115 }
116}