1use core::marker::PhantomData;
2
3pub use async_trait::async_trait;
4pub use schema::*;
5pub use tokio_postgres::{self as postgres, *};
6
7pub mod prelude {
9 pub use super::{Exec, Fetch, Table, TableHelper};
10}
11
12pub mod key;
13pub mod schema;
14pub mod untyped_key;
15
16pub struct Statement<'a> {
17 pub code: &'static str,
19 pub vals: &'a [&'a (dyn types::ToSql + Sync)],
21}
22
23impl<'a> Statement<'a> {
24 #[doc(hidden)]
25 pub fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
26 Self { code, vals }
27 }
28}
29
30pub struct Query<'a, O: From<Row>> {
34 pub code: &'static str,
36 pub vals: &'a [&'a (dyn types::ToSql + Sync)],
38 _phantom: PhantomData<O>,
40}
41
42impl<'a, O: From<Row> + Send + Sync> Query<'a, O> {
43 #[doc(hidden)]
44 pub fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
48 Self {
49 code,
50 vals,
51 _phantom: PhantomData,
52 }
53 }
54
55 pub async fn execute_on(self, client: &mut Client) -> Result<u64, Error> {
57 client.execute(self.code, self.vals).await
58 }
59}
60
61impl<'a, O: From<Row>> Query<'a, O> {
62 #[doc(hidden)]
63 pub fn casted<T: From<Row>>(self) -> Query<'a, T> {
64 Query {
65 code: self.code,
66 vals: self.vals,
67 _phantom: PhantomData,
68 }
69 }
70}
71
72#[async_trait]
73pub trait Fetch {
75 async fn fetch<'a, O: From<row::Row> + Send + Sync>(
77 &self,
78 query: Query<'a, O>,
79 ) -> Result<Vec<O>, Error>;
80}
81#[async_trait]
82impl<C: GenericClient + Sync> Fetch for C {
83 async fn fetch<'a, O: From<Row> + Send + Sync>(
84 &self,
85 query: Query<'a, O>,
86 ) -> Result<Vec<O>, Error> {
87 let res = self
88 .query(query.code, query.vals)
89 .await?
90 .into_iter()
91 .map(Into::into)
92 .collect();
93 Ok(res)
94 }
95}
96
97#[async_trait]
98pub trait Exec {
100 async fn exec<'a>(&self, stmt: Statement<'a>) -> Result<u64, Error>;
104}
105#[async_trait]
106impl<C: GenericClient + Sync> Exec for C {
107 async fn exec<'a>(&self, stmt: Statement<'a>) -> Result<u64, Error> {
108 self.execute(stmt.code, stmt.vals).await
109 }
110}
111
112pub struct WhereClause<'a> {
114 pub clause: &'static str,
116 pub vals: &'a [&'a (dyn types::ToSql + Sync)],
118}
119
120impl<'a> WhereClause<'a> {
121 #[doc(hidden)]
122 pub fn new(santa: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
123 Self {
124 clause: santa,
125 vals,
126 }
127 }
128}
129
130#[derive(Default, Debug, PartialEq, Eq, Clone)]
131pub struct InsertOptions {
132 pub on_conflict_do_nothing: bool,
133 pub on_conflict_do_update: bool,
134}
135
136#[async_trait]
137pub trait Table: From<Row> + Sync + Send {
138 fn key(&self) -> key::Key<Self>;
139 async fn fetch_by_key<C: postgres::GenericClient + Sync>(
140 key: key::Key<Self>,
141 client: &C,
142 ) -> Result<Option<Self>, postgres::Error>;
143 async fn fetch_where<C: postgres::GenericClient + Sync>(
144 client: &C,
145 where_clause: WhereClause<'_>,
146 ) -> Result<Vec<Self>, postgres::Error>;
147 async fn delete_by_key<C: postgres::GenericClient + Sync>(
148 key: key::Key<Self>,
149 client: &C,
150 ) -> Result<u64, postgres::Error>;
151 async fn delete<C: postgres::GenericClient + Sync>(
152 &self,
153 client: &C,
154 ) -> Result<u64, postgres::Error> {
155 Self::delete_by_key(self.key(), client).await
156 }
157 async fn insert<C: postgres::GenericClient + Sync>(
158 &self,
159 client: &C,
160 ) -> Result<u64, postgres::Error>;
161 async fn update<C: postgres::GenericClient + Sync>(
162 &self,
163 client: &C,
164 ) -> Result<u64, postgres::Error>;
165 async fn upsert<C: postgres::GenericClient + Sync>(
166 &self,
167 client: &C,
168 ) -> Result<u64, postgres::Error>;
169 async fn create_table<C: postgres::GenericClient + Sync>(
170 client: &C,
171 ) -> Result<(), postgres::Error>;
172 async fn bulk_insert<C: postgres::GenericClient + Sync>(
173 client: &C,
174 values: &[Self],
175 ) -> Result<(), postgres::Error> {
176 Self::bulk_insert_opt(client, values, InsertOptions::default()).await
177 }
178 async fn bulk_insert_opt<C: postgres::GenericClient + Sync>(
179 client: &C,
180 values: &[Self],
181 options: InsertOptions,
182 ) -> Result<(), postgres::Error>;
183}
184
185#[async_trait]
186pub trait TableHelper<T: 'static + Table>: Sync + Send {
187 async fn delete_by_key(&self, key: key::Key<T>) -> Result<u64, postgres::Error>;
189
190 async fn delete(&self, record: T) -> Result<u64, postgres::Error> {
191 self.delete_by_key(record.key()).await
192 }
193 async fn insert(&self, record: &T) -> Result<u64, postgres::Error>;
194 async fn update(&self, record: &T) -> Result<u64, postgres::Error>;
195 async fn upsert(&self, record: &T) -> Result<u64, postgres::Error>;
196
197 async fn fetch_table(&self, where_clause: WhereClause<'_>) -> Result<Vec<T>, postgres::Error>;
238
239 async fn bulk_insert(&self, records: &[T]) -> Result<(), postgres::Error>;
240}
241
242#[async_trait]
243impl<T: 'static + Table, C: GenericClient + Send + Sync> TableHelper<T> for C {
244 async fn delete_by_key(&self, key: key::Key<T>) -> Result<u64, postgres::Error> {
245 key.delete(self).await
246 }
247
248 async fn insert(&self, record: &T) -> Result<u64, postgres::Error> {
249 record.insert(self).await
250 }
251
252 async fn update(&self, record: &T) -> Result<u64, postgres::Error> {
253 record.update(self).await
254 }
255
256 async fn upsert(&self, record: &T) -> Result<u64, postgres::Error> {
257 record.upsert(self).await
258 }
259
260 async fn fetch_table(&self, where_clause: WhereClause<'_>) -> Result<Vec<T>, postgres::Error> {
261 T::fetch_where(self, where_clause).await
262 }
263
264 async fn bulk_insert(&self, records: &[T]) -> Result<(), postgres::Error> {
265 T::bulk_insert(self, records).await
266 }
267}
268
269#[derive(Debug)]
270pub struct Ref<T: Table + std::fmt::Debug> {
271 pub fk: untyped_key::Key,
273 _phantom: PhantomData<T>,
274}