package database import ( domainUpdate "RenewCMS/internal/domain/update" "fmt" "time" "gorm.io/gorm" ) type PoolSettings struct { MaxOpenConns int MaxIdleConns int ConnMaxLifetime time.Duration } type Config struct { Driver string Source string Pool *PoolSettings } type Driver interface { Open(source string) (*gorm.DB, error) NewBackup(db *gorm.DB, directory string, now func() time.Time) domainUpdate.DatabaseBackup IsLockContention(err error) bool IsUniqueViolation(err error) bool } var drivers = map[string]Driver{ DriverSQLite: sqliteDriver{}, DriverMySQL: mysqlDriver{}, DriverPostgres: postgresDriver{}, } func IsLockContentionFor(driverName string, err error) bool { driver, ok := drivers[driverName] return ok && err != nil && driver.IsLockContention(err) } func IsLockContention(db *gorm.DB, err error) bool { return IsLockContentionFor(db.Name(), err) } func IsUniqueViolationFor(driverName string, err error) bool { driver, ok := drivers[driverName] return ok && err != nil && driver.IsUniqueViolation(err) } func IsUniqueViolation(db *gorm.DB, err error) bool { return IsUniqueViolationFor(db.Name(), err) } type Connection struct { DB *gorm.DB driver Driver } func Connect(config Config) (*Connection, error) { driver, ok := drivers[config.Driver] if !ok { return nil, fmt.Errorf("unsupported database driver %q", config.Driver) } db, err := driver.Open(config.Source) if err != nil { return nil, err } if config.Pool != nil { if err := applyPool(db, *config.Pool); err != nil { return nil, err } } return &Connection{DB: db, driver: driver}, nil } func applyPool(db *gorm.DB, pool PoolSettings) error { sqlDb, err := db.DB() if err != nil { return err } sqlDb.SetMaxOpenConns(pool.MaxOpenConns) sqlDb.SetMaxIdleConns(pool.MaxIdleConns) sqlDb.SetConnMaxLifetime(pool.ConnMaxLifetime) return nil } func (c *Connection) NewBackup(directory string, now func() time.Time) domainUpdate.DatabaseBackup { return c.driver.NewBackup(c.DB, directory, now) } func (c *Connection) Close() error { sqlDb, err := c.DB.DB() if err != nil { return err } return sqlDb.Close() }