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