Coverage for pgsql_upserter / config.py: 100.00%
35 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 18:15 -0300
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 18:15 -0300
1"""Database connection and configuration utilities."""
3import logging
4import os
5import psycopg2
7from dotenv import load_dotenv
8from psycopg2.extras import RealDictCursor
10from .exceptions import ConnectionError, PermissionError
12load_dotenv()
14logger = logging.getLogger(__name__)
17def create_connection_from_env():
18 """Create PostgreSQL connection from environment variables.
20 Expected environment variables:
21 - PGHOST (default: localhost)
22 - PGPORT (default: 5432)
23 - PGDATABASE (required)
24 - PGUSER (required)
25 - PGPASSWORD (required)
27 Returns:
28 psycopg2.connection: Active database connection
30 Raises:
31 ConnectionError: If connection fails
32 """
33 try:
34 connection_params = {
35 'host': os.getenv('PGHOST', 'localhost'),
36 'port': int(os.getenv('PGPORT', '5432')),
37 'database': os.getenv('PGDATABASE'),
38 'user': os.getenv('PGUSER'),
39 'password': os.getenv('PGPASSWORD'),
40 }
42 # Validate required parameters
43 if not all([connection_params['database'], connection_params['user'], connection_params['password']]):
44 raise ConnectionError(
45 "Missing required environment variables: PGDATABASE, PGUSER, PGPASSWORD")
47 logger.debug(
48 f"Connecting to PostgreSQL: {connection_params['user']}@{connection_params['host']}:{connection_params['port']}/{connection_params['database']}") # noqa
50 connection = psycopg2.connect(**connection_params)
51 connection.autocommit = False # Explicit transaction control
53 return connection
55 except psycopg2.Error as e:
56 raise ConnectionError(f"Failed to connect to PostgreSQL: {e}")
57 except Exception as e:
58 raise ConnectionError(f"Unexpected error during connection: {e}")
61def validate_permissions(connection) -> None:
62 """Validate that user has required permissions for upsert operations.
64 Checks:
65 - CREATE privilege on database (for temp tables)
66 - General connection health
68 Args:
69 connection: Active PostgreSQL connection
71 Raises:
72 PermissionError: If user lacks required permissions
73 """
74 try:
75 with connection.cursor(cursor_factory=RealDictCursor) as cursor:
76 # Test CREATE TEMP TABLE permission
77 cursor.execute("""
78 CREATE TEMP TABLE pgsql_upserter_permission_test (
79 test_col INTEGER
80 );
81 DROP TABLE pgsql_upserter_permission_test;
82 """)
83 connection.commit()
85 logger.debug("Permission validation successful")
87 except psycopg2.Error as e:
88 connection.rollback()
89 raise PermissionError(f"Insufficient permissions for upsert operations: {e}")
92def test_connection():
93 """Test database connection and validate permissions.
95 Returns:
96 psycopg2.connection: Validated connection ready for use
98 Raises:
99 ConnectionError: If connection fails
100 PermissionError: If user lacks required permissions
101 """
102 connection = create_connection_from_env()
103 validate_permissions(connection)
105 logger.debug("Database connection and permissions validated successfully")
106 return connection