Skip to main content

agent_sdk_store_postgres/
client.rs

1use std::sync::Arc;
2
3use agent_sdk_core::AgentError;
4use serde_json::Value;
5
6#[derive(Clone, Debug, Eq, PartialEq)]
7/// SQL request sent through the host-owned Postgres transport.
8pub struct PostgresSqlRequest {
9    /// SQL statement or prepared statement name.
10    pub statement: String,
11    /// Bound parameters as JSON for deterministic scripted tests.
12    pub params: Vec<Value>,
13}
14
15#[derive(Clone, Debug, Default, Eq, PartialEq)]
16/// SQL response returned by the host-owned Postgres transport.
17pub struct PostgresSqlResponse {
18    /// Rows represented as JSON objects.
19    pub rows: Vec<Value>,
20    /// Number of affected rows.
21    pub affected: u64,
22}
23
24impl PostgresSqlResponse {
25    /// Creates a response with rows.
26    pub fn rows(rows: impl IntoIterator<Item = Value>) -> Self {
27        Self {
28            rows: rows.into_iter().collect(),
29            affected: 0,
30        }
31    }
32
33    /// Creates an affected-row response.
34    pub fn affected(affected: u64) -> Self {
35        Self {
36            rows: Vec::new(),
37            affected,
38        }
39    }
40}
41
42/// Host-owned SQL transport for Postgres-style stores.
43pub trait PostgresSqlTransport: Send + Sync {
44    /// Executes a SQL request. Implementations may talk to a database; tests can script responses.
45    fn execute(&self, request: PostgresSqlRequest) -> Result<PostgresSqlResponse, AgentError>;
46}
47
48#[derive(Clone, Debug)]
49/// Postgres store configuration.
50pub struct PostgresStoreConfig {
51    /// SQL schema name used in generated statements.
52    pub schema: String,
53    /// Store scope used to partition rows.
54    pub store_scope: String,
55}
56
57impl PostgresStoreConfig {
58    /// Creates a Postgres store config.
59    pub fn new(schema: impl Into<String>, store_scope: impl Into<String>) -> Self {
60        Self {
61            schema: schema.into(),
62            store_scope: store_scope.into(),
63        }
64    }
65}
66
67#[derive(Clone)]
68/// Shared Postgres client over a host-owned SQL transport.
69pub struct PostgresStoreClient {
70    pub(crate) config: PostgresStoreConfig,
71    transport: Arc<dyn PostgresSqlTransport>,
72}
73
74impl PostgresStoreClient {
75    /// Creates a client over a scripted or host-provided transport.
76    pub fn new(config: PostgresStoreConfig, transport: Arc<dyn PostgresSqlTransport>) -> Self {
77        Self { config, transport }
78    }
79
80    pub(crate) fn execute(
81        &self,
82        statement: impl Into<String>,
83        params: Vec<Value>,
84    ) -> Result<PostgresSqlResponse, AgentError> {
85        self.transport.execute(PostgresSqlRequest {
86            statement: statement.into(),
87            params,
88        })
89    }
90
91    pub(crate) fn table(&self, table: &str) -> String {
92        format!("{}.{}", self.config.schema, table)
93    }
94
95    pub(crate) fn scope(&self) -> Value {
96        Value::String(self.config.store_scope.clone())
97    }
98}