Postgres Connection

The database module provides asynchronous database clients with connection pooling and transaction management for various database systems.

Environment Variables

The PostgreSQL client can be configured using either a connection string or individual environment variables: The PostgreSQL client can be configured using the following environment variables:

  • DB_HOST: Database host (default: localhost)

  • DB_PORT: Database port (default: 5432)

  • DB_NAME: Database name (default: postgres)

  • DB_USER: Database user (required)

  • DB_PASSWORD: Database password (required)

  • DB_SSLMODE: SSL mode (default: disable)

Example .env file:

# Database configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydb
DB_USER=myuser
DB_PASSWORD=mypassword
DB_SSLMODE=disable

API Reference

class prs_commons.db.PostgresConnection(*args: Any, **kwargs: Any)[source]

PostgreSQL database connection manager with connection pooling.

This class implements the DatabaseConnection interface and provides connection pooling and transaction management. It uses a singleton pattern to ensure a single connection pool is used per process.

The connection pool is automatically managed and will be created on first use. Connections are automatically returned to the pool when their transaction context is exited.

The PostgresConnection manages the actual database connections and connection pooling. It’s typically not used directly but rather through the higher-level PostgresClient.

__init__(dsn=None, min_size=1, max_size=50, **kwargs)[source]

Initialize the PostgreSQL client.

Note: This will only initialize the instance once due to the singleton pattern. Subsequent calls with different parameters will be ignored.

__init__(dsn: str | None = None, min_size: int = 1, max_size: int = 50, **kwargs: Any) None[source]

Initialize the PostgreSQL client.

Note: This will only initialize the instance once due to the singleton pattern. Subsequent calls with different parameters will be ignored.

async connect() None[source]

Initialize the database connection pool.

Creates a connection pool with the configured parameters. This method is called automatically when the first connection is requested.

The connection pool parameters are: - min_size: Minimum number of connections to keep open - max_size: Maximum number of connections to allow - Other parameters passed during client initialization

Note

This method is idempotent - calling it multiple times will only create the pool once.

async disconnect() None[source]

Close all connections in the connection pool.

This method should be called when the database client is no longer needed to ensure proper cleanup of resources. After calling this method, the client can be reused by calling connect() again.

Note

It’s good practice to call this when your application shuts down.

get_connection() AsyncIterator[Connection][source]

Get a managed database connection with transaction support.

This context manager provides a connection from the pool with automatic transaction management. The connection is automatically returned to the pool when the context exits.

The following operations are performed automatically:

  1. Starts a new transaction when entering the context

  2. Commits the transaction if the block completes successfully

  3. Rolls back the transaction if an exception occurs

  4. Returns the connection to the pool when done

Example

async with db.get_connection() as conn:
    # Execute queries within a transaction
    result = await conn.fetch("SELECT * FROM users")
    # Transaction will be committed if no exceptions occur
Yields:

asyncpg.Connection – A database connection from the pool.

Note

The connection and its transaction are managed automatically. Do not manually commit or rollback the transaction within the context.

Note

Nested transactions are supported using savepoints. For example:

async with db.get_connection() as conn:
    # Outer transaction starts automatically
    await conn.execute("INSERT INTO users (name) VALUES ('user1')")


    try:
        # Start a nested transaction (savepoint)
        async with conn.transaction():
            await conn.execute("INSERT INTO accounts (user_id, balance)
            VALUES (1, 100)")
            # This savepoint can be rolled back independently
            raise Exception("Something went wrong")


    except Exception as e:
        # Only the inner transaction is rolled back
        print(f"Caught error: {e}")
        # The outer transaction continues and will be committed
        await conn.execute("UPDATE users
            SET status = 'active' WHERE name = 'user1'")

    # The outer transaction is committed here if no exceptions

Important

If an exception occurs in the outer transaction after an inner transaction has committed, the entire transaction (including the committed savepoint) will be rolled back. This ensures transaction atomicity - either all changes complete successfully, or none of them do.

If you need the inner transaction to persist regardless of the outer transaction’s outcome, use separate database connections/transactions instead of nested transactions.

async __aenter__() PostgresConnection[source]

Async context manager entry.

async __aexit__(exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) None[source]

Async context manager exit.

Error Handling

The PostgresConnection raises the following exceptions:

  • ValueError: If required environment variables are missing

  • asyncpg.PostgresError: For database-related errors

  • RuntimeError: For connection pool errors

  • Exception: For other unexpected errors

See Also