1use crate::{
46 Connection, Database, Error,
47 connection::{ConnectionOwned, Transaction},
48 database::DatabaseError,
49};
50
51#[derive(Debug, Clone)]
56#[cfg_attr(feature = "chuchi", derive(chuchi::Resource))]
57pub struct Db {
58 pg: Option<Database>,
59}
60
61impl Db {
62 pub fn new_memory() -> Self {
63 Self { pg: None }
64 }
65
66 pub async fn get(&self) -> Result<ConnOwned, DatabaseError> {
67 match &self.pg {
68 Some(pg) => Ok(ConnOwned {
69 pg: Some(pg.get().await?),
70 }),
71 None => Ok(ConnOwned { pg: None }),
72 }
73 }
74}
75
76impl From<Database> for Db {
77 fn from(pg: Database) -> Self {
78 Self { pg: Some(pg) }
79 }
80}
81
82#[derive(Debug)]
83pub struct ConnOwned {
84 pg: Option<ConnectionOwned>,
85}
86
87impl ConnOwned {
88 pub fn conn(&self) -> Conn<'_> {
90 Conn {
91 pg: self.pg.as_ref().map(|pg| pg.connection()),
92 }
93 }
94
95 pub async fn trans(&mut self) -> Result<Trans<'_>, Error> {
97 match &mut self.pg {
98 Some(pg) => Ok(Trans {
99 pg: Some(pg.transaction().await?),
100 }),
101 None => Ok(Trans { pg: None }),
102 }
103 }
104}
105
106#[cfg(feature = "chuchi")]
107mod impl_chuchi {
108 use chuchi::{
109 extractor::Extractor, extractor_extract, extractor_prepare,
110 extractor_validate,
111 };
112
113 use super::*;
114
115 impl<'a, R> Extractor<'a, R> for ConnOwned {
116 type Error = DatabaseError;
117 type Prepared = Self;
118
119 extractor_validate!(|validate| {
120 assert!(validate.resources.exists::<Db>(), "Db resource not found");
121 });
122
123 extractor_prepare!(|prepare| {
124 let db = prepare.resources.get::<Db>().unwrap();
125 db.get().await
126 });
127
128 extractor_extract!(|extract| { Ok(extract.prepared) });
129 }
130}
131
132#[derive(Debug, Clone, Copy)]
134pub struct Conn<'a> {
135 pg: Option<Connection<'a>>,
136}
137
138impl<'a> Conn<'a> {
139 pub fn new_memory() -> Self {
141 Self { pg: None }
142 }
143
144 pub fn pg(self) -> Connection<'a> {
149 self.pg.unwrap()
150 }
151}
152
153#[derive(Debug)]
155pub struct Trans<'a> {
156 pg: Option<Transaction<'a>>,
157}
158
159impl<'a> Trans<'a> {
160 pub fn conn(&self) -> Conn<'_> {
162 Conn {
163 pg: self.pg.as_ref().map(|pg| pg.connection()),
164 }
165 }
166
167 pub async fn commit(self) -> Result<(), Error> {
172 match self.pg {
173 Some(pg) => pg.commit().await,
174 None => Ok(()),
175 }
176 }
177
178 pub async fn rollback(self) -> Result<(), Error> {
183 match self.pg {
184 Some(pg) => pg.commit().await,
185 None => panic!("rollback not supported"),
186 }
187 }
188}