package mysql import ( "context" "database/sql" "fmt" "sync" "time" querier "git.gocasts.ir/ebhomengo/niki/pkg/query_transaction/sql" ) type Config struct { Username string `koanf:"username"` Password string `koanf:"password"` Port int `koanf:"port"` Host string `koanf:"host"` DBName string `koanf:"db_name"` } type DB struct { config Config db *querier.SQLDB mu sync.Mutex statements map[statementKey]*sql.Stmt } func (db *DB) Conn() *querier.SQLDB { return db.db } // TODO: this temporary to ignore linter error (magic number). const ( dbMaxConnLifetime = time.Minute * 3 dbMaxOpenConns = 10 dbMaxIdleConns = 10 ) func New(config Config) *DB { // parseTime=true changes the output type of DATE and DATETIME values to time.Time // instead of []byte / string // The date or datetime like 0000-00-00 00:00:00 is converted into zero value of time.Time db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", config.Username, config.Password, config.Host, config.Port, config.DBName)) if err != nil { panic(fmt.Errorf("can't open mysql db: %w", err)) } // See "Important settings" section. db.SetConnMaxLifetime(dbMaxConnLifetime) db.SetMaxOpenConns(dbMaxOpenConns) db.SetMaxIdleConns(dbMaxIdleConns) return &DB{ config: config, db: &querier.SQLDB{DB: db}, statements: make(map[statementKey]*sql.Stmt), } } func (db *DB) PrepareStatement(ctx context.Context, key statementKey, query string) (*sql.Stmt, error) { db.mu.Lock() defer db.mu.Unlock() if stmt, ok := db.statements[key]; ok { return stmt, nil } stmt, err := db.db.PrepareContext(ctx, query) if err != nil { return nil, err } db.statements[key] = stmt return stmt, nil } func (db *DB) CloseStatements() error { db.mu.Lock() defer db.mu.Unlock() for _, stmt := range db.statements { err := stmt.Close() if err != nil { return err } } return nil }