163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package utils
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"path/filepath"
 | 
						|
	"time"
 | 
						|
 | 
						|
	logger "git.site.quack-lab.dev/dave/cylogger"
 | 
						|
	"gorm.io/driver/sqlite"
 | 
						|
	"gorm.io/gorm"
 | 
						|
	gormlogger "gorm.io/gorm/logger"
 | 
						|
)
 | 
						|
 | 
						|
// dbLogger is a scoped logger for the utils/db package.
 | 
						|
var dbLogger = logger.Default.WithPrefix("utils/db")
 | 
						|
 | 
						|
type DB interface {
 | 
						|
	DB() *gorm.DB
 | 
						|
	Raw(sql string, args ...any) *gorm.DB
 | 
						|
	SaveFile(filePath string, fileData []byte) error
 | 
						|
	GetFile(filePath string) ([]byte, error)
 | 
						|
	GetAllFiles() ([]FileSnapshot, error)
 | 
						|
	RemoveAllFiles() error
 | 
						|
}
 | 
						|
 | 
						|
type FileSnapshot struct {
 | 
						|
	Date     time.Time `gorm:"primaryKey"`
 | 
						|
	FilePath string    `gorm:"primaryKey"`
 | 
						|
	FileData []byte    `gorm:"type:blob"`
 | 
						|
}
 | 
						|
 | 
						|
type DBWrapper struct {
 | 
						|
	db *gorm.DB
 | 
						|
}
 | 
						|
 | 
						|
var globalDB *DBWrapper
 | 
						|
 | 
						|
func GetDB() (DB, error) {
 | 
						|
	getDBLogger := dbLogger.WithPrefix("GetDB")
 | 
						|
	getDBLogger.Debug("Attempting to get database connection")
 | 
						|
	var err error
 | 
						|
 | 
						|
	dbFile := filepath.Join("data.sqlite")
 | 
						|
	getDBLogger.Debug("Opening database file: %q", dbFile)
 | 
						|
	getDBLogger.Trace("Database configuration: PrepareStmt=true, GORM logger=Silent")
 | 
						|
	db, err := gorm.Open(sqlite.Open(dbFile), &gorm.Config{
 | 
						|
		// SkipDefaultTransaction: true,
 | 
						|
		PrepareStmt: true,
 | 
						|
		Logger:      gormlogger.Default.LogMode(gormlogger.Silent),
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		getDBLogger.Error("Failed to open database file %q: %v", dbFile, err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	getDBLogger.Debug("Database opened successfully, running auto migration for FileSnapshot model")
 | 
						|
	if err := db.AutoMigrate(&FileSnapshot{}); err != nil {
 | 
						|
		getDBLogger.Error("Auto migration failed for FileSnapshot model: %v", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	getDBLogger.Info("Database initialized and migrated successfully")
 | 
						|
 | 
						|
	globalDB = &DBWrapper{db: db}
 | 
						|
	getDBLogger.Debug("Database wrapper initialized and cached globally")
 | 
						|
	return globalDB, nil
 | 
						|
}
 | 
						|
 | 
						|
// Just a wrapper
 | 
						|
func (db *DBWrapper) Raw(sql string, args ...any) *gorm.DB {
 | 
						|
	rawLogger := dbLogger.WithPrefix("Raw").WithField("sql", sql)
 | 
						|
	rawLogger.Debug("Executing raw SQL query with args: %v", args)
 | 
						|
	return db.db.Raw(sql, args...)
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) DB() *gorm.DB {
 | 
						|
	dbLogger.WithPrefix("DB").Debug("Returning GORM DB instance")
 | 
						|
	return db.db
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) FileExists(filePath string) (bool, error) {
 | 
						|
	fileExistsLogger := dbLogger.WithPrefix("FileExists").WithField("filePath", filePath)
 | 
						|
	fileExistsLogger.Debug("Checking if file exists in database")
 | 
						|
	var count int64
 | 
						|
	err := db.db.Model(&FileSnapshot{}).Where("file_path = ?", filePath).Count(&count).Error
 | 
						|
	if err != nil {
 | 
						|
		fileExistsLogger.Error("Error checking if file exists: %v", err)
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	fileExistsLogger.Debug("File exists: %t", count > 0)
 | 
						|
	return count > 0, err
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) SaveFile(filePath string, fileData []byte) error {
 | 
						|
	saveFileLogger := dbLogger.WithPrefix("SaveFile").WithField("filePath", filePath).WithField("dataSize", len(fileData))
 | 
						|
	saveFileLogger.Debug("Attempting to save file to database")
 | 
						|
	saveFileLogger.Trace("File data length: %d", len(fileData))
 | 
						|
 | 
						|
	exists, err := db.FileExists(filePath)
 | 
						|
	if err != nil {
 | 
						|
		saveFileLogger.Error("Error checking if file exists: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if exists {
 | 
						|
		saveFileLogger.Debug("File already exists in database, skipping save to avoid overwriting original snapshot")
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	saveFileLogger.Debug("Creating new file snapshot in database")
 | 
						|
	err = db.db.Create(&FileSnapshot{
 | 
						|
		Date:     time.Now(),
 | 
						|
		FilePath: filePath,
 | 
						|
		FileData: fileData,
 | 
						|
	}).Error
 | 
						|
	if err != nil {
 | 
						|
		saveFileLogger.Error("Failed to create file snapshot: %v", err)
 | 
						|
	} else {
 | 
						|
		saveFileLogger.Info("File successfully saved to database")
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) GetFile(filePath string) ([]byte, error) {
 | 
						|
	getFileLogger := dbLogger.WithPrefix("GetFile").WithField("filePath", filePath)
 | 
						|
	getFileLogger.Debug("Getting file from database")
 | 
						|
	var fileSnapshot FileSnapshot
 | 
						|
	err := db.db.Model(&FileSnapshot{}).Where("file_path = ?", filePath).First(&fileSnapshot).Error
 | 
						|
	if err != nil {
 | 
						|
		if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
						|
			getFileLogger.Debug("File not found in database: %v", err)
 | 
						|
		} else {
 | 
						|
			getFileLogger.Warning("Failed to get file from database: %v", err)
 | 
						|
		}
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	getFileLogger.Debug("File found in database")
 | 
						|
	getFileLogger.Trace("Retrieved file data length: %d", len(fileSnapshot.FileData))
 | 
						|
	return fileSnapshot.FileData, nil
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) GetAllFiles() ([]FileSnapshot, error) {
 | 
						|
	getAllFilesLogger := dbLogger.WithPrefix("GetAllFiles")
 | 
						|
	getAllFilesLogger.Debug("Getting all files from database")
 | 
						|
	var fileSnapshots []FileSnapshot
 | 
						|
	err := db.db.Model(&FileSnapshot{}).Find(&fileSnapshots).Error
 | 
						|
	if err != nil {
 | 
						|
		getAllFilesLogger.Error("Failed to get all files from database: %v", err)
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	getAllFilesLogger.Debug("Found %d files in database", len(fileSnapshots))
 | 
						|
	getAllFilesLogger.Trace("File snapshots retrieved: %v", fileSnapshots)
 | 
						|
	return fileSnapshots, nil
 | 
						|
}
 | 
						|
 | 
						|
func (db *DBWrapper) RemoveAllFiles() error {
 | 
						|
	removeAllFilesLogger := dbLogger.WithPrefix("RemoveAllFiles")
 | 
						|
	removeAllFilesLogger.Debug("Removing all files from database")
 | 
						|
	err := db.db.Exec("DELETE FROM file_snapshots").Error
 | 
						|
	if err != nil {
 | 
						|
		removeAllFilesLogger.Error("Failed to remove all files from database: %v", err)
 | 
						|
	} else {
 | 
						|
		removeAllFilesLogger.Debug("All files removed from database")
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 |