Move project files from uzdb/ subdirectory to root directory for cleaner project structure.
Changes:
- Move frontend/ to root
- Move internal/ to root
- Move build/ to root
- Move all config files (go.mod, wails.json, etc.) to root
- Remove redundant uzdb/ subdirectory nesting
Project structure is now:
├── frontend/ # React application
├── internal/ # Go backend
├── build/ # Wails build assets
├── doc/ # Design documentation
├── main.go # Entry point
└── ...
🤖 Generated with Qoder
129 lines
2.8 KiB
Go
129 lines
2.8 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"uzdb/internal/config"
|
|
"uzdb/internal/models"
|
|
)
|
|
|
|
var (
|
|
sqliteDB *gorm.DB
|
|
sqliteMu sync.RWMutex
|
|
)
|
|
|
|
// InitSQLite initializes the SQLite database for application data
|
|
func InitSQLite(dbPath string, cfg *config.DatabaseConfig) (*gorm.DB, error) {
|
|
sqliteMu.Lock()
|
|
defer sqliteMu.Unlock()
|
|
|
|
// Ensure directory exists
|
|
dir := filepath.Dir(dbPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return nil, fmt.Errorf("failed to create database directory: %w", err)
|
|
}
|
|
|
|
// Configure GORM logger
|
|
var gormLogger logger.Interface
|
|
if config.Get().IsDevelopment() {
|
|
gormLogger = logger.Default.LogMode(logger.Info)
|
|
} else {
|
|
gormLogger = logger.Default.LogMode(logger.Silent)
|
|
}
|
|
|
|
// Open SQLite connection
|
|
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
|
Logger: gormLogger,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open SQLite database: %w", err)
|
|
}
|
|
|
|
// Set connection pool settings
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get underlying DB: %w", err)
|
|
}
|
|
|
|
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
|
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
|
sqlDB.SetConnMaxLifetime(time.Duration(cfg.MaxLifetime) * time.Minute)
|
|
|
|
// Enable WAL mode for better concurrency
|
|
if err := db.Exec("PRAGMA journal_mode=WAL").Error; err != nil {
|
|
config.GetLogger().Warn("failed to enable WAL mode", zap.Error(err))
|
|
}
|
|
|
|
// Run migrations
|
|
if err := runMigrations(db); err != nil {
|
|
return nil, fmt.Errorf("migration failed: %w", err)
|
|
}
|
|
|
|
sqliteDB = db
|
|
|
|
config.GetLogger().Info("SQLite database initialized",
|
|
zap.String("path", dbPath),
|
|
zap.Int("max_open_conns", cfg.MaxOpenConns),
|
|
zap.Int("max_idle_conns", cfg.MaxIdleConns),
|
|
)
|
|
|
|
return db, nil
|
|
}
|
|
|
|
// runMigrations runs database migrations
|
|
func runMigrations(db *gorm.DB) error {
|
|
migrations := []interface{}{
|
|
&models.UserConnection{},
|
|
&models.QueryHistory{},
|
|
&models.SavedQuery{},
|
|
}
|
|
|
|
for _, model := range migrations {
|
|
if err := db.AutoMigrate(model); err != nil {
|
|
return fmt.Errorf("failed to migrate %T: %w", model, err)
|
|
}
|
|
}
|
|
|
|
config.GetLogger().Info("database migrations completed")
|
|
return nil
|
|
}
|
|
|
|
// GetSQLiteDB returns the SQLite database instance
|
|
func GetSQLiteDB() *gorm.DB {
|
|
sqliteMu.RLock()
|
|
defer sqliteMu.RUnlock()
|
|
return sqliteDB
|
|
}
|
|
|
|
// CloseSQLite closes the SQLite database connection
|
|
func CloseSQLite() error {
|
|
sqliteMu.Lock()
|
|
defer sqliteMu.Unlock()
|
|
|
|
if sqliteDB == nil {
|
|
return nil
|
|
}
|
|
|
|
sqlDB, err := sqliteDB.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := sqlDB.Close(); err != nil {
|
|
return fmt.Errorf("failed to close SQLite database: %w", err)
|
|
}
|
|
|
|
sqliteDB = nil
|
|
config.GetLogger().Info("SQLite database closed")
|
|
return nil
|
|
}
|