systemprompt_database/services/
database.rs1use super::postgres::PostgresProvider;
17use super::postgres::connection::PoolConfig;
18use super::provider::DatabaseProvider;
19use crate::error::DatabaseResult;
20use crate::models::{DatabaseInfo, QueryResult};
21use std::sync::Arc;
22
23pub struct Database {
24 provider: Arc<dyn DatabaseProvider>,
25 write_provider: Option<Arc<dyn DatabaseProvider>>,
26 session_provider: Option<Arc<dyn DatabaseProvider>>,
27}
28
29impl std::fmt::Debug for Database {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.debug_struct("Database")
32 .field("backend", &"PostgreSQL")
33 .finish()
34 }
35}
36
37impl Database {
38 pub async fn new_postgres(url: &str) -> DatabaseResult<Self> {
39 let provider = PostgresProvider::new(url).await?;
40 Ok(Self {
41 provider: Arc::new(provider),
42 write_provider: None,
43 session_provider: None,
44 })
45 }
46
47 pub async fn connect(
48 read_url: &str,
49 write_url: Option<&str>,
50 pool: &PoolConfig,
51 ) -> DatabaseResult<Self> {
52 let provider: Arc<dyn DatabaseProvider> =
53 Arc::new(PostgresProvider::new_with_pool(read_url, pool).await?);
54
55 let write_provider: Option<Arc<dyn DatabaseProvider>> = match write_url {
56 Some(url) => Some(Arc::new(PostgresProvider::new_with_pool(url, pool).await?)),
57 None => None,
58 };
59
60 Ok(Self {
61 provider,
62 write_provider,
63 session_provider: None,
64 })
65 }
66
67 pub async fn with_session_url(
68 mut self,
69 session_url: Option<&str>,
70 pool: &PoolConfig,
71 ) -> DatabaseResult<Self> {
72 if let Some(url) = session_url {
73 self.session_provider =
74 Some(Arc::new(PostgresProvider::new_with_pool(url, pool).await?));
75 }
76 Ok(self)
77 }
78
79 #[must_use]
80 pub fn from_pools(read: Arc<sqlx::PgPool>, write: Option<Arc<sqlx::PgPool>>) -> Self {
81 let write_provider = write.map(|pool| -> Arc<dyn DatabaseProvider> {
82 Arc::new(PostgresProvider::from_pool(pool))
83 });
84 Self {
85 provider: Arc::new(PostgresProvider::from_pool(read)),
86 write_provider,
87 session_provider: None,
88 }
89 }
90
91 #[must_use]
92 pub fn read(&self) -> &dyn DatabaseProvider {
93 self.provider.as_ref()
94 }
95
96 #[must_use]
97 pub fn write(&self) -> &dyn DatabaseProvider {
98 self.write_provider
99 .as_deref()
100 .unwrap_or_else(|| self.provider.as_ref())
101 }
102
103 #[must_use]
104 pub fn session(&self) -> &dyn DatabaseProvider {
105 self.session_provider
106 .as_deref()
107 .unwrap_or_else(|| self.write())
108 }
109
110 #[must_use]
111 pub fn pool(&self) -> Arc<sqlx::PgPool> {
112 self.read().get_postgres_pool()
113 }
114
115 #[must_use]
116 pub fn write_pool(&self) -> Arc<sqlx::PgPool> {
117 self.write().get_postgres_pool()
118 }
119
120 #[must_use]
121 pub fn session_pool(&self) -> Arc<sqlx::PgPool> {
122 self.session().get_postgres_pool()
123 }
124
125 #[must_use]
126 pub fn has_session_pool(&self) -> bool {
127 self.session_provider.is_some()
128 }
129
130 #[must_use]
131 pub fn has_write_pool(&self) -> bool {
132 self.write_provider.is_some()
133 }
134
135 pub async fn execute_batch(&self, sql: &str) -> DatabaseResult<()> {
136 self.write().execute_batch(sql).await
137 }
138
139 pub async fn get_info(&self) -> DatabaseResult<DatabaseInfo> {
140 self.read().get_database_info().await
141 }
142
143 pub async fn test_connection(&self) -> DatabaseResult<()> {
144 self.provider.test_connection().await?;
145 if let Some(wp) = &self.write_provider {
146 wp.test_connection().await?;
147 }
148 if let Some(sp) = &self.session_provider {
149 sp.test_connection().await?;
150 }
151 Ok(())
152 }
153
154 pub async fn begin(&self) -> DatabaseResult<sqlx::Transaction<'_, sqlx::Postgres>> {
155 self.write_pool().begin().await.map_err(Into::into)
156 }
157}
158
159pub type DbPool = Arc<Database>;
160
161pub trait DatabaseExt {
162 fn database(&self) -> Arc<Database>;
163}
164
165impl DatabaseExt for Arc<Database> {
166 fn database(&self) -> Arc<Database> {
167 Self::clone(self)
168 }
169}
170
171#[async_trait::async_trait]
172impl DatabaseProvider for Database {
173 fn get_postgres_pool(&self) -> Arc<sqlx::PgPool> {
174 self.read().get_postgres_pool()
175 }
176
177 async fn execute(
178 &self,
179 query: &dyn crate::models::QuerySelector,
180 params: &[&dyn crate::models::ToDbValue],
181 ) -> DatabaseResult<u64> {
182 self.write().execute(query, params).await
183 }
184
185 async fn execute_raw(&self, sql: &str) -> DatabaseResult<()> {
186 self.write().execute_raw(sql).await
187 }
188
189 async fn fetch_all(
190 &self,
191 query: &dyn crate::models::QuerySelector,
192 params: &[&dyn crate::models::ToDbValue],
193 ) -> DatabaseResult<Vec<crate::models::JsonRow>> {
194 self.read().fetch_all(query, params).await
195 }
196
197 async fn fetch_one(
198 &self,
199 query: &dyn crate::models::QuerySelector,
200 params: &[&dyn crate::models::ToDbValue],
201 ) -> DatabaseResult<crate::models::JsonRow> {
202 self.read().fetch_one(query, params).await
203 }
204
205 async fn fetch_optional(
206 &self,
207 query: &dyn crate::models::QuerySelector,
208 params: &[&dyn crate::models::ToDbValue],
209 ) -> DatabaseResult<Option<crate::models::JsonRow>> {
210 self.read().fetch_optional(query, params).await
211 }
212
213 async fn begin_transaction(
214 &self,
215 ) -> DatabaseResult<Box<dyn crate::models::DatabaseTransaction>> {
216 self.write().begin_transaction().await
217 }
218
219 async fn get_database_info(&self) -> DatabaseResult<DatabaseInfo> {
220 self.read().get_database_info().await
221 }
222
223 async fn test_connection(&self) -> DatabaseResult<()> {
224 self.read().test_connection().await
225 }
226
227 async fn execute_batch(&self, sql: &str) -> DatabaseResult<()> {
228 self.write().execute_batch(sql).await
229 }
230
231 async fn query_raw(
232 &self,
233 query: &dyn crate::models::QuerySelector,
234 ) -> DatabaseResult<QueryResult> {
235 self.read().query_raw(query).await
236 }
237
238 async fn query_raw_with(
239 &self,
240 query: &dyn crate::models::QuerySelector,
241 params: &[&dyn crate::models::ToDbValue],
242 ) -> DatabaseResult<QueryResult> {
243 self.read().query_raw_with(query, params).await
244 }
245}