endpoint_libs/libs/
database.rs1use deadpool_postgres::*;
2use eyre::*;
3use postgres_from_row::FromRow;
4use secrecy::SecretString;
5use serde::de::DeserializeOwned;
6use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8use std::path::Path;
9use std::process::Command;
10use std::time::Duration;
11pub use tokio_postgres::types::ToSql;
12pub use tokio_postgres::Row;
13mod data_thread;
14mod pooled;
15pub use data_thread::*;
16pub use pooled::*;
17
18use super::datatable::RDataTable;
19
20#[derive(Clone, Debug, Default, Deserialize)]
21pub struct DatabaseConfig {
22 pub user: Option<String>,
24 pub password: Option<SecretString>,
26 pub dbname: Option<String>,
28 pub options: Option<String>,
30 pub application_name: Option<String>,
32 pub ssl_mode: Option<SslMode>,
34 pub host: Option<String>,
43 pub hosts: Option<Vec<String>>,
45 pub port: Option<u16>,
54 pub ports: Option<Vec<u16>>,
56 pub connect_timeout: Option<Duration>,
58 pub keepalives: Option<bool>,
60 pub keepalives_idle: Option<Duration>,
62 pub target_session_attrs: Option<TargetSessionAttrs>,
64 pub channel_binding: Option<ChannelBinding>,
66
67 pub manager: Option<ManagerConfig>,
71
72 pub pool: Option<PoolConfig>,
74}
75
76pub trait DatabaseRequest: Send {
77 type ResponseRow: Send + Sync + Clone + Serialize + DeserializeOwned + FromRow;
78 fn statement(&self) -> &str;
79 fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
80}
81pub type DatabaseRequestBoxed = Box<dyn DatabaseRequest<ResponseRow = Row>>;
82#[derive(Clone)]
83pub enum DbClient {
84 Pooled(PooledDbClient),
85 Threaded(ThreadedDbClient),
86}
87impl From<PooledDbClient> for DbClient {
88 fn from(client: PooledDbClient) -> Self {
89 Self::Pooled(client)
90 }
91}
92impl From<ThreadedDbClient> for DbClient {
93 fn from(value: ThreadedDbClient) -> Self {
94 Self::Threaded(value)
95 }
96}
97impl DbClient {
98 pub async fn execute<T>(&self, req: T) -> Result<RDataTable<T::ResponseRow>>
99 where
100 T: DatabaseRequest + Sync + Send + Debug + 'static,
101 T::ResponseRow: FromRow + Sync + Send + Clone + Debug + Sized + 'static,
102 {
103 match self {
104 DbClient::Pooled(client) => client.execute(req).await,
105 DbClient::Threaded(client) => client.execute(req).await,
106 }
107 }
108}
109
110pub fn database_test_config() -> DatabaseConfig {
111 DatabaseConfig {
112 user: Some("postgres".to_string()),
113 password: Some("123456".to_string().into()),
114 dbname: Some("red_alert".to_string()),
115 host: Some("localhost".to_string()),
116 ..Default::default()
117 }
118}
119
120pub fn drop_and_recreate_database() -> Result<()> {
121 let script = Path::new("scripts/drop_and_recreate_database.sh");
122 Command::new("bash")
123 .arg(script)
124 .arg("etc/config.json")
125 .status()?;
126 Ok(())
127}