exercises

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

mod.rs (3537B)


      1 //! Database connection management
      2 //!
      3 //! This module provides a wrapper around sqlx's PostgreSQL connection pool
      4 //! with automatic configuration of the `orders` schema search path.
      5 //!
      6 //! # Schema Search Path
      7 //! All connections are configured to use `search_path TO orders, products, public`,
      8 //! which means queries don't need to prefix table names with `orders.`
      9 //! The products schema is also in the search path for reference data.
     10 //!
     11 //! # Connection Pool
     12 //! The pool is managed by sqlx and handles:
     13 //! - Connection pooling and reuse
     14 //! - Automatic reconnection on connection failures
     15 //! - Connection health checks
     16 //! - Maximum connection limits
     17 
     18 use anyhow::Result;
     19 use sqlx::{
     20     postgres::{PgConnectOptions, PgPoolOptions},
     21     ConnectOptions, PgPool,
     22 };
     23 use std::str::FromStr;
     24 
     25 pub mod repository;
     26 pub mod transaction;
     27 
     28 pub use repository::*;
     29 pub use transaction::*;
     30 
     31 /// Database connection pool wrapper
     32 ///
     33 /// Wraps sqlx's PgPool with custom configuration for the orders service.
     34 #[derive(Clone)]
     35 pub struct Database {
     36     pool: PgPool,
     37 }
     38 
     39 impl Database {
     40     /// Create a new database connection pool
     41     ///
     42     /// This function:
     43     /// 1. Parses the database URL
     44     /// 2. Configures connection options (disables statement logging)
     45     /// 3. Sets application name to "orders-service"
     46     /// 4. Creates a connection pool with the specified max connections
     47     /// 5. Configures each connection to use the `orders` schema by default
     48     ///
     49     /// # Arguments
     50     /// * `database_url` - PostgreSQL connection string (e.g., "postgres://user:pass@host/db")
     51     /// * `max_connections` - Maximum number of connections in the pool
     52     ///
     53     /// # Example
     54     /// ```no_run
     55     /// let db = Database::new("postgres://localhost/mydb", 10).await?;
     56     /// let pool = db.pool();
     57     /// ```
     58     ///
     59     /// # Errors
     60     /// Returns an error if:
     61     /// - Database URL is invalid
     62     /// - Cannot connect to the database
     63     /// - Database authentication fails
     64     pub async fn new(database_url: &str, max_connections: u32) -> Result<Self> {
     65         // Parse the connection string into structured options
     66         let mut connect_opts = PgConnectOptions::from_str(database_url)?
     67             // Disable statement logging to reduce noise in production
     68             .disable_statement_logging();
     69 
     70         // Set application name for PostgreSQL monitoring and logging
     71         connect_opts = connect_opts.application_name("orders-service");
     72 
     73         // Build the connection pool with custom configuration
     74         let pool = PgPoolOptions::new()
     75             .max_connections(max_connections)
     76             // Hook that runs after each connection is established
     77             .after_connect(|conn, _meta| {
     78                 Box::pin(async move {
     79                     // Set the schema search path so queries can use unqualified table names
     80                     // Include products schema for reference data access
     81                     sqlx::query("SET search_path TO orders, products, public")
     82                         .execute(conn)
     83                         .await?;
     84                     Ok(())
     85                 })
     86             })
     87             .connect_with(connect_opts)
     88             .await?;
     89 
     90         Ok(Self { pool })
     91     }
     92 
     93     /// Get a reference to the underlying connection pool
     94     ///
     95     /// Use this to execute queries:
     96     /// ```no_run
     97     /// let pool = db.pool();
     98     /// let orders = sqlx::query!("SELECT * FROM orders").fetch_all(pool).await?;
     99     /// ```
    100     pub fn pool(&self) -> &PgPool {
    101         &self.pool
    102     }
    103 }