diff --git a/crates/db/src/lib.rs b/crates/db/src/lib.rs index bd7de6d..27ceab9 100644 --- a/crates/db/src/lib.rs +++ b/crates/db/src/lib.rs @@ -1 +1,40 @@ //! Database access. All SQL lives in this crate. + +use sqlx::postgres::{PgPool, PgPoolOptions}; + +/// A handle to the organization's PostgreSQL database. +#[derive(Clone)] +pub struct Db { + pool: PgPool, +} + +impl Db { + /// Connect to the database at `database_url`, opening a connection pool. + pub async fn connect(database_url: &str) -> Result { + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(database_url) + .await?; + + Ok(Self { pool }) + } + + /// Build a handle from an existing pool (used in tests). + pub fn from_pool(pool: PgPool) -> Self { + Self { pool } + } + + /// Borrow the underlying pool for repository modules. + pub fn pool(&self) -> &PgPool { + &self.pool + } + + /// Readiness check: run a trivial query to confirm the database answers. + pub async fn ping(&self) -> Result<(), sqlx::Error> { + sqlx::query_scalar::<_, i32>("SELECT 1") + .fetch_one(&self.pool) + .await?; + + Ok(()) + } +} diff --git a/crates/db/tests/ping.rs b/crates/db/tests/ping.rs new file mode 100644 index 0000000..6565b39 --- /dev/null +++ b/crates/db/tests/ping.rs @@ -0,0 +1,10 @@ +use db::Db; +use sqlx::PgPool; + +#[sqlx::test] +async fn ping_succeeds(pool: PgPool) { + let db = Db::from_pool(pool); + db.ping() + .await + .expect("ping should succeed against a live database"); +}