feat(database): add PostgreSQL support with native pgx pool
Add PostgreSQL support to database package alongside existing MySQL support. Both databases share common infrastructure (pool management, metrics, transactions) while using database-specific connectors. database/ changes: - Add PostgresConfig struct and PostgreSQL connector using pgx/stdlib - Change MySQL config from DBConfig to *MySQLConfig (pointer) - Add Config.Validate() to prevent multiple database configs - Add PostgreSQL connector with secure config building (no password in DSN) - Add field validation and secure defaults (SSLMode="prefer") - Support legacy flat PostgreSQL config format for backward compatibility - Add tests for PostgreSQL configs and validation New database/pgdb/ package: - Native pgx connection pool support (*pgxpool.Pool) - OpenPool() and OpenPoolWithConfigFile() APIs - CreatePoolConfig() for secure config conversion - PoolOptions for fine-grained pool control - Full test coverage and documentation Security: - Passwords never exposed in DSN strings - Set passwords separately in pgx config objects - Validate all configuration before connection Architecture: - Shared code in database/ for both MySQL and PostgreSQL (sql.DB) - database/pgdb/ for PostgreSQL-specific native pool support
This commit is contained in:
@@ -56,9 +56,9 @@ func TestMonitorConfigOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigStructures(t *testing.T) {
|
||||
// Test that configuration structures can be created and populated
|
||||
// Test that MySQL configuration structures can be created and populated
|
||||
config := Config{
|
||||
MySQL: DBConfig{
|
||||
MySQL: &MySQLConfig{
|
||||
DSN: "user:pass@tcp(localhost:3306)/dbname",
|
||||
User: "testuser",
|
||||
Pass: "testpass",
|
||||
@@ -79,3 +79,118 @@ func TestConfigStructures(t *testing.T) {
|
||||
t.Errorf("Expected DBName='testdb', got '%s'", config.MySQL.DBName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostgresConfigStructures(t *testing.T) {
|
||||
// Test that PostgreSQL configuration structures can be created and populated
|
||||
config := Config{
|
||||
Postgres: &PostgresConfig{
|
||||
Host: "localhost",
|
||||
Port: 5432,
|
||||
User: "testuser",
|
||||
Pass: "testpass",
|
||||
Name: "testdb",
|
||||
SSLMode: "require",
|
||||
},
|
||||
}
|
||||
|
||||
if config.Postgres.Host != "localhost" {
|
||||
t.Errorf("Expected Host='localhost', got '%s'", config.Postgres.Host)
|
||||
}
|
||||
if config.Postgres.Port != 5432 {
|
||||
t.Errorf("Expected Port=5432, got %d", config.Postgres.Port)
|
||||
}
|
||||
if config.Postgres.User != "testuser" {
|
||||
t.Errorf("Expected User='testuser', got '%s'", config.Postgres.User)
|
||||
}
|
||||
if config.Postgres.Pass != "testpass" {
|
||||
t.Errorf("Expected Pass='testpass', got '%s'", config.Postgres.Pass)
|
||||
}
|
||||
if config.Postgres.Name != "testdb" {
|
||||
t.Errorf("Expected Name='testdb', got '%s'", config.Postgres.Name)
|
||||
}
|
||||
if config.Postgres.SSLMode != "require" {
|
||||
t.Errorf("Expected SSLMode='require', got '%s'", config.Postgres.SSLMode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegacyPostgresConfig(t *testing.T) {
|
||||
// Test that legacy flat PostgreSQL format can be created
|
||||
config := Config{
|
||||
User: "testuser",
|
||||
Pass: "testpass",
|
||||
Host: "localhost",
|
||||
Port: 5432,
|
||||
Name: "testdb",
|
||||
SSLMode: "require",
|
||||
}
|
||||
|
||||
if config.User != "testuser" {
|
||||
t.Errorf("Expected User='testuser', got '%s'", config.User)
|
||||
}
|
||||
if config.Name != "testdb" {
|
||||
t.Errorf("Expected Name='testdb', got '%s'", config.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config Config
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid mysql config",
|
||||
config: Config{
|
||||
MySQL: &MySQLConfig{DSN: "test"},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid postgres config",
|
||||
config: Config{
|
||||
Postgres: &PostgresConfig{User: "test", Host: "localhost", Name: "test"},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid legacy postgres config",
|
||||
config: Config{
|
||||
User: "test",
|
||||
Host: "localhost",
|
||||
Name: "testdb",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "both mysql and postgres set",
|
||||
config: Config{
|
||||
MySQL: &MySQLConfig{DSN: "test"},
|
||||
Postgres: &PostgresConfig{User: "test"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "mysql and legacy postgres set",
|
||||
config: Config{
|
||||
MySQL: &MySQLConfig{DSN: "test"},
|
||||
User: "test",
|
||||
Name: "testdb",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no config set",
|
||||
config: Config{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.config.Validate()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user