package utils import ( "fmt" "path/filepath" "time" "git.site.quack-lab.dev/dave/cylogger" "gorm.io/driver/sqlite" "gorm.io/gorm" ) 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 db *DBWrapper func GetDB() (DB, error) { var err error dbFile := filepath.Join("data.sqlite") db, err := gorm.Open(sqlite.Open(dbFile), &gorm.Config{ // SkipDefaultTransaction: true, PrepareStmt: true, // Logger: gormlogger.Default.LogMode(gormlogger.Silent), }) if err != nil { return nil, err } db.AutoMigrate(&FileSnapshot{}) return &DBWrapper{db: db}, nil } // Just a wrapper func (db *DBWrapper) Raw(sql string, args ...any) *gorm.DB { return db.db.Raw(sql, args...) } func (db *DBWrapper) DB() *gorm.DB { return db.db } func (db *DBWrapper) FileExists(filePath string) (bool, error) { var count int64 err := db.db.Model(&FileSnapshot{}).Where("file_path = ?", filePath).Count(&count).Error return count > 0, err } func (db *DBWrapper) SaveFile(filePath string, fileData []byte) error { log := cylogger.Default.WithPrefix(fmt.Sprintf("SaveFile: %q", filePath)) exists, err := db.FileExists(filePath) if err != nil { log.Error("Error checking if file exists: %v", err) return err } log.Debug("File exists: %t", exists) // Nothing to do, file already exists if exists { log.Debug("File already exists, skipping save") return nil } log.Debug("Saving file to database") return db.db.Create(&FileSnapshot{ Date: time.Now(), FilePath: filePath, FileData: fileData, }).Error } func (db *DBWrapper) GetFile(filePath string) ([]byte, error) { log := cylogger.Default.WithPrefix(fmt.Sprintf("GetFile: %q", filePath)) log.Debug("Getting file from database") var fileSnapshot FileSnapshot err := db.db.Model(&FileSnapshot{}).Where("file_path = ?", filePath).First(&fileSnapshot).Error if err != nil { return nil, err } log.Debug("File found in database") return fileSnapshot.FileData, nil } func (db *DBWrapper) GetAllFiles() ([]FileSnapshot, error) { log := cylogger.Default.WithPrefix("GetAllFiles") log.Debug("Getting all files from database") var fileSnapshots []FileSnapshot err := db.db.Model(&FileSnapshot{}).Find(&fileSnapshots).Error if err != nil { return nil, err } log.Debug("Found %d files in database", len(fileSnapshots)) return fileSnapshots, nil } func (db *DBWrapper) RemoveAllFiles() error { log := cylogger.Default.WithPrefix("RemoveAllFiles") log.Debug("Removing all files from database") err := db.db.Exec("DELETE FROM file_snapshots").Error if err != nil { return err } log.Debug("All files removed from database") return nil }