first commit
This commit is contained in:
101
configs/db.go
Normal file
101
configs/db.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
accountModels "ginimageApi/app/accounts/models"
|
||||
blogModels "ginimageApi/app/blogs/models"
|
||||
imageModels "ginimageApi/app/images/models"
|
||||
mcpModels "ginimageApi/app/mcp/models"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
// DB global GORM veritabanı bağlantısı
|
||||
var DB *gorm.DB
|
||||
|
||||
// ConnectDB .env dosyasındaki ayarlarla MySQL bağlantısını kurar
|
||||
func ConnectDB() error {
|
||||
host := os.Getenv("DB_HOST")
|
||||
port := os.Getenv("DB_PORT")
|
||||
user := os.Getenv("DB_USER")
|
||||
password := os.Getenv("DB_PASSWORD")
|
||||
dbName := os.Getenv("DB_NAME")
|
||||
|
||||
// DSN (Data Source Name) oluştur
|
||||
dsn := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
user, password, host, port, dbName,
|
||||
)
|
||||
|
||||
// GORM logger ayarları
|
||||
gormLogger := logger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags),
|
||||
logger.Config{
|
||||
SlowThreshold: 200 * time.Millisecond,
|
||||
LogLevel: logger.Warn,
|
||||
IgnoreRecordNotFoundError: true,
|
||||
Colorful: true,
|
||||
},
|
||||
)
|
||||
|
||||
var err error
|
||||
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||
Logger: gormLogger,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("veritabanına bağlanılamadı: %w", err)
|
||||
}
|
||||
|
||||
// Bağlantı havuzu ayarları
|
||||
sqlDB, err := DB.DB()
|
||||
if err != nil {
|
||||
return fmt.Errorf("sql.DB alınamadı: %w", err)
|
||||
}
|
||||
|
||||
sqlDB.SetMaxIdleConns(10)
|
||||
sqlDB.SetMaxOpenConns(100)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
log.Printf("✅ Veritabanı bağlantısı kuruldu: %s:%s/%s", host, port, dbName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunAutoMigrate tanımlanan modelleri otomatik olarak migrate eder
|
||||
func RunAutoMigrate() error {
|
||||
if DB == nil {
|
||||
return fmt.Errorf("migration icin veritabani baglantisi yok")
|
||||
}
|
||||
|
||||
err := DB.AutoMigrate(
|
||||
&accountModels.User{},
|
||||
&accountModels.SocialAccount{},
|
||||
&accountModels.Profile{},
|
||||
&accountModels.RefreshToken{},
|
||||
&blogModels.Category{},
|
||||
&blogModels.Tag{},
|
||||
&blogModels.Post{},
|
||||
&blogModels.CategoryView{},
|
||||
&blogModels.Comment{},
|
||||
&imageModels.Image{},
|
||||
&mcpModels.ToolRun{},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("auto migrate basarisiz: %w", err)
|
||||
}
|
||||
|
||||
log.Println("✅ AutoMigrate tamamlandı")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SeedSecurityDefaults dinamik guvenlik ayarlari icin baslangic adimini temsil eder.
|
||||
// Bu projede kalici ayar tablolari henuz olmadigi icin no-op tutulur.
|
||||
func SeedSecurityDefaults() error {
|
||||
log.Println("✅ SeedSecurityDefaults tamamlandı")
|
||||
return nil
|
||||
}
|
||||
51
configs/db_test.go
Normal file
51
configs/db_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestRunAutoMigrateRequiresDB(t *testing.T) {
|
||||
prev := DB
|
||||
DB = nil
|
||||
t.Cleanup(func() { DB = prev })
|
||||
|
||||
if err := RunAutoMigrate(); err == nil {
|
||||
t.Fatalf("expected error when DB is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAutoMigrateSuccess(t *testing.T) {
|
||||
prev := DB
|
||||
dsn := "file:" + t.Name() + "?mode=memory&cache=shared"
|
||||
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("sqlite open failed: %v", err)
|
||||
}
|
||||
DB = db
|
||||
t.Cleanup(func() {
|
||||
if sqlDB, err := db.DB(); err == nil {
|
||||
_ = sqlDB.Close()
|
||||
}
|
||||
DB = prev
|
||||
})
|
||||
|
||||
if err := RunAutoMigrate(); err != nil {
|
||||
t.Fatalf("RunAutoMigrate failed: %v", err)
|
||||
}
|
||||
|
||||
if !DB.Migrator().HasTable("users") {
|
||||
t.Fatalf("expected users table after migration")
|
||||
}
|
||||
if !DB.Migrator().HasTable("refresh_tokens") {
|
||||
t.Fatalf("expected refresh_tokens table after migration")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedSecurityDefaults(t *testing.T) {
|
||||
if err := SeedSecurityDefaults(); err != nil {
|
||||
t.Fatalf("SeedSecurityDefaults should not fail: %v", err)
|
||||
}
|
||||
}
|
||||
46
configs/redis.go
Normal file
46
configs/redis.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RDB global Redis istemcisi
|
||||
var RDB *redis.Client
|
||||
|
||||
// ConnectRedis .env'deki REDIS_URL ile Redis bağlantısını kurar
|
||||
// Format: redis://<user>:<password>@<host>:<port>/<db>
|
||||
func ConnectRedis() error {
|
||||
redisURL := os.Getenv("REDIS_URL")
|
||||
if redisURL == "" {
|
||||
return fmt.Errorf("REDIS_URL ortam değişkeni tanımlı değil")
|
||||
}
|
||||
|
||||
opts, err := redis.ParseURL(redisURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("REDIS_URL ayrıştırılamadı: %w", err)
|
||||
}
|
||||
|
||||
RDB = redis.NewClient(opts)
|
||||
|
||||
// Bağlantıyı test et
|
||||
ctx := context.Background()
|
||||
if _, err := RDB.Ping(ctx).Result(); err != nil {
|
||||
return fmt.Errorf("Redis'e bağlanılamadı: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("✅ Redis bağlantısı kuruldu: %s (db=%d)", opts.Addr, opts.DB)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseRedis Redis bağlantısını güvenli şekilde kapatır
|
||||
func CloseRedis() error {
|
||||
if RDB != nil {
|
||||
return RDB.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
45
configs/redis_test.go
Normal file
45
configs/redis_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
miniredis "github.com/alicebob/miniredis/v2"
|
||||
)
|
||||
|
||||
func TestConnectRedisMissingURL(t *testing.T) {
|
||||
t.Setenv("REDIS_URL", "")
|
||||
if err := ConnectRedis(); err == nil {
|
||||
t.Fatalf("expected error for missing REDIS_URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectRedisInvalidURL(t *testing.T) {
|
||||
t.Setenv("REDIS_URL", "%%%")
|
||||
if err := ConnectRedis(); err == nil {
|
||||
t.Fatalf("expected parse error for invalid REDIS_URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectRedisSuccessAndClose(t *testing.T) {
|
||||
mini, err := miniredis.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("miniredis start failed: %v", err)
|
||||
}
|
||||
defer mini.Close()
|
||||
|
||||
t.Setenv("REDIS_URL", "redis://"+mini.Addr()+"/0")
|
||||
|
||||
if err := ConnectRedis(); err != nil {
|
||||
t.Fatalf("ConnectRedis failed: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = CloseRedis() })
|
||||
|
||||
if pong, err := RDB.Ping(context.Background()).Result(); err != nil || pong != "PONG" {
|
||||
t.Fatalf("expected redis ping PONG, got %q err=%v", pong, err)
|
||||
}
|
||||
|
||||
if err := CloseRedis(); err != nil {
|
||||
t.Fatalf("CloseRedis failed: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user