Skip to main content

systemprompt_database/services/
provider.rs

1//! Trait abstractions over a database backend.
2//!
3//! [`DatabaseProvider`] is dyn-safe (callers hold `Arc<dyn DatabaseProvider>`)
4//! and uses `#[async_trait]`. [`DatabaseProviderExt`] is generic, never used
5//! through a trait object, and uses native `async fn`.
6//!
7//! Copyright (c) systemprompt.io — Business Source License 1.1.
8//! See <https://systemprompt.io> for licensing details.
9
10use crate::error::DatabaseResult;
11use crate::models::{
12    DatabaseInfo, DatabaseTransaction, DbValue, FromDatabaseRow, JsonRow, QueryResult,
13    QuerySelector, ToDbValue,
14};
15use async_trait::async_trait;
16use std::sync::Arc;
17
18#[async_trait]
19pub trait DatabaseProvider: Send + Sync + std::fmt::Debug {
20    fn get_postgres_pool(&self) -> Option<Arc<sqlx::PgPool>> {
21        None
22    }
23
24    fn is_postgres(&self) -> bool {
25        true
26    }
27
28    async fn execute(
29        &self,
30        query: &dyn QuerySelector,
31        params: &[&dyn ToDbValue],
32    ) -> DatabaseResult<u64>;
33
34    async fn execute_raw(&self, sql: &str) -> DatabaseResult<()>;
35
36    async fn fetch_all(
37        &self,
38        query: &dyn QuerySelector,
39        params: &[&dyn ToDbValue],
40    ) -> DatabaseResult<Vec<JsonRow>>;
41
42    async fn fetch_one(
43        &self,
44        query: &dyn QuerySelector,
45        params: &[&dyn ToDbValue],
46    ) -> DatabaseResult<JsonRow>;
47
48    async fn fetch_optional(
49        &self,
50        query: &dyn QuerySelector,
51        params: &[&dyn ToDbValue],
52    ) -> DatabaseResult<Option<JsonRow>>;
53
54    async fn fetch_scalar_value(
55        &self,
56        query: &dyn QuerySelector,
57        params: &[&dyn ToDbValue],
58    ) -> DatabaseResult<DbValue>;
59
60    async fn begin_transaction(&self) -> DatabaseResult<Box<dyn DatabaseTransaction>>;
61
62    async fn get_database_info(&self) -> DatabaseResult<DatabaseInfo>;
63
64    async fn test_connection(&self) -> DatabaseResult<()>;
65
66    async fn execute_batch(&self, sql: &str) -> DatabaseResult<()>;
67
68    async fn query_raw(&self, query: &dyn QuerySelector) -> DatabaseResult<QueryResult>;
69
70    async fn query_raw_with(
71        &self,
72        query: &dyn QuerySelector,
73        params: &[&dyn ToDbValue],
74    ) -> DatabaseResult<QueryResult>;
75}
76
77#[expect(
78    async_fn_in_trait,
79    reason = "internal extension trait used statically; no dyn dispatch, so no Send-bound concern"
80)]
81pub trait DatabaseProviderExt {
82    async fn fetch_typed_optional<T: FromDatabaseRow>(
83        &self,
84        query: &dyn QuerySelector,
85        params: &[&dyn ToDbValue],
86    ) -> DatabaseResult<Option<T>>;
87
88    async fn fetch_typed_one<T: FromDatabaseRow>(
89        &self,
90        query: &dyn QuerySelector,
91        params: &[&dyn ToDbValue],
92    ) -> DatabaseResult<T>;
93
94    async fn fetch_typed_all<T: FromDatabaseRow>(
95        &self,
96        query: &dyn QuerySelector,
97        params: &[&dyn ToDbValue],
98    ) -> DatabaseResult<Vec<T>>;
99}