73 lines
1.5 KiB
Go
73 lines
1.5 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"go-dy/internal/config"
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
)
|
|
|
|
var (
|
|
mu sync.Mutex
|
|
conn *sql.DB
|
|
)
|
|
|
|
func getDSN(cfg config.Config) string {
|
|
if cfg.DBDsn != "" {
|
|
return cfg.DBDsn
|
|
}
|
|
// sensible default for local dev
|
|
return "root:password@tcp(127.0.0.1:3306)/go-dy?parseTime=true&charset=utf8mb4&loc=Local"
|
|
}
|
|
|
|
// Get returns a shared DB connection. It retries initialization if previous attempts failed.
|
|
func Get(cfg config.Config) (*sql.DB, error) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if conn != nil {
|
|
return conn, nil
|
|
}
|
|
dsn := getDSN(cfg)
|
|
db, err := sql.Open("mysql", dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
db.SetMaxOpenConns(20)
|
|
db.SetMaxIdleConns(5)
|
|
db.SetConnMaxLifetime(30 * time.Minute)
|
|
|
|
// verify connection first
|
|
if e := db.Ping(); e != nil {
|
|
_ = db.Close()
|
|
return nil, e
|
|
}
|
|
|
|
// init schema after successful ping
|
|
if e := initSchema(db); e != nil {
|
|
_ = db.Close()
|
|
return nil, e
|
|
}
|
|
|
|
conn = db
|
|
return conn, nil
|
|
}
|
|
|
|
func initSchema(db *sql.DB) error {
|
|
// minimal users table
|
|
_, err := db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
name VARCHAR(255) NOT NULL UNIQUE,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("init schema: %w", err)
|
|
}
|
|
return nil
|
|
} |