Updat erubhan besar query builder
This commit is contained in:
+427
-81
@@ -20,7 +20,7 @@ import (
|
||||
type Config struct {
|
||||
Server ServerConfig
|
||||
Databases map[string]DatabaseConfig
|
||||
ReadReplicas map[string][]DatabaseConfig // For read replicas
|
||||
ReadReplicas map[string][]DatabaseConfig
|
||||
Auth AuthConfig
|
||||
Keycloak KeycloakConfig
|
||||
Bpjs BpjsConfig
|
||||
@@ -65,6 +65,20 @@ type DatabaseConfig struct {
|
||||
MaxOpenConns int // Max open connections
|
||||
MaxIdleConns int // Max idle connections
|
||||
ConnMaxLifetime time.Duration // Connection max lifetime
|
||||
// Security settings
|
||||
RequireSSL bool // Require SSL connection
|
||||
SSLRootCert string // Path to SSL root certificate
|
||||
SSLCert string // Path to SSL client certificate
|
||||
SSLKey string // Path to SSL client key
|
||||
Timeout time.Duration // Connection timeout
|
||||
ConnectTimeout time.Duration // Connect timeout
|
||||
ReadTimeout time.Duration // Read timeout
|
||||
WriteTimeout time.Duration // Write timeout
|
||||
StatementTimeout time.Duration // Statement timeout for PostgreSQL
|
||||
// Connection pool settings
|
||||
MaxLifetime time.Duration // Maximum amount of time a connection may be reused
|
||||
MaxIdleTime time.Duration // Maximum amount of time a connection may be idle
|
||||
HealthCheckPeriod time.Duration // Health check period
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
@@ -79,6 +93,7 @@ type AuthYAMLConfig struct {
|
||||
StaticTokens []string `yaml:"static_tokens"`
|
||||
FallbackTo string `yaml:"fallback_to"`
|
||||
}
|
||||
|
||||
type KeycloakYAMLConfig struct {
|
||||
Issuer string `yaml:"issuer"`
|
||||
Audience string `yaml:"audience"`
|
||||
@@ -121,6 +136,10 @@ type SecurityConfig struct {
|
||||
RateLimit RateLimitConfig `mapstructure:"rate_limit"`
|
||||
// Input Validation
|
||||
MaxInputLength int `mapstructure:"max_input_length"`
|
||||
// SQL Injection Protection
|
||||
SanitizeQueries bool `mapstructure:"sanitize_queries"`
|
||||
// Connection Security
|
||||
RequireSecureConnections bool `mapstructure:"require_secure_connections"`
|
||||
}
|
||||
|
||||
// RateLimitConfig berisi pengaturan untuk rate limiter
|
||||
@@ -229,6 +248,8 @@ func LoadConfig() *Config {
|
||||
DB: getEnvAsInt("REDIS_DB", 0),
|
||||
},
|
||||
},
|
||||
SanitizeQueries: getEnvAsBool("SECURITY_SANITIZE_QUERIES", true),
|
||||
RequireSecureConnections: getEnvAsBool("SECURITY_REQUIRE_SECURE_CONNECTIONS", false),
|
||||
},
|
||||
}
|
||||
log.Printf("DEBUG: Final Config Object. MaxInputLength is: %d", config.Security.MaxInputLength)
|
||||
@@ -372,32 +393,60 @@ func loadKeycloakConfig() KeycloakConfig {
|
||||
}
|
||||
|
||||
func (c *Config) loadDatabaseConfigs() {
|
||||
// Simplified approach: Directly load from environment variables
|
||||
// This ensures we get the exact values specified in .env
|
||||
|
||||
// // Primary database configuration
|
||||
// c.Databases["default"] = DatabaseConfig{
|
||||
// Name: "default",
|
||||
// Type: getEnv("DB_CONNECTION", "postgres"),
|
||||
// Host: getEnv("DB_HOST", "localhost"),
|
||||
// Port: getEnvAsInt("DB_PORT", 5432),
|
||||
// Username: getEnv("DB_USERNAME", ""),
|
||||
// Password: getEnv("DB_PASSWORD", ""),
|
||||
// Database: getEnv("DB_DATABASE", "satu_db"),
|
||||
// Schema: getEnv("DB_SCHEMA", "public"),
|
||||
// SSLMode: getEnv("DB_SSLMODE", "disable"),
|
||||
// MaxOpenConns: getEnvAsInt("DB_MAX_OPEN_CONNS", 25),
|
||||
// MaxIdleConns: getEnvAsInt("DB_MAX_IDLE_CONNS", 25),
|
||||
// ConnMaxLifetime: parseDuration(getEnv("DB_CONN_MAX_LIFETIME", "5m")),
|
||||
// }
|
||||
|
||||
// SATUDATA database configuration
|
||||
// Load PostgreSQL configurations
|
||||
c.addPostgreSQLConfigs()
|
||||
|
||||
// MongoDB database configuration
|
||||
// Load MySQL configurations
|
||||
c.addMySQLConfigs()
|
||||
|
||||
// Load MongoDB configurations
|
||||
c.addMongoDBConfigs()
|
||||
|
||||
// Legacy support for backward compatibility
|
||||
// Load SQLite configurations
|
||||
c.addSQLiteConfigs()
|
||||
|
||||
// Load custom database configurations from environment variables
|
||||
c.loadCustomDatabaseConfigs()
|
||||
|
||||
// Remove duplicate database configurations
|
||||
c.removeDuplicateDatabases()
|
||||
}
|
||||
|
||||
func (c *Config) removeDuplicateDatabases() {
|
||||
// Create a map to track unique database connections
|
||||
uniqueDBs := make(map[string]DatabaseConfig)
|
||||
duplicates := make(map[string][]string)
|
||||
|
||||
// First pass: identify duplicates
|
||||
for name, config := range c.Databases {
|
||||
// Create a unique key based on connection parameters
|
||||
key := fmt.Sprintf("%s:%s:%d:%s", config.Type, config.Host, config.Port, config.Database)
|
||||
|
||||
if existing, exists := uniqueDBs[key]; exists {
|
||||
// Found a duplicate
|
||||
if duplicates[key] == nil {
|
||||
duplicates[key] = []string{existing.Name}
|
||||
}
|
||||
duplicates[key] = append(duplicates[key], name)
|
||||
log.Printf("⚠️ Database %s is a duplicate of %s (same connection parameters)", name, existing.Name)
|
||||
} else {
|
||||
uniqueDBs[key] = config
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: remove duplicates, keeping the first one
|
||||
for _, dupNames := range duplicates {
|
||||
// Keep the first database name, remove the rest
|
||||
keepName := dupNames[0]
|
||||
for i := 1; i < len(dupNames); i++ {
|
||||
removeName := dupNames[i]
|
||||
delete(c.Databases, removeName)
|
||||
log.Printf("🗑️ Removed duplicate database configuration: %s (kept: %s)", removeName, keepName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) loadCustomDatabaseConfigs() {
|
||||
envVars := os.Environ()
|
||||
dbConfigs := make(map[string]map[string]string)
|
||||
|
||||
@@ -437,28 +486,45 @@ func (c *Config) loadDatabaseConfigs() {
|
||||
continue
|
||||
}
|
||||
|
||||
dbConfig := DatabaseConfig{
|
||||
Name: name,
|
||||
Type: getEnvFromMap(config, "connection", getEnvFromMap(config, "type", "postgres")),
|
||||
Host: getEnvFromMap(config, "host", "localhost"),
|
||||
Port: getEnvAsIntFromMap(config, "port", 5432),
|
||||
Username: getEnvFromMap(config, "username", ""),
|
||||
Password: getEnvFromMap(config, "password", ""),
|
||||
Database: getEnvFromMap(config, "database", getEnvFromMap(config, "name", name)),
|
||||
Schema: getEnvFromMap(config, "schema", "public"),
|
||||
SSLMode: getEnvFromMap(config, "sslmode", "disable"),
|
||||
Path: getEnvFromMap(config, "path", ""),
|
||||
Options: getEnvFromMap(config, "options", ""),
|
||||
MaxOpenConns: getEnvAsIntFromMap(config, "max_open_conns", 25),
|
||||
MaxIdleConns: getEnvAsIntFromMap(config, "max_idle_conns", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnvFromMap(config, "conn_max_lifetime", "5m")),
|
||||
}
|
||||
dbType := getEnvFromMap(config, "connection", getEnvFromMap(config, "type", "postgres"))
|
||||
|
||||
// Skip if username is empty and it's not a system config
|
||||
if dbConfig.Username == "" && !strings.HasPrefix(name, "chrome") {
|
||||
username := getEnvFromMap(config, "username", "")
|
||||
if username == "" && !strings.HasPrefix(name, "chrome") {
|
||||
continue
|
||||
}
|
||||
|
||||
dbConfig := DatabaseConfig{
|
||||
Name: name,
|
||||
Type: dbType,
|
||||
Host: getEnvFromMap(config, "host", "localhost"),
|
||||
Port: getEnvAsIntFromMap(config, "port", getDefaultPort(dbType)),
|
||||
Username: username,
|
||||
Password: getEnvFromMap(config, "password", ""),
|
||||
Database: getEnvFromMap(config, "database", getEnvFromMap(config, "name", name)),
|
||||
Schema: getEnvFromMap(config, "schema", getDefaultSchema(dbType)),
|
||||
SSLMode: getEnvFromMap(config, "sslmode", getDefaultSSLMode(dbType)),
|
||||
Path: getEnvFromMap(config, "path", ""),
|
||||
Options: getEnvFromMap(config, "options", ""),
|
||||
MaxOpenConns: getEnvAsIntFromMap(config, "max_open_conns", getDefaultMaxOpenConns(dbType)),
|
||||
MaxIdleConns: getEnvAsIntFromMap(config, "max_idle_conns", getDefaultMaxIdleConns(dbType)),
|
||||
ConnMaxLifetime: parseDuration(getEnvFromMap(config, "conn_max_lifetime", getDefaultConnMaxLifetime(dbType))),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBoolFromMap(config, "require_ssl", false),
|
||||
SSLRootCert: getEnvFromMap(config, "ssl_root_cert", ""),
|
||||
SSLCert: getEnvFromMap(config, "ssl_cert", ""),
|
||||
SSLKey: getEnvFromMap(config, "ssl_key", ""),
|
||||
Timeout: parseDuration(getEnvFromMap(config, "timeout", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnvFromMap(config, "connect_timeout", "10s")),
|
||||
ReadTimeout: parseDuration(getEnvFromMap(config, "read_timeout", "30s")),
|
||||
WriteTimeout: parseDuration(getEnvFromMap(config, "write_timeout", "30s")),
|
||||
StatementTimeout: parseDuration(getEnvFromMap(config, "statement_timeout", "120s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnvFromMap(config, "max_lifetime", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnvFromMap(config, "max_idle_time", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnvFromMap(config, "health_check_period", "1m")),
|
||||
}
|
||||
|
||||
c.Databases[name] = dbConfig
|
||||
}
|
||||
}
|
||||
@@ -499,20 +565,41 @@ func (c *Config) loadReadReplicaConfigs() {
|
||||
}
|
||||
|
||||
if replicaConfig == nil {
|
||||
// Create new replica config
|
||||
// Get primary DB config as base
|
||||
primaryDB, exists := c.Databases[dbName]
|
||||
if !exists {
|
||||
log.Printf("Warning: Primary database %s not found for replica configuration", dbName)
|
||||
continue
|
||||
}
|
||||
|
||||
// Create new replica config based on primary
|
||||
newConfig := DatabaseConfig{
|
||||
Name: replicaKey,
|
||||
Type: c.Databases[dbName].Type,
|
||||
Host: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_HOST", c.Databases[dbName].Host),
|
||||
Port: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PORT", c.Databases[dbName].Port),
|
||||
Username: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_USERNAME", c.Databases[dbName].Username),
|
||||
Password: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PASSWORD", c.Databases[dbName].Password),
|
||||
Database: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_DATABASE", c.Databases[dbName].Database),
|
||||
Schema: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SCHEMA", c.Databases[dbName].Schema),
|
||||
SSLMode: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSLMODE", c.Databases[dbName].SSLMode),
|
||||
MaxOpenConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_OPEN_CONNS", c.Databases[dbName].MaxOpenConns),
|
||||
MaxIdleConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_IDLE_CONNS", c.Databases[dbName].MaxIdleConns),
|
||||
ConnMaxLifetime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_CONN_MAX_LIFETIME", "5m")),
|
||||
Type: primaryDB.Type,
|
||||
Host: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_HOST", primaryDB.Host),
|
||||
Port: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PORT", primaryDB.Port),
|
||||
Username: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_USERNAME", primaryDB.Username),
|
||||
Password: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PASSWORD", primaryDB.Password),
|
||||
Database: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_DATABASE", primaryDB.Database),
|
||||
Schema: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SCHEMA", primaryDB.Schema),
|
||||
SSLMode: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSLMODE", primaryDB.SSLMode),
|
||||
MaxOpenConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_OPEN_CONNS", primaryDB.MaxOpenConns),
|
||||
MaxIdleConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_IDLE_CONNS", primaryDB.MaxIdleConns),
|
||||
ConnMaxLifetime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_CONN_MAX_LIFETIME", primaryDB.ConnMaxLifetime.String())),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_REQUIRE_SSL", primaryDB.RequireSSL),
|
||||
SSLRootCert: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSL_ROOT_CERT", primaryDB.SSLRootCert),
|
||||
SSLCert: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSL_CERT", primaryDB.SSLCert),
|
||||
SSLKey: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSL_KEY", primaryDB.SSLKey),
|
||||
Timeout: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_TIMEOUT", primaryDB.Timeout.String())),
|
||||
ConnectTimeout: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_CONNECT_TIMEOUT", primaryDB.ConnectTimeout.String())),
|
||||
ReadTimeout: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_READ_TIMEOUT", primaryDB.ReadTimeout.String())),
|
||||
WriteTimeout: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_WRITE_TIMEOUT", primaryDB.WriteTimeout.String())),
|
||||
StatementTimeout: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_STATEMENT_TIMEOUT", primaryDB.StatementTimeout.String())),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_LIFETIME", primaryDB.MaxLifetime.String())),
|
||||
MaxIdleTime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_IDLE_TIME", primaryDB.MaxIdleTime.String())),
|
||||
HealthCheckPeriod: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_HEALTH_CHECK_PERIOD", primaryDB.HealthCheckPeriod.String())),
|
||||
}
|
||||
c.ReadReplicas[dbName] = append(c.ReadReplicas[dbName], newConfig)
|
||||
replicaConfig = &c.ReadReplicas[dbName][len(c.ReadReplicas[dbName])-1]
|
||||
@@ -540,6 +627,30 @@ func (c *Config) loadReadReplicaConfigs() {
|
||||
replicaConfig.MaxIdleConns = getEnvAsInt(key, 25)
|
||||
case "conn_max_lifetime":
|
||||
replicaConfig.ConnMaxLifetime = parseDuration(value)
|
||||
case "require_ssl":
|
||||
replicaConfig.RequireSSL = getEnvAsBool(key, false)
|
||||
case "ssl_root_cert":
|
||||
replicaConfig.SSLRootCert = value
|
||||
case "ssl_cert":
|
||||
replicaConfig.SSLCert = value
|
||||
case "ssl_key":
|
||||
replicaConfig.SSLKey = value
|
||||
case "timeout":
|
||||
replicaConfig.Timeout = parseDuration(value)
|
||||
case "connect_timeout":
|
||||
replicaConfig.ConnectTimeout = parseDuration(value)
|
||||
case "read_timeout":
|
||||
replicaConfig.ReadTimeout = parseDuration(value)
|
||||
case "write_timeout":
|
||||
replicaConfig.WriteTimeout = parseDuration(value)
|
||||
case "statement_timeout":
|
||||
replicaConfig.StatementTimeout = parseDuration(value)
|
||||
case "max_lifetime":
|
||||
replicaConfig.MaxLifetime = parseDuration(value)
|
||||
case "max_idle_time":
|
||||
replicaConfig.MaxIdleTime = parseDuration(value)
|
||||
case "health_check_period":
|
||||
replicaConfig.HealthCheckPeriod = parseDuration(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,15 +665,29 @@ func (c *Config) addSpecificDatabase(prefix, defaultType string) {
|
||||
Name: prefix,
|
||||
Type: connection,
|
||||
Host: host,
|
||||
Port: getEnvAsInt(strings.ToUpper(prefix)+"_PORT", 5432),
|
||||
Port: getEnvAsInt(strings.ToUpper(prefix)+"_PORT", getDefaultPort(connection)),
|
||||
Username: getEnv(strings.ToUpper(prefix)+"_USERNAME", ""),
|
||||
Password: getEnv(strings.ToUpper(prefix)+"_PASSWORD", ""),
|
||||
Database: getEnv(strings.ToUpper(prefix)+"_DATABASE", getEnv(strings.ToUpper(prefix)+"_NAME", prefix)),
|
||||
Schema: getEnv(strings.ToUpper(prefix)+"_SCHEMA", "public"),
|
||||
SSLMode: getEnv(strings.ToUpper(prefix)+"_SSLMODE", "disable"),
|
||||
MaxOpenConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_IDLE_CONNS", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnv(strings.ToUpper(prefix)+"_CONN_MAX_LIFETIME", "5m")),
|
||||
Schema: getEnv(strings.ToUpper(prefix)+"_SCHEMA", getDefaultSchema(connection)),
|
||||
SSLMode: getEnv(strings.ToUpper(prefix)+"_SSLMODE", getDefaultSSLMode(connection)),
|
||||
MaxOpenConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_OPEN_CONNS", getDefaultMaxOpenConns(connection)),
|
||||
MaxIdleConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_IDLE_CONNS", getDefaultMaxIdleConns(connection)),
|
||||
ConnMaxLifetime: parseDuration(getEnv(strings.ToUpper(prefix)+"_CONN_MAX_LIFETIME", getDefaultConnMaxLifetime(connection))),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool(strings.ToUpper(prefix)+"_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv(strings.ToUpper(prefix)+"_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv(strings.ToUpper(prefix)+"_SSL_CERT", ""),
|
||||
SSLKey: getEnv(strings.ToUpper(prefix)+"_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv(strings.ToUpper(prefix)+"_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv(strings.ToUpper(prefix)+"_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv(strings.ToUpper(prefix)+"_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv(strings.ToUpper(prefix)+"_WRITE_TIMEOUT", "30s")),
|
||||
StatementTimeout: parseDuration(getEnv(strings.ToUpper(prefix)+"_STATEMENT_TIMEOUT", "120s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv(strings.ToUpper(prefix)+"_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv(strings.ToUpper(prefix)+"_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv(strings.ToUpper(prefix)+"_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
c.Databases[prefix] = dbConfig
|
||||
}
|
||||
@@ -570,25 +695,6 @@ func (c *Config) addSpecificDatabase(prefix, defaultType string) {
|
||||
|
||||
// PostgreSQL database
|
||||
func (c *Config) addPostgreSQLConfigs() {
|
||||
// SATUDATA database configuration
|
||||
// defaultPOSTGRESHost := getEnv("POSTGRES_HOST", "localhost")
|
||||
// if defaultPOSTGRESHost != "" {
|
||||
// c.Databases["postgres"] = DatabaseConfig{
|
||||
// Name: "postgres",
|
||||
// Type: getEnv("POSTGRES_CONNECTION", "postgres"),
|
||||
// Host: defaultPOSTGRESHost,
|
||||
// Port: getEnvAsInt("POSTGRES_PORT", 5432),
|
||||
// Username: getEnv("POSTGRES_USERNAME", ""),
|
||||
// Password: getEnv("POSTGRES_PASSWORD", ""),
|
||||
// Database: getEnv("POSTGRES_DATABASE", "postgres"),
|
||||
// Schema: getEnv("POSTGRES_SCHEMA", "public"),
|
||||
// SSLMode: getEnv("POSTGRES_SSLMODE", "disable"),
|
||||
// MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
|
||||
// MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
|
||||
// ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
|
||||
// }
|
||||
// }
|
||||
|
||||
// Support for custom PostgreSQL configurations with POSTGRES_ prefix
|
||||
envVars := os.Environ()
|
||||
for _, envVar := range envVars {
|
||||
@@ -624,6 +730,20 @@ func (c *Config) addPostgreSQLConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("POSTGRES_"+strings.ToUpper(dbName)+"_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSL_CERT", ""),
|
||||
SSLKey: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_WRITE_TIMEOUT", "30s")),
|
||||
StatementTimeout: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_STATEMENT_TIMEOUT", "120s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -648,6 +768,19 @@ func (c *Config) addMySQLConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("MYSQL_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("MYSQL_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("MYSQL_SSL_CERT", ""),
|
||||
SSLKey: getEnv("MYSQL_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("MYSQL_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("MYSQL_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("MYSQL_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("MYSQL_WRITE_TIMEOUT", "30s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("MYSQL_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("MYSQL_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("MYSQL_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,6 +820,19 @@ func (c *Config) addMySQLConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("MYSQL_"+strings.ToUpper(dbName)+"_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_SSL_CERT", ""),
|
||||
SSLKey: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_WRITE_TIMEOUT", "30s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("MYSQL_"+strings.ToUpper(dbName)+"_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -712,6 +858,19 @@ func (c *Config) addMongoDBConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
|
||||
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
|
||||
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("MONGODB_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("MONGODB_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("MONGODB_SSL_CERT", ""),
|
||||
SSLKey: getEnv("MONGODB_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("MONGODB_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("MONGODB_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("MONGODB_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("MONGODB_WRITE_TIMEOUT", "30s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("MONGODB_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("MONGODB_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("MONGODB_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,6 +889,19 @@ func (c *Config) addMongoDBConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
|
||||
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
|
||||
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("MONGODB_LOCAL_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("MONGODB_LOCAL_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("MONGODB_LOCAL_SSL_CERT", ""),
|
||||
SSLKey: getEnv("MONGODB_LOCAL_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("MONGODB_LOCAL_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("MONGODB_LOCAL_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("MONGODB_LOCAL_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("MONGODB_LOCAL_WRITE_TIMEOUT", "30s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("MONGODB_LOCAL_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("MONGODB_LOCAL_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("MONGODB_LOCAL_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,6 +938,19 @@ func (c *Config) addMongoDBConfigs() {
|
||||
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
|
||||
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
|
||||
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
|
||||
// Security settings
|
||||
RequireSSL: getEnvAsBool("MONGODB_"+strings.ToUpper(dbName)+"_REQUIRE_SSL", false),
|
||||
SSLRootCert: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_SSL_ROOT_CERT", ""),
|
||||
SSLCert: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_SSL_CERT", ""),
|
||||
SSLKey: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_SSL_KEY", ""),
|
||||
Timeout: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_TIMEOUT", "30s")),
|
||||
ConnectTimeout: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_CONNECT_TIMEOUT", "10s")),
|
||||
ReadTimeout: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_READ_TIMEOUT", "30s")),
|
||||
WriteTimeout: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_WRITE_TIMEOUT", "30s")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("MONGODB_"+strings.ToUpper(dbName)+"_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -773,6 +958,155 @@ func (c *Config) addMongoDBConfigs() {
|
||||
}
|
||||
}
|
||||
|
||||
// addSQLiteConfigs adds SQLite database configurations from environment variables
|
||||
func (c *Config) addSQLiteConfigs() {
|
||||
// Support for custom SQLite configurations with SQLITE_ prefix
|
||||
envVars := os.Environ()
|
||||
for _, envVar := range envVars {
|
||||
parts := strings.SplitN(envVar, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
key := parts[0]
|
||||
// Parse SQLite configurations (format: SQLITE_[NAME]_[PROPERTY])
|
||||
if strings.HasPrefix(key, "SQLITE_") && strings.Contains(key, "_") {
|
||||
segments := strings.Split(key, "_")
|
||||
if len(segments) >= 3 {
|
||||
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
||||
|
||||
// Skip if it's a standard SQLite configuration
|
||||
if dbName == "connection" || dbName == "dev" || dbName == "default" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Create or update SQLite configuration
|
||||
if _, exists := c.Databases[dbName]; !exists {
|
||||
sqlitePath := getEnv("SQLITE_"+strings.ToUpper(dbName)+"_PATH", "")
|
||||
if sqlitePath != "" {
|
||||
c.Databases[dbName] = DatabaseConfig{
|
||||
Name: dbName,
|
||||
Type: "sqlite",
|
||||
Path: sqlitePath,
|
||||
Database: getEnv("SQLITE_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
|
||||
MaxOpenConns: getEnvAsInt("SQLITE_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: getEnvAsInt("SQLITE_MAX_IDLE_CONNS", 25),
|
||||
ConnMaxLifetime: parseDuration(getEnv("SQLITE_CONN_MAX_LIFETIME", "5m")),
|
||||
// Connection pool settings
|
||||
MaxLifetime: parseDuration(getEnv("SQLITE_"+strings.ToUpper(dbName)+"_MAX_LIFETIME", "1h")),
|
||||
MaxIdleTime: parseDuration(getEnv("SQLITE_"+strings.ToUpper(dbName)+"_MAX_IDLE_TIME", "5m")),
|
||||
HealthCheckPeriod: parseDuration(getEnv("SQLITE_"+strings.ToUpper(dbName)+"_HEALTH_CHECK_PERIOD", "1m")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for getting default values based on database type
|
||||
func getDefaultPort(dbType string) int {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return 5432
|
||||
case "mysql":
|
||||
return 3306
|
||||
case "sqlserver":
|
||||
return 1433
|
||||
case "mongodb":
|
||||
return 27017
|
||||
case "sqlite":
|
||||
return 0 // SQLite doesn't use port
|
||||
default:
|
||||
return 5432
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultSchema(dbType string) string {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return "public"
|
||||
case "mysql":
|
||||
return ""
|
||||
case "sqlserver":
|
||||
return "dbo"
|
||||
case "mongodb":
|
||||
return ""
|
||||
case "sqlite":
|
||||
return ""
|
||||
default:
|
||||
return "public"
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultSSLMode(dbType string) string {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return "disable"
|
||||
case "mysql":
|
||||
return "false"
|
||||
case "sqlserver":
|
||||
return "false"
|
||||
case "mongodb":
|
||||
return "false"
|
||||
case "sqlite":
|
||||
return ""
|
||||
default:
|
||||
return "disable"
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultMaxOpenConns(dbType string) int {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return 25
|
||||
case "mysql":
|
||||
return 25
|
||||
case "sqlserver":
|
||||
return 25
|
||||
case "mongodb":
|
||||
return 100
|
||||
case "sqlite":
|
||||
return 1 // SQLite only supports one writer at a time
|
||||
default:
|
||||
return 25
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultMaxIdleConns(dbType string) int {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return 25
|
||||
case "mysql":
|
||||
return 25
|
||||
case "sqlserver":
|
||||
return 25
|
||||
case "mongodb":
|
||||
return 10
|
||||
case "sqlite":
|
||||
return 1 // SQLite only supports one writer at a time
|
||||
default:
|
||||
return 25
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultConnMaxLifetime(dbType string) string {
|
||||
switch dbType {
|
||||
case "postgres":
|
||||
return "5m"
|
||||
case "mysql":
|
||||
return "5m"
|
||||
case "sqlserver":
|
||||
return "5m"
|
||||
case "mongodb":
|
||||
return "30m"
|
||||
case "sqlite":
|
||||
return "5m"
|
||||
default:
|
||||
return "5m"
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvFromMap(config map[string]string, key, defaultValue string) string {
|
||||
if value, exists := config[key]; exists {
|
||||
return value
|
||||
@@ -789,6 +1123,15 @@ func getEnvAsIntFromMap(config map[string]string, key string, defaultValue int)
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func getEnvAsBoolFromMap(config map[string]string, key string, defaultValue bool) bool {
|
||||
if value, exists := config[key]; exists {
|
||||
if boolValue, err := strconv.ParseBool(value); err == nil {
|
||||
return boolValue
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func parseDuration(durationStr string) time.Duration {
|
||||
if duration, err := time.ParseDuration(durationStr); err == nil {
|
||||
return duration
|
||||
@@ -869,16 +1212,19 @@ func (c *Config) Validate() error {
|
||||
}
|
||||
|
||||
for name, db := range c.Databases {
|
||||
if db.Host == "" {
|
||||
if db.Type != "sqlite" && db.Host == "" {
|
||||
errs = append(errs, fmt.Sprintf("database host is required for %s", name))
|
||||
}
|
||||
if db.Username == "" {
|
||||
if db.Type != "sqlite" && db.Username == "" {
|
||||
errs = append(errs, fmt.Sprintf("database username is required for %s", name))
|
||||
}
|
||||
if db.Password == "" {
|
||||
if db.Type != "sqlite" && db.Password == "" {
|
||||
errs = append(errs, fmt.Sprintf("database password is required for %s", name))
|
||||
}
|
||||
if db.Database == "" {
|
||||
if db.Type == "sqlite" && db.Path == "" {
|
||||
errs = append(errs, fmt.Sprintf("database path is required for SQLite database %s", name))
|
||||
}
|
||||
if db.Type != "sqlite" && db.Database == "" {
|
||||
errs = append(errs, fmt.Sprintf("database name is required for %s", name))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user