package database import ( "context" "database/sql/driver" "errors" "fmt" "os" "github.com/go-sql-driver/mysql" "gopkg.in/yaml.v3" ) // from https://github.com/Boostport/dynamic-database-config // CreateConnectorFunc is a function that creates a database connector type CreateConnectorFunc func() (driver.Connector, error) // Driver implements the sql/driver interface with dynamic configuration type Driver struct { CreateConnectorFunc CreateConnectorFunc } // Driver returns the driver instance func (d Driver) Driver() driver.Driver { return d } // Connect creates a new database connection using the dynamic connector func (d Driver) Connect(ctx context.Context) (driver.Conn, error) { connector, err := d.CreateConnectorFunc() if err != nil { return nil, fmt.Errorf("error creating connector from function: %w", err) } return connector.Connect(ctx) } // Open is not supported for dynamic configuration func (d Driver) Open(name string) (driver.Conn, error) { return nil, errors.New("open is not supported") } // createConnector creates a connector function that reads configuration from a file func createConnector(configFile string) CreateConnectorFunc { return func() (driver.Connector, error) { dbFile, err := os.Open(configFile) if err != nil { return nil, err } defer dbFile.Close() dec := yaml.NewDecoder(dbFile) cfg := Config{} err = dec.Decode(&cfg) if err != nil { return nil, err } dsn := cfg.MySQL.DSN if len(dsn) == 0 { dsn = os.Getenv("DATABASE_DSN") if len(dsn) == 0 { return nil, fmt.Errorf("dsn config in database.yaml or DATABASE_DSN environment variable required") } } dbcfg, err := mysql.ParseDSN(dsn) if err != nil { return nil, err } if user := cfg.MySQL.User; len(user) > 0 { dbcfg.User = user } if pass := cfg.MySQL.Pass; len(pass) > 0 { dbcfg.Passwd = pass } if name := cfg.MySQL.DBName; len(name) > 0 { dbcfg.DBName = name } return mysql.NewConnector(dbcfg) } }