package database import ( "cargo-erp-backend/internal/config" "cargo-erp-backend/internal/logger" "fmt" "net/url" "sync" "time" "go.uber.org/zap" "gorm.io/driver/postgres" "gorm.io/gorm" ) type DatabaseInterface interface { Connect() Close() Get(key string) *gorm.DB RegisterCallback() } type Database struct { Config config.ConfigInterface DB map[string]*gorm.DB dbLock sync.RWMutex Logger *zap.Logger AppLogger *zap.Logger } func NewDatabase(config config.ConfigInterface, logger *zap.Logger, app_logger *zap.Logger) DatabaseInterface { return &Database{ Config: config, Logger: logger, AppLogger: app_logger, } } func (d *Database) Connect() { d.dbLock.Lock() defer d.dbLock.Unlock() db := make(map[string]*gorm.DB) username := d.Config.Get("database.username").(string) password := d.Config.Get("database.password").(string) dbname := d.Config.Get("database.database").(string) host_master := fmt.Sprintf("%v", d.Config.Get("database.master.host")) port_master := fmt.Sprintf("%v", d.Config.Get("database.master.port")) ssl_master := d.Config.Get("database.master.ssl") dsnMaster := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", url.PathEscape(username), url.PathEscape(password), host_master, port_master, dbname, ssl_master, ) d.AppLogger.Info("Connect To Master DB") gormLogger := logger.NewGormZapLogger(d.Logger, 5*time.Second) dbMaster, err := gorm.Open(postgres.Open(dsnMaster), &gorm.Config{ Logger: gormLogger, }) if err != nil { d.AppLogger.Fatal(err.Error()) return } db["master"] = dbMaster d.AppLogger.Info("DB Master Connected") host_slave := fmt.Sprintf("%v", d.Config.Get("database.slave.host")) port_slave := fmt.Sprintf("%v", d.Config.Get("database.slave.port")) ssl_slave := d.Config.Get("database.slave.ssl") dsnSlave := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", url.PathEscape(username), url.PathEscape(password), host_slave, port_slave, dbname, ssl_slave, ) d.AppLogger.Info("Connect To Slave DB") dbSlave, err := gorm.Open(postgres.Open(dsnSlave), &gorm.Config{ Logger: gormLogger, }) if err != nil { d.AppLogger.Fatal(err.Error()) return } db["slave"] = dbSlave d.DB = db d.AppLogger.Info("DB Connection Done") } func (d *Database) RegisterCallback() { d.Config.RegisterOnChangeCallback(d.ReloadDB) } func (d *Database) Get(key string) *gorm.DB { d.dbLock.RLock() defer d.dbLock.RUnlock() if v, ok := d.DB[key]; ok { return v } return nil } func (d *Database) Close() { d.dbLock.Lock() defer d.dbLock.Unlock() d.AppLogger.Info("Close Database Connection Start") for k, db := range d.DB { if db != nil { sqlDb, _ := db.DB() sqlDb.Close() d.AppLogger.Info(fmt.Sprintf("Close Database Connection %s", k)) } } d.AppLogger.Info("Close Database Connection Done") } func (d *Database) ReloadDB() { d.AppLogger.Info("Reload Connecting Database") d.Close() d.Connect() d.AppLogger.Info("Reload Connecting Database Done") }