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