/infrastructure/sql_connector.go

https://github.com/kyawmyintthein/golangRestfulAPISample · Go · 108 lines · 92 code · 16 blank · 0 comment · 12 complexity · 3212205e59b521a4d3f7180d5cfdacc9 MD5 · raw file

  1. package infrastructure
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/jmoiron/sqlx"
  7. "github.com/kyawmyintthein/orange-contrib/logx"
  8. _ "github.com/lib/pq"
  9. _ "github.com/mattn/go-sqlite3"
  10. )
  11. type DBDriver string
  12. const (
  13. Mysql DBDriver = `mysql`
  14. Postgres DBDriver = `postgres`
  15. Sqlite3 DBDriver = `sqlite3`
  16. )
  17. type SqlDBConfig struct {
  18. Driver DBDriver `mapstructure:"driver" json:"driver"`
  19. DBName string `mapstructure:"db_name" json:"db_name"`
  20. DBHost string `mapstructure:"db_host" json:"db_host"`
  21. DialTimeOut time.Duration `mapstructure:"dial_timeout" json:"dial_timeout"` // second
  22. MaxIdleConns int `mapstructure:"max_idle_conns" json:"max_idle_conns"`
  23. MaxOpenConns int `mapstructure:"max_open_conns" json:"max_open_conns"`
  24. ConnMaxLifetime time.Duration `mapstructure:"conn_max_life_time" json:"conn_max_life_time"` // second
  25. Username string `mapstructure:"username" json:"username"`
  26. Password string `mapstructure:"password" json:"password"`
  27. SSLMode string `mapstructure:"ssl_mode" json:"ssl_mode"`
  28. URI string `mapstructure:"uri" json:"uri"`
  29. }
  30. type SqlDBConnector interface {
  31. DB(context.Context) *sqlx.DB
  32. Config() SqlDBConfig
  33. }
  34. type sqlConnector struct {
  35. cfg *SqlDBConfig
  36. db *sqlx.DB
  37. }
  38. func NewSQLConnector(cfg *SqlDBConfig) (SqlDBConnector, error) {
  39. connectionString := cfg.URI
  40. if connectionString == "" {
  41. switch cfg.Driver {
  42. case Mysql:
  43. connectionString = getMySQLConnectionString(cfg)
  44. break
  45. case Postgres:
  46. connectionString = getPostgresConnectionString(cfg)
  47. break
  48. case Sqlite3:
  49. return nil, fmt.Errorf("connection string is empty! Use URI to set sqlite DB")
  50. }
  51. }
  52. if cfg.SSLMode == "" {
  53. cfg.SSLMode = "disable"
  54. }
  55. sqlConnector := &sqlConnector{
  56. cfg: cfg,
  57. }
  58. ctx, cancel := context.WithTimeout(context.Background(), cfg.DialTimeOut*time.Second)
  59. defer cancel()
  60. db, err := sqlx.ConnectContext(ctx, string(cfg.Driver), connectionString)
  61. if err != nil {
  62. logx.Errorf(context.Background(), err, "Failed to connect to mysql database: %s", cfg.DBName)
  63. return nil, err
  64. }
  65. db.SetMaxIdleConns(cfg.MaxIdleConns)
  66. db.SetMaxOpenConns(cfg.MaxOpenConns)
  67. db.SetConnMaxLifetime(cfg.ConnMaxLifetime * time.Second)
  68. err = db.Ping()
  69. if err != nil {
  70. logx.Errorf(context.Background(), err, "Failed to connect to database: %s", cfg.DBName)
  71. return sqlConnector, err
  72. }
  73. sqlConnector.db = db
  74. logx.Infof(context.Background(), "Successfully connected to database: %v", cfg.DBName)
  75. return sqlConnector, nil
  76. }
  77. func (mysql *sqlConnector) DB(ctx context.Context) *sqlx.DB {
  78. err := mysql.db.Ping() // reconnect is happen when Ping is called.
  79. if err != nil {
  80. logx.Errorf(context.Background(), err, "Failed to reconnect db")
  81. }
  82. return mysql.db
  83. }
  84. func (mysql *sqlConnector) Config() SqlDBConfig {
  85. return *mysql.cfg
  86. }
  87. func getMySQLConnectionString(cfg *SqlDBConfig) string {
  88. return fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=true", cfg.Username, cfg.Password, cfg.DBHost, cfg.DBName)
  89. }
  90. func getPostgresConnectionString(cfg *SqlDBConfig) string {
  91. return fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=%s", cfg.DBHost, cfg.Username, cfg.Password, cfg.DBName, cfg.SSLMode)
  92. }