Compare commits

...

4 Commits

2 changed files with 216 additions and 0 deletions

View File

@@ -2,6 +2,9 @@ package config
import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
@@ -91,6 +94,160 @@ func (c *DBManagerConfig) ToManagerConfig() interface{} {
return c
}
// PopulateFromDSN parses a DSN and populates the connection fields
func (cc *DBConnectionConfig) PopulateFromDSN() error {
if cc.DSN == "" {
return nil // Nothing to populate
}
switch cc.Type {
case "postgres":
return cc.populatePostgresDSN()
case "mongodb":
return cc.populateMongoDSN()
case "mssql":
return cc.populateMSSQLDSN()
case "sqlite":
return cc.populateSQLiteDSN()
default:
return fmt.Errorf("cannot parse DSN for unsupported database type: %s", cc.Type)
}
}
// populatePostgresDSN parses PostgreSQL DSN format
// Example: host=localhost port=5432 user=postgres password=secret dbname=mydb sslmode=disable
func (cc *DBConnectionConfig) populatePostgresDSN() error {
parts := strings.Fields(cc.DSN)
for _, part := range parts {
kv := strings.SplitN(part, "=", 2)
if len(kv) != 2 {
continue
}
key, value := kv[0], kv[1]
switch key {
case "host":
cc.Host = value
case "port":
port, err := strconv.Atoi(value)
if err != nil {
return fmt.Errorf("invalid port in DSN: %w", err)
}
cc.Port = port
case "user":
cc.User = value
case "password":
cc.Password = value
case "dbname":
cc.Database = value
case "sslmode":
cc.SSLMode = value
case "search_path":
cc.Schema = value
}
}
return nil
}
// populateMongoDSN parses MongoDB DSN format
// Example: mongodb://user:password@host:port/database?authSource=admin&replicaSet=rs0
func (cc *DBConnectionConfig) populateMongoDSN() error {
u, err := url.Parse(cc.DSN)
if err != nil {
return fmt.Errorf("invalid MongoDB DSN: %w", err)
}
// Extract user and password
if u.User != nil {
cc.User = u.User.Username()
if password, ok := u.User.Password(); ok {
cc.Password = password
}
}
// Extract host and port
if u.Host != "" {
host := u.Host
if strings.Contains(host, ":") {
hostPort := strings.SplitN(host, ":", 2)
cc.Host = hostPort[0]
if port, err := strconv.Atoi(hostPort[1]); err == nil {
cc.Port = port
}
} else {
cc.Host = host
}
}
// Extract database
if u.Path != "" {
cc.Database = strings.TrimPrefix(u.Path, "/")
}
// Extract query parameters
params := u.Query()
if authSource := params.Get("authSource"); authSource != "" {
cc.AuthSource = authSource
}
if replicaSet := params.Get("replicaSet"); replicaSet != "" {
cc.ReplicaSet = replicaSet
}
if readPref := params.Get("readPreference"); readPref != "" {
cc.ReadPreference = readPref
}
return nil
}
// populateMSSQLDSN parses MSSQL DSN format
// Example: sqlserver://username:password@host:port?database=dbname&schema=dbo
func (cc *DBConnectionConfig) populateMSSQLDSN() error {
u, err := url.Parse(cc.DSN)
if err != nil {
return fmt.Errorf("invalid MSSQL DSN: %w", err)
}
// Extract user and password
if u.User != nil {
cc.User = u.User.Username()
if password, ok := u.User.Password(); ok {
cc.Password = password
}
}
// Extract host and port
if u.Host != "" {
host := u.Host
if strings.Contains(host, ":") {
hostPort := strings.SplitN(host, ":", 2)
cc.Host = hostPort[0]
if port, err := strconv.Atoi(hostPort[1]); err == nil {
cc.Port = port
}
} else {
cc.Host = host
}
}
// Extract query parameters
params := u.Query()
if database := params.Get("database"); database != "" {
cc.Database = database
}
if schema := params.Get("schema"); schema != "" {
cc.Schema = schema
}
return nil
}
// populateSQLiteDSN parses SQLite DSN format
// Example: /path/to/database.db or :memory:
func (cc *DBConnectionConfig) populateSQLiteDSN() error {
cc.FilePath = cc.DSN
return nil
}
// Validate validates the DBManager configuration
func (c *DBManagerConfig) Validate() error {
if len(c.Connections) == 0 {

View File

@@ -97,6 +97,29 @@ func (m *Manager) GetConfig() (*Config, error) {
return &cfg, nil
}
// SetConfig sets the complete configuration
func (m *Manager) SetConfig(cfg *Config) error {
configMap := make(map[string]interface{})
// Marshal the config to a map structure that viper can use
if err := m.v.Unmarshal(&configMap); err != nil {
return fmt.Errorf("failed to prepare config map: %w", err)
}
// Use viper's merge to apply the config
m.v.Set("server", cfg.Server)
m.v.Set("tracing", cfg.Tracing)
m.v.Set("cache", cfg.Cache)
m.v.Set("logger", cfg.Logger)
m.v.Set("error_tracking", cfg.ErrorTracking)
m.v.Set("middleware", cfg.Middleware)
m.v.Set("cors", cfg.CORS)
m.v.Set("event_broker", cfg.EventBroker)
m.v.Set("dbmanager", cfg.DBManager)
return nil
}
// Get returns a configuration value by key
func (m *Manager) Get(key string) interface{} {
return m.v.Get(key)
@@ -122,6 +145,14 @@ func (m *Manager) Set(key string, value interface{}) {
m.v.Set(key, value)
}
// SaveConfig writes the current configuration to the specified path
func (m *Manager) SaveConfig(path string) error {
if err := m.v.WriteConfigAs(path); err != nil {
return fmt.Errorf("failed to save config to %s: %w", path, err)
}
return nil
}
// setDefaults sets default configuration values
func setDefaults(v *viper.Viper) {
// Server defaults
@@ -166,6 +197,34 @@ func setDefaults(v *viper.Viper) {
// Database defaults
v.SetDefault("database.url", "")
// Database Manager defaults
v.SetDefault("dbmanager.default_connection", "default")
v.SetDefault("dbmanager.max_open_conns", 25)
v.SetDefault("dbmanager.max_idle_conns", 5)
v.SetDefault("dbmanager.conn_max_lifetime", "30m")
v.SetDefault("dbmanager.conn_max_idle_time", "5m")
v.SetDefault("dbmanager.retry_attempts", 3)
v.SetDefault("dbmanager.retry_delay", "1s")
v.SetDefault("dbmanager.retry_max_delay", "10s")
v.SetDefault("dbmanager.health_check_interval", "30s")
v.SetDefault("dbmanager.enable_auto_reconnect", true)
// Default PostgreSQL connection
v.SetDefault("dbmanager.connections.default.name", "default")
v.SetDefault("dbmanager.connections.default.type", "postgres")
v.SetDefault("dbmanager.connections.default.host", "localhost")
v.SetDefault("dbmanager.connections.default.port", 5432)
v.SetDefault("dbmanager.connections.default.user", "postgres")
v.SetDefault("dbmanager.connections.default.password", "")
v.SetDefault("dbmanager.connections.default.database", "resolvespec")
v.SetDefault("dbmanager.connections.default.sslmode", "disable")
v.SetDefault("dbmanager.connections.default.connect_timeout", "10s")
v.SetDefault("dbmanager.connections.default.query_timeout", "30s")
v.SetDefault("dbmanager.connections.default.enable_tracing", false)
v.SetDefault("dbmanager.connections.default.enable_metrics", false)
v.SetDefault("dbmanager.connections.default.enable_logging", false)
v.SetDefault("dbmanager.connections.default.default_orm", "bun")
// Event Broker defaults
v.SetDefault("event_broker.enabled", false)
v.SetDefault("event_broker.provider", "memory")