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