106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package databaseconfig
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
mysql "github.com/go-sql-driver/mysql"
|
|
"primaya-api/cpone-middleware/internal/repository"
|
|
)
|
|
|
|
// ErrRSCodeMismatch indicates that a request was sent to the wrong hospital
|
|
// instance. The code is a guard for this installation, not a database key.
|
|
var ErrRSCodeMismatch = errors.New("kode RS tidak sesuai dengan instance CPONE")
|
|
|
|
type Setting struct {
|
|
RSCode string `json:"kode_rs"`
|
|
Name string `json:"nama"`
|
|
Host string `json:"host"`
|
|
Port string `json:"port"`
|
|
Database string `json:"database"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type PoolConfig struct {
|
|
MaxOpenConns int
|
|
MaxIdleConns int
|
|
ConnMaxLifetime time.Duration
|
|
}
|
|
|
|
func NormalizeRSCode(code string) string { return strings.ToUpper(strings.TrimSpace(code)) }
|
|
|
|
// StaticResolver owns one HIS connection for one CPONE installation. Resolve
|
|
// only validates the request code and always returns the same repository.
|
|
type StaticResolver struct {
|
|
code string
|
|
db *sql.DB
|
|
repo repository.MySQLLayananRepository
|
|
}
|
|
|
|
func NewStaticResolver(ctx context.Context, code string, setting Setting, pool PoolConfig) (*StaticResolver, error) {
|
|
code = NormalizeRSCode(code)
|
|
if code == "" {
|
|
return nil, errors.New("CPONE_RS_CODE wajib diisi")
|
|
}
|
|
if setting.Host == "" || setting.Port == "" || setting.Database == "" || setting.Username == "" {
|
|
return nil, errors.New("host, port, database, dan username HIS wajib diisi")
|
|
}
|
|
port, err := strconv.Atoi(setting.Port)
|
|
if err != nil || port < 1 || port > 65535 {
|
|
return nil, errors.New("port database HIS harus berupa angka antara 1 sampai 65535")
|
|
}
|
|
|
|
db, err := sql.Open("mysql", mysqlDSN(setting))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
applyPoolConfig(db, pool)
|
|
if err := db.PingContext(ctx); err != nil {
|
|
_ = db.Close()
|
|
return nil, fmt.Errorf("koneksi database HIS gagal: %w", err)
|
|
}
|
|
return &StaticResolver{code: code, db: db, repo: repository.NewMySQLLayananRepository(db)}, nil
|
|
}
|
|
|
|
func (r *StaticResolver) Resolve(_ context.Context, code string) (repository.MySQLLayananRepository, error) {
|
|
if NormalizeRSCode(code) != r.code {
|
|
return repository.MySQLLayananRepository{}, ErrRSCodeMismatch
|
|
}
|
|
return r.repo, nil
|
|
}
|
|
|
|
func (r *StaticResolver) Close() error {
|
|
if r == nil || r.db == nil {
|
|
return nil
|
|
}
|
|
return r.db.Close()
|
|
}
|
|
|
|
func (r *StaticResolver) Code() string { return strings.TrimSpace(r.code) }
|
|
|
|
func applyPoolConfig(db *sql.DB, pool PoolConfig) {
|
|
db.SetMaxOpenConns(pool.MaxOpenConns)
|
|
db.SetMaxIdleConns(pool.MaxIdleConns)
|
|
db.SetConnMaxLifetime(pool.ConnMaxLifetime)
|
|
}
|
|
|
|
func mysqlDSN(setting Setting) string {
|
|
cfg := mysql.NewConfig()
|
|
cfg.User = setting.Username
|
|
cfg.Passwd = setting.Password
|
|
cfg.Net = "tcp"
|
|
cfg.Addr = net.JoinHostPort(setting.Host, setting.Port)
|
|
cfg.DBName = setting.Database
|
|
cfg.ParseTime = true
|
|
cfg.Loc = time.Local
|
|
cfg.Params = map[string]string{"charset": "utf8mb4"}
|
|
return cfg.FormatDSN()
|
|
}
|