package database import ( "context" "database/sql" "fmt" "time" _ "github.com/lib/pq" "github.com/kms/api-key-service/internal/repository" ) // PostgresProvider implements the DatabaseProvider interface type PostgresProvider struct { db *sql.DB dsn string } // NewPostgresProvider creates a new PostgreSQL database provider func NewPostgresProvider(dsn string, maxOpenConns, maxIdleConns int, maxLifetime string) (repository.DatabaseProvider, error) { db, err := sql.Open("postgres", dsn) if err != nil { return nil, fmt.Errorf("failed to open database connection: %w", err) } // Set connection pool settings db.SetMaxOpenConns(maxOpenConns) db.SetMaxIdleConns(maxIdleConns) // Parse and set max lifetime if provided if maxLifetime != "" { if lifetime, err := time.ParseDuration(maxLifetime); err == nil { db.SetConnMaxLifetime(lifetime) } } // Test the connection if err := db.Ping(); err != nil { db.Close() return nil, fmt.Errorf("failed to ping database: %w", err) } return &PostgresProvider{db: db, dsn: dsn}, nil } // GetDB returns the underlying database connection func (p *PostgresProvider) GetDB() interface{} { return p.db } // Ping checks the database connection func (p *PostgresProvider) Ping(ctx context.Context) error { if p.db == nil { return fmt.Errorf("database connection is nil") } // Check if database is closed if err := p.db.PingContext(ctx); err != nil { return fmt.Errorf("database ping failed: %w", err) } return nil } // Close closes all database connections func (p *PostgresProvider) Close() error { return p.db.Close() } // BeginTx starts a database transaction func (p *PostgresProvider) BeginTx(ctx context.Context) (repository.TransactionProvider, error) { tx, err := p.db.BeginTx(ctx, nil) if err != nil { return nil, fmt.Errorf("failed to begin transaction: %w", err) } return &PostgresTransaction{tx: tx}, nil } // PostgresTransaction implements the TransactionProvider interface type PostgresTransaction struct { tx *sql.Tx } // Commit commits the transaction func (t *PostgresTransaction) Commit() error { return t.tx.Commit() } // Rollback rolls back the transaction func (t *PostgresTransaction) Rollback() error { return t.tx.Rollback() } // GetTx returns the underlying transaction func (t *PostgresTransaction) GetTx() interface{} { return t.tx }