Skip to main content

elefant_client/
lib.rs

1#![allow(dead_code)]
2
3pub mod batch;
4mod error;
5#[cfg(feature = "pg_interval")]
6pub mod pg_interval;
7pub mod pool;
8mod postgres_client;
9pub mod profiler;
10mod protocol;
11#[cfg(test)]
12mod test_helpers;
13#[cfg(feature = "rustls")]
14pub mod tls;
15#[cfg(feature = "tokio")]
16pub mod tokio_connection;
17mod types;
18
19pub use batch::{CollectBatch, FlattenTuple, TupleAppend};
20pub use error::ElefantClientError;
21#[cfg(feature = "pg_interval")]
22pub use pg_interval::Interval;
23pub use pool::{ConnectionFactory, PoolableClient, PostgresPool};
24pub use postgres_client::*;
25pub use protocol::FieldDescription;
26pub use types::*;
27
28#[cfg(feature = "derive")]
29pub use elefant_client_macros::PostgresEnum;
30
31#[derive(Clone)]
32pub struct PostgresConnectionSettings {
33    pub host: String,
34    pub port: u16,
35    pub user: String,
36    pub password: String,
37    pub database: String,
38    pub options: Option<String>,
39    pub replication: Option<String>,
40    enum_type_names: Vec<&'static str>,
41    #[cfg(feature = "rustls")]
42    pub tls: TlsSettings,
43}
44
45impl PostgresConnectionSettings {
46    pub fn new(host: impl Into<String>) -> Self {
47        Self {
48            host: host.into(),
49            ..Self::default()
50        }
51    }
52
53    pub fn port(mut self, port: u16) -> Self {
54        self.port = port;
55        self
56    }
57
58    pub fn user(mut self, user: impl Into<String>) -> Self {
59        self.user = user.into();
60        self
61    }
62
63    pub fn password(mut self, password: impl Into<String>) -> Self {
64        self.password = password.into();
65        self
66    }
67
68    pub fn database(mut self, database: impl Into<String>) -> Self {
69        self.database = database.into();
70        self
71    }
72
73    pub fn options(mut self, options: impl Into<String>) -> Self {
74        self.options = Some(options.into());
75        self
76    }
77
78    pub fn replication(mut self, replication: impl Into<String>) -> Self {
79        self.replication = Some(replication.into());
80        self
81    }
82
83    /// Register a PostgreSQL enum type for OID resolution at pool creation time.
84    pub fn register_enum<T: PostgresEnum>(mut self) -> Self {
85        if !self.enum_type_names.contains(&T::PG_TYPE_NAME) {
86            self.enum_type_names.push(T::PG_TYPE_NAME);
87        }
88
89        self
90    }
91
92    /// Returns the registered enum type names.
93    pub fn enum_type_names(&self) -> &[&'static str] {
94        &self.enum_type_names
95    }
96
97    #[cfg(feature = "rustls")]
98    pub fn tls(mut self, tls: TlsSettings) -> Self {
99        self.tls = tls;
100        self
101    }
102}
103
104impl Default for PostgresConnectionSettings {
105    fn default() -> Self {
106        Self {
107            host: "localhost".to_string(),
108            port: 5432,
109            user: "postgres".to_string(),
110            password: String::new(),
111            database: "postgres".to_string(),
112            options: None,
113            replication: None,
114            enum_type_names: Vec::new(),
115            #[cfg(feature = "rustls")]
116            tls: TlsSettings::disable(),
117        }
118    }
119}
120
121#[cfg(feature = "rustls")]
122#[derive(Clone)]
123pub enum TlsSettings {
124    /// TLS is disabled — connect without encryption.
125    Disabled,
126    /// Try TLS, but fall back to plaintext if the server declines.
127    Prefer(std::sync::Arc<rustls::ClientConfig>),
128    /// Require TLS — fail if the server does not support it.
129    Require(std::sync::Arc<rustls::ClientConfig>),
130}
131
132#[cfg(feature = "rustls")]
133impl std::fmt::Debug for TlsSettings {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        match self {
136            Self::Disabled => write!(f, "Disabled"),
137            Self::Prefer(_) => write!(f, "Prefer(...)"),
138            Self::Require(_) => write!(f, "Require(...)"),
139        }
140    }
141}
142
143#[cfg(feature = "rustls")]
144impl TlsSettings {
145    pub fn disable() -> Self {
146        Self::Disabled
147    }
148
149    pub fn prefer(config: std::sync::Arc<rustls::ClientConfig>) -> Self {
150        Self::Prefer(config)
151    }
152
153    pub fn require(config: std::sync::Arc<rustls::ClientConfig>) -> Self {
154        Self::Require(config)
155    }
156
157    pub fn config(&self) -> Option<&std::sync::Arc<rustls::ClientConfig>> {
158        match self {
159            Self::Disabled => None,
160            Self::Prefer(c) | Self::Require(c) => Some(c),
161        }
162    }
163
164    pub fn is_required(&self) -> bool {
165        matches!(self, Self::Require(_))
166    }
167}