1use crate::{
2 Connection, Database, Error,
3 connection::{ConnectionOwned, Transaction},
4 database::DatabaseError,
5};
6
7#[derive(Debug, Clone)]
12#[cfg_attr(feature = "chuchi", derive(chuchi::Resource))]
13pub struct Db {
14 pg: Option<Database>,
15}
16
17impl Db {
18 pub fn new_memory() -> Self {
19 Self { pg: None }
20 }
21
22 pub async fn get(&self) -> Result<ConnOwned, DatabaseError> {
23 match &self.pg {
24 Some(pg) => Ok(ConnOwned {
25 pg: Some(pg.get().await?),
26 }),
27 None => Ok(ConnOwned { pg: None }),
28 }
29 }
30}
31
32impl From<Database> for Db {
33 fn from(pg: Database) -> Self {
34 Self { pg: Some(pg) }
35 }
36}
37
38#[derive(Debug)]
39pub struct ConnOwned {
40 pg: Option<ConnectionOwned>,
41}
42
43impl ConnOwned {
44 pub fn conn(&self) -> Conn {
46 Conn {
47 pg: self.pg.as_ref().map(|pg| pg.connection()),
48 }
49 }
50
51 #[allow(dead_code)]
53 pub async fn trans(&mut self) -> Result<Trans, Error> {
54 match &mut self.pg {
55 Some(pg) => Ok(Trans {
56 pg: Some(pg.transaction().await?),
57 }),
58 None => Ok(Trans { pg: None }),
59 }
60 }
61}
62
63#[cfg(feature = "chuchi")]
64mod impl_chuchi {
65 use chuchi::{
66 extractor::Extractor, extractor_extract, extractor_prepare,
67 extractor_validate,
68 };
69
70 use super::*;
71
72 impl<'a, R> Extractor<'a, R> for ConnOwned {
73 type Error = DatabaseError;
74 type Prepared = Self;
75
76 extractor_validate!(|validate| {
77 assert!(validate.resources.exists::<Db>(), "Db resource not found");
78 });
79
80 extractor_prepare!(|prepare| {
81 let db = prepare.resources.get::<Db>().unwrap();
82 db.get().await
83 });
84
85 extractor_extract!(|extract| { Ok(extract.prepared) });
86 }
87}
88
89#[derive(Debug, Clone, Copy)]
91pub struct Conn<'a> {
92 pg: Option<Connection<'a>>,
93}
94
95impl<'a> Conn<'a> {
96 pub fn new_memory() -> Self {
98 Self { pg: None }
99 }
100
101 pub fn pg(self) -> Connection<'a> {
106 self.pg.unwrap()
107 }
108}
109
110#[derive(Debug)]
112pub struct Trans<'a> {
113 pg: Option<Transaction<'a>>,
114}
115
116impl<'a> Trans<'a> {
117 pub fn conn(&self) -> Conn {
119 Conn {
120 pg: self.pg.as_ref().map(|pg| pg.connection()),
121 }
122 }
123
124 pub async fn commit(self) -> Result<(), Error> {
129 match self.pg {
130 Some(pg) => pg.commit().await,
131 None => Ok(()),
132 }
133 }
134
135 pub async fn rollback(self) -> Result<(), Error> {
140 match self.pg {
141 Some(pg) => pg.commit().await,
142 None => panic!("rollback not supported"),
143 }
144 }
145}