little-durable-objects 0.1.2

Standalone regional durable-object control plane, host, and durability runtime
Documentation
use std::{str::FromStr, sync::Arc};

use anyhow::{Context, Result};
use native_tls::TlsConnector;
use postgres_native_tls::MakeTlsConnector;
use tokio_postgres::{Client, Config, NoTls, config::SslMode};
use tracing::error;

mod embedded {
    use refinery::embed_migrations;

    embed_migrations!("migrations");
}

#[derive(Clone)]
pub(crate) struct PostgresDatabase {
    client: Arc<Client>,
}

impl PostgresDatabase {
    pub(crate) async fn connect(url: &str) -> Result<Self> {
        let config = Config::from_str(url).context("parse PostgreSQL connection URL")?;
        let mut client = match config.get_ssl_mode() {
            SslMode::Disable => {
                let (client, connection) = config
                    .connect(NoTls)
                    .await
                    .context("connect to PostgreSQL without TLS")?;
                tokio::spawn(async move {
                    if let Err(error) = connection.await {
                        error!(error = %error, "PostgreSQL connection stopped");
                    }
                });
                client
            }
            _ => {
                let connector = TlsConnector::builder()
                    .build()
                    .context("build PostgreSQL TLS connector")?;
                let (client, connection) = config
                    .connect(MakeTlsConnector::new(connector))
                    .await
                    .context("connect to PostgreSQL with TLS")?;
                tokio::spawn(async move {
                    if let Err(error) = connection.await {
                        error!(error = %error, "PostgreSQL TLS connection stopped");
                    }
                });
                client
            }
        };
        embedded::migrations::runner()
            .run_async(&mut client)
            .await
            .context("run durable-object PostgreSQL migrations")?;
        Ok(Self {
            client: Arc::new(client),
        })
    }

    pub(crate) fn client(&self) -> &Client {
        &self.client
    }
}