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, FromDatabaseRow, JsonRow, QueryResult, QuerySelector,
13    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) -> Arc<sqlx::PgPool>;
21
22    async fn execute(
23        &self,
24        query: &dyn QuerySelector,
25        params: &[&dyn ToDbValue],
26    ) -> DatabaseResult<u64>;
27
28    async fn execute_raw(&self, sql: &str) -> DatabaseResult<()>;
29
30    async fn fetch_all(
31        &self,
32        query: &dyn QuerySelector,
33        params: &[&dyn ToDbValue],
34    ) -> DatabaseResult<Vec<JsonRow>>;
35
36    async fn fetch_one(
37        &self,
38        query: &dyn QuerySelector,
39        params: &[&dyn ToDbValue],
40    ) -> DatabaseResult<JsonRow>;
41
42    async fn fetch_optional(
43        &self,
44        query: &dyn QuerySelector,
45        params: &[&dyn ToDbValue],
46    ) -> DatabaseResult<Option<JsonRow>>;
47
48
49    async fn begin_transaction(&self) -> DatabaseResult<Box<dyn DatabaseTransaction>>;
50
51    async fn get_database_info(&self) -> DatabaseResult<DatabaseInfo>;
52
53    async fn test_connection(&self) -> DatabaseResult<()>;
54
55    async fn execute_batch(&self, sql: &str) -> DatabaseResult<()>;
56
57    async fn query_raw(&self, query: &dyn QuerySelector) -> DatabaseResult<QueryResult>;
58
59    async fn query_raw_with(
60        &self,
61        query: &dyn QuerySelector,
62        params: &[&dyn ToDbValue],
63    ) -> DatabaseResult<QueryResult>;
64}
65
66#[expect(
67    async_fn_in_trait,
68    reason = "internal extension trait used statically; no dyn dispatch, so no Send-bound concern"
69)]
70pub trait DatabaseProviderExt {
71    async fn fetch_typed_optional<T: FromDatabaseRow>(
72        &self,
73        query: &dyn QuerySelector,
74        params: &[&dyn ToDbValue],
75    ) -> DatabaseResult<Option<T>>;
76
77    async fn fetch_typed_one<T: FromDatabaseRow>(
78        &self,
79        query: &dyn QuerySelector,
80        params: &[&dyn ToDbValue],
81    ) -> DatabaseResult<T>;
82
83    async fn fetch_typed_all<T: FromDatabaseRow>(
84        &self,
85        query: &dyn QuerySelector,
86        params: &[&dyn ToDbValue],
87    ) -> DatabaseResult<Vec<T>>;
88}