Skip to main content

nextsql_tokio_postgres_adapter/
lib.rs

1//! tokio-postgres / deadpool-postgres adapter for NextSQL runtime.
2//!
3//! Provides [`PooledPgClient`] which wraps a `deadpool_postgres::Object`
4//! and implements the NextSQL [`Client`] trait.
5//!
6//! Also re-exports the core tokio-postgres types from the runtime crate
7//! for convenience.
8
9pub use nextsql_backend_rust_runtime::tokio_postgres_impl::{
10    convert_params, to_owned_param, OwnedParam, PgClient, PgRow, PgTransaction,
11};
12pub use nextsql_backend_rust_runtime::{Client, Row, ToSqlParam, Transaction};
13
14/// Convert a slice of [`OwnedParam`] to a vec of trait-object references
15/// suitable for passing to `tokio_postgres` query methods.
16pub fn owned_params_to_refs(owned: &[OwnedParam]) -> Vec<&(dyn tokio_postgres::types::ToSql + Sync)> {
17    owned
18        .iter()
19        .map(|p| p as &(dyn tokio_postgres::types::ToSql + Sync))
20        .collect()
21}
22
23/// A wrapper around `deadpool_postgres::Object` implementing the NextSQL [`Client`] trait.
24///
25/// This allows using a pooled connection from deadpool-postgres directly
26/// with NextSQL generated query/mutation functions.
27pub struct PooledPgClient {
28    conn: deadpool_postgres::Object,
29}
30
31impl PooledPgClient {
32    pub fn new(conn: deadpool_postgres::Object) -> Self {
33        Self { conn }
34    }
35
36    /// Get a reference to the underlying `tokio_postgres::Client`.
37    pub fn inner(&self) -> &tokio_postgres::Client {
38        use std::ops::Deref;
39        self.conn.deref()
40    }
41
42    fn inner_mut(&mut self) -> &mut tokio_postgres::Client {
43        use std::ops::DerefMut;
44        self.conn.deref_mut()
45    }
46}
47
48impl Client for PooledPgClient {
49    type Error = tokio_postgres::Error;
50    type Row = PgRow;
51    type Transaction<'a> = PgTransaction<'a>;
52
53    fn query(
54        &self,
55        sql: &str,
56        params: &[&dyn ToSqlParam],
57    ) -> impl std::future::Future<Output = Result<Vec<Self::Row>, Self::Error>> + Send {
58        let owned_params = convert_params(params);
59        let sql = sql.to_owned();
60        let client = self.inner();
61        async move {
62            let param_refs = owned_params_to_refs(&owned_params);
63            let rows = client.query(&sql, &param_refs).await?;
64            Ok(rows.into_iter().map(PgRow).collect())
65        }
66    }
67
68    fn execute(
69        &self,
70        sql: &str,
71        params: &[&dyn ToSqlParam],
72    ) -> impl std::future::Future<Output = Result<u64, Self::Error>> + Send {
73        let owned_params = convert_params(params);
74        let sql = sql.to_owned();
75        let client = self.inner();
76        async move {
77            let param_refs = owned_params_to_refs(&owned_params);
78            client.execute(&sql, &param_refs).await
79        }
80    }
81
82    fn transaction(
83        &mut self,
84    ) -> impl std::future::Future<Output = Result<Self::Transaction<'_>, Self::Error>> + Send {
85        async move {
86            let tx = self.inner_mut().transaction().await?;
87            Ok(PgTransaction::new(tx))
88        }
89    }
90}