1pub use async_lazy;
2use async_lazy::Lazy;
3pub use ctor::ctor;
4pub use paste::paste;
5pub use tokio_postgres::{self, types::ToSql, Client, Error, NoTls, Row, Statement, ToStatement};
6use tokio_postgres::{error::SqlState, ToStatementType};
7use tracing::error;
8pub use trt::TRT;
9pub use xxpg_proc::{Q, Q01, Q1};
10
11pub struct LazyStatement {
12 pub statement: async_lazy::Lazy<tokio_postgres::Statement>,
13 pub sql: &'static str,
14}
15
16impl ToStatement for LazyStatement {
17 fn __convert(&self) -> ToStatementType<'_> {
18 ToStatementType::Statement(self.statement.get().unwrap())
19 }
20}
21
22#[macro_export]
23macro_rules! sql {
24 ($($var:ident : $sql:expr),+ ) => {
25 $(
26 $crate::paste!{
27 pub static [<__ $var:upper >]: $crate::LazyStatement =
28 $crate::LazyStatement{
29 statement:$crate::async_lazy::Lazy::const_new(|| Box::pin(async move { $crate::PG.force().await.prepare($sql).await.unwrap() })),
30 sql:$sql
31 };
32 pub static [<$var:upper>] : &$crate::LazyStatement = &[<__ $var:upper>];
33 }
34 )+
35
36 mod private {
37 #[$crate::ctor]
38 fn pg_statement_init() {
39 $crate::TRT.block_on(async move {
40 $crate::paste!{
41 $(super::[<$var:upper>].statement.force().await;)+
42 }
43 });
44 }
45 }
46 };
47}
48
49pub async fn conn() -> Client {
54 let pg_uri = std::env::var("PG_URI").unwrap();
55 let (client, connection) = tokio_postgres::connect(&format!("postgres://{}", pg_uri), NoTls)
56 .await
57 .unwrap();
58
59 tokio::spawn(async move {
60 if let Err(e) = connection.await {
61 let err_code = e.code();
62 let code = match err_code {
63 Some(code) => code.code(),
64 None => "",
65 };
66 tracing::error!("❌ POSTGRES ERROR CODE {code} : {e}\n SEE https://www.postgresql.org/docs/current/errcodes-appendix.html\n");
67
68 if err_code == Some(&SqlState::ADMIN_SHUTDOWN) || e.is_closed() {
69 std::process::exit(1)
70 }
71 }
72 });
73
74 client
75}
76
77pub static PG: Lazy<Client> = Lazy::const_new(|| Box::pin(async move { conn().await }));
78
79#[ctor]
80fn init() {
81 TRT.block_on(async move {
82 use std::future::IntoFuture;
83 PG.into_future().await;
84 });
85}
86
87macro_rules! q {
88 ($name:ident,$func:ident,$rt:ty) => {
89 #[allow(non_snake_case)]
90 pub async fn $name<T>(statement: &T, params: &[&(dyn ToSql + Sync)]) -> Result<$rt, Error>
91 where
92 T: ?Sized + ToStatement,
93 {
94 match PG.get().unwrap().$func(statement, params).await {
95 Ok(r) => Ok(r),
96 Err(err) => {
97 if err.is_closed() {
98 error!("{}", err);
99 std::process::exit(1);
100 }
101 Err(err)
102 }
103 }
104 }
105 };
106}
107
108q!(Q, query, Vec<Row>);
109q!(Q1, query_one, Row);
110q!(Q01, query_opt, Option<Row>);