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 `products` schema search path.
      5 //!
      6 //! # Schema Search Path
      7 //! All connections are configured to use `search_path TO products, public`,
      8 //! which means queries don't need to prefix table names with `products.`
      9 //!
     10 //! # Connection Pool
     11 //! The pool is managed by sqlx and handles:
     12 //! - Connection pooling and reuse
     13 //! - Automatic reconnection on connection failures
     14 //! - Connection health checks
     15 //! - Maximum connection limits
     16 
     17 use anyhow::Result;
     18 use sqlx::{
     19     postgres::{PgConnectOptions, PgPoolOptions},
     20     ConnectOptions, PgPool,
     21 };
     22 use std::str::FromStr;
     23 
     24 pub mod ratings;
     25 pub mod repository;
     26 
     27 // Re-export all repository functions for easy access
     28 pub use ratings::*;
     29 pub use repository::*;
     30 
     31 /// Database connection pool wrapper
     32 ///
     33 /// Wraps sqlx's PgPool with custom configuration for the products 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 "products-service"
     46     /// 4. Creates a connection pool with the specified max connections
     47     /// 5. Configures each connection to use the `products` 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("products-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                     // Example: SELECT * FROM products instead of SELECT * FROM products.products
     81                     sqlx::query("SET search_path TO 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 products = sqlx::query!("SELECT * FROM products").fetch_all(pool).await?;
     99     /// ```
    100     pub fn pool(&self) -> &PgPool {
    101         &self.pool
    102     }
    103 }