sql_middleware/postgres/config.rs
1use crate::middleware::{ConfigAndPool, DatabaseType, MiddlewarePool, SqlMiddlewareDbError};
2use deadpool_postgres::Config as PgConfig;
3use tokio_postgres::NoTls;
4
5impl ConfigAndPool {
6 /// Asynchronous initializer for `ConfigAndPool` with Postgres
7 ///
8 /// # Errors
9 /// Returns `SqlMiddlewareDbError::ConfigError` if required config fields are missing or `SqlMiddlewareDbError::ConnectionError` if pool creation fails.
10 #[allow(clippy::unused_async)]
11 pub async fn new_postgres(pg_config: PgConfig) -> Result<Self, SqlMiddlewareDbError> {
12 Self::new_postgres_with_translation(pg_config, false).await
13 }
14
15 /// Asynchronous initializer for `ConfigAndPool` with Postgres and optional translation default.
16 ///
17 /// # Errors
18 /// Returns `SqlMiddlewareDbError::ConfigError` if required config fields are missing or `SqlMiddlewareDbError::ConnectionError` if pool creation fails.
19 ///
20 /// Warning: translation skips placeholders inside quoted strings, comments, and dollar-quoted
21 /// blocks via a lightweight state machine; it may miss edge cases in complex SQL (e.g.,
22 /// PL/pgSQL bodies). Prefer backend-specific SQL instead of relying on translation:
23 /// ```rust
24 /// # use sql_middleware::prelude::*;
25 /// let query = match &conn {
26 /// MiddlewarePoolConnection::Postgres { .. } => r#"$function$
27 /// BEGIN
28 /// RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
29 /// END;
30 /// $function$"#,
31 /// MiddlewarePoolConnection::Sqlite { .. } | MiddlewarePoolConnection::Turso { .. } => {
32 /// include_str!("../sql/functions/sqlite/03_sp_get_scores.sql")
33 /// }
34 /// };
35 /// ```
36 #[allow(clippy::unused_async)]
37 pub async fn new_postgres_with_translation(
38 pg_config: PgConfig,
39 translate_placeholders: bool,
40 ) -> Result<Self, SqlMiddlewareDbError> {
41 // Validate all required config fields are present
42 if pg_config.dbname.is_none() {
43 return Err(SqlMiddlewareDbError::ConfigError(
44 "dbname is required".to_string(),
45 ));
46 }
47
48 if pg_config.host.is_none() {
49 return Err(SqlMiddlewareDbError::ConfigError(
50 "host is required".to_string(),
51 ));
52 }
53 if pg_config.port.is_none() {
54 return Err(SqlMiddlewareDbError::ConfigError(
55 "port is required".to_string(),
56 ));
57 }
58 if pg_config.user.is_none() {
59 return Err(SqlMiddlewareDbError::ConfigError(
60 "user is required".to_string(),
61 ));
62 }
63 if pg_config.password.is_none() {
64 return Err(SqlMiddlewareDbError::ConfigError(
65 "password is required".to_string(),
66 ));
67 }
68
69 // Attempt to create connection pool
70 let pg_pool = pg_config
71 .create_pool(Some(deadpool_postgres::Runtime::Tokio1), NoTls)
72 .map_err(|e| {
73 SqlMiddlewareDbError::ConnectionError(format!(
74 "Failed to create Postgres pool: {e}"
75 ))
76 })?;
77
78 Ok(ConfigAndPool {
79 pool: MiddlewarePool::Postgres(pg_pool),
80 db_type: DatabaseType::Postgres,
81 translate_placeholders,
82 })
83 }
84}