package mysqlx import ( "errors" "time" mysqldriver "github.com/go-sql-driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "gorm.io/gorm/schema" ) // Option configures the SDK client. type Option func(*config) type config struct { DSN string DSNConfig *mysqldriver.Config DSNUser string DSNPassword string DSNNet string DSNAddr string DSNDBName string DSNParams map[string]string DSNParseTime *bool DSNTLSConfig string DSNLoc *time.Location DSNCollation string DSNTimeout time.Duration DSNReadTimeout time.Duration DSNWriteTimeout time.Duration Dialector gorm.Dialector Logger logger.Interface NamingStrategy schema.NamingStrategy MaxIdleConns int MaxOpenConns int ConnMaxIdleTime time.Duration ConnMaxLifetime time.Duration DisableForeignKeyConstraintWhenMigrating bool SkipDefaultTransaction bool DryRun bool } type DSN struct { } func defaultConfig() *config { return &config{ Logger: logger.Default, NamingStrategy: schema.NamingStrategy{SingularTable: true}, MaxIdleConns: 10, MaxOpenConns: 100, } } func buildDSN(cfg *config) (string, error) { var mysqlConfig *mysqldriver.Config if cfg.DSN != "" { parsed, err := mysqldriver.ParseDSN(cfg.DSN) if err != nil { return "", err } mysqlConfig = parsed } else if cfg.DSNConfig != nil { mysqlConfig = cfg.DSNConfig.Clone() } else { mysqlConfig = mysqldriver.NewConfig() } applyMySQLConfigOverrides(mysqlConfig, cfg) if mysqlConfig.User == "" && mysqlConfig.Passwd == "" && mysqlConfig.Addr == "" && mysqlConfig.DBName == "" && len(mysqlConfig.Params) == 0 { if cfg.DSN == "" { return "", errors.New("mysqlx: DSN or expanded DSN configuration must be provided") } } return mysqlConfig.FormatDSN(), nil } func applyMySQLConfigOverrides(mysqlConfig *mysqldriver.Config, cfg *config) { if cfg.DSNConfig != nil { mergeMySQLConfig(mysqlConfig, cfg.DSNConfig) } if cfg.DSNUser != "" { mysqlConfig.User = cfg.DSNUser } if cfg.DSNPassword != "" { mysqlConfig.Passwd = cfg.DSNPassword } if cfg.DSNNet != "" { mysqlConfig.Net = cfg.DSNNet } if cfg.DSNAddr != "" { mysqlConfig.Addr = cfg.DSNAddr } if cfg.DSNDBName != "" { mysqlConfig.DBName = cfg.DSNDBName } if cfg.DSNParams != nil { if mysqlConfig.Params == nil { mysqlConfig.Params = map[string]string{} } for key, value := range cfg.DSNParams { mysqlConfig.Params[key] = value } } if cfg.DSNParseTime != nil { mysqlConfig.ParseTime = *cfg.DSNParseTime } if cfg.DSNTLSConfig != "" { mysqlConfig.TLSConfig = cfg.DSNTLSConfig } if cfg.DSNLoc != nil { mysqlConfig.Loc = cfg.DSNLoc } if cfg.DSNCollation != "" { mysqlConfig.Collation = cfg.DSNCollation } if cfg.DSNTimeout > 0 { mysqlConfig.Timeout = cfg.DSNTimeout } if cfg.DSNReadTimeout > 0 { mysqlConfig.ReadTimeout = cfg.DSNReadTimeout } if cfg.DSNWriteTimeout > 0 { mysqlConfig.WriteTimeout = cfg.DSNWriteTimeout } } func mergeMySQLConfig(base, override *mysqldriver.Config) { if override.User != "" { base.User = override.User } if override.Passwd != "" { base.Passwd = override.Passwd } if override.Net != "" { base.Net = override.Net } if override.Addr != "" { base.Addr = override.Addr } if override.DBName != "" { base.DBName = override.DBName } if override.Params != nil { if base.Params == nil { base.Params = map[string]string{} } for key, value := range override.Params { base.Params[key] = value } } if override.Collation != "" { base.Collation = override.Collation } if override.Loc != nil { base.Loc = override.Loc } if override.TLSConfig != "" { base.TLSConfig = override.TLSConfig } if override.Timeout > 0 { base.Timeout = override.Timeout } if override.ReadTimeout > 0 { base.ReadTimeout = override.ReadTimeout } if override.WriteTimeout > 0 { base.WriteTimeout = override.WriteTimeout } if override.ParseTime { base.ParseTime = override.ParseTime } } // WithDSN sets the MySQL DSN used to open the database. func WithDSN(dsn string) Option { return func(cfg *config) { cfg.DSN = dsn } } // WithDSNConfig sets the underlying mysql.Config used to generate the DSN. func WithDSNConfig(mysqlConfig *mysqldriver.Config) Option { return func(cfg *config) { cfg.DSNConfig = mysqlConfig } } // WithDSNUser sets the MySQL username. func WithDSNUser(user string) Option { return func(cfg *config) { cfg.DSNUser = user } } // WithDSNPassword sets the MySQL password. func WithDSNPassword(password string) Option { return func(cfg *config) { cfg.DSNPassword = password } } // WithDSNNet sets the network type for the DSN. func WithDSNNet(net string) Option { return func(cfg *config) { cfg.DSNNet = net } } // WithDSNAddr sets the database address for the DSN. func WithDSNAddr(addr string) Option { return func(cfg *config) { cfg.DSNAddr = addr } } // WithDSNDBName sets the database name for the DSN. func WithDSNDBName(dbName string) Option { return func(cfg *config) { cfg.DSNDBName = dbName } } // WithDSNParams sets additional DSN query parameters. func WithDSNParams(params map[string]string) Option { return func(cfg *config) { if cfg.DSNParams == nil { cfg.DSNParams = map[string]string{} } for key, value := range params { cfg.DSNParams[key] = value } } } // WithDSNParseTime configures parseTime for the DSN. func WithDSNParseTime(parseTime bool) Option { return func(cfg *config) { cfg.DSNParseTime = &parseTime } } // WithDSNTLSConfig sets the TLS configuration name for the DSN. func WithDSNTLSConfig(tlsConfig string) Option { return func(cfg *config) { cfg.DSNTLSConfig = tlsConfig } } // WithDSNLocation sets the time location for DSN parsing. func WithDSNLocation(loc *time.Location) Option { return func(cfg *config) { cfg.DSNLoc = loc } } // WithDSNCollation sets the connection collation for the DSN. func WithDSNCollation(collation string) Option { return func(cfg *config) { cfg.DSNCollation = collation } } // WithDSNTimeout sets the dial timeout for the DSN. func WithDSNTimeout(timeout time.Duration) Option { return func(cfg *config) { cfg.DSNTimeout = timeout } } // WithDSNReadTimeout sets the read timeout for the DSN. func WithDSNReadTimeout(timeout time.Duration) Option { return func(cfg *config) { cfg.DSNReadTimeout = timeout } } // WithDSNWriteTimeout sets the write timeout for the DSN. func WithDSNWriteTimeout(timeout time.Duration) Option { return func(cfg *config) { cfg.DSNWriteTimeout = timeout } } // WithDialector sets a custom gorm Dialector. func WithDialector(dialector gorm.Dialector) Option { return func(cfg *config) { cfg.Dialector = dialector } } // WithLogger sets the gorm logger. func WithLogger(logger logger.Interface) Option { return func(cfg *config) { cfg.Logger = logger } } // WithNamingStrategy sets the naming strategy for gorm models. func WithNamingStrategy(strategy schema.NamingStrategy) Option { return func(cfg *config) { cfg.NamingStrategy = strategy } } // WithSingularTable enables or disables singular table names for gorm models. func WithSingularTable(singular bool) Option { return func(cfg *config) { cfg.NamingStrategy.SingularTable = singular } } // WithConnectionPool configures database connection pooling. func WithConnectionPool(maxIdleConns, maxOpenConns int, maxIdleTime, maxLifetime time.Duration) Option { return func(cfg *config) { cfg.MaxIdleConns = maxIdleConns cfg.MaxOpenConns = maxOpenConns cfg.ConnMaxIdleTime = maxIdleTime cfg.ConnMaxLifetime = maxLifetime } } // WithDisableForeignKeyConstraintWhenMigrating toggles foreign key constraint creation during migrations. func WithDisableForeignKeyConstraintWhenMigrating(disable bool) Option { return func(cfg *config) { cfg.DisableForeignKeyConstraintWhenMigrating = disable } } // WithSkipDefaultTransaction toggles default transactions in gorm. func WithSkipDefaultTransaction(skip bool) Option { return func(cfg *config) { cfg.SkipDefaultTransaction = skip } } // WithDryRun toggles gorm dry run mode. func WithDryRun(dryRun bool) Option { return func(cfg *config) { cfg.DryRun = dryRun } }