sqlite.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package dbmanager
  2. import (
  3. "fmt"
  4. "os"
  5. "gorm.io/driver/sqlite"
  6. "gorm.io/gorm"
  7. "gorm.io/gorm/logger"
  8. )
  9. // SQLiteManager implements the DbManager interface for SQLite using GORM
  10. type SQLiteManager struct {
  11. db *gorm.DB
  12. dsn string
  13. }
  14. // NewSQLiteManager initializes a new SQLiteManager
  15. func NewSQLiteManager(dataSourceName string) (*SQLiteManager, error) {
  16. // First check if the database file exists
  17. isNewDb := !fileExists(dataSourceName)
  18. if isNewDb {
  19. // Create the database file if it doesn't exist
  20. file, err := os.Create(dataSourceName)
  21. if err != nil {
  22. return nil, fmt.Errorf("failed to create SQLite database file: %w", err)
  23. }
  24. defer file.Close()
  25. }
  26. // Open SQLite database with GORM and SQLite-specific configuration
  27. db, err := gorm.Open(sqlite.Open(dataSourceName), &gorm.Config{
  28. Logger: logger.Default.LogMode(logger.Silent),
  29. // Set DisableForeignKeyConstraintWhenMigrating to true to avoid foreign key issues during migration
  30. DisableForeignKeyConstraintWhenMigrating: true,
  31. })
  32. if err != nil {
  33. return nil, fmt.Errorf("failed to connect to SQLite database: %w", err)
  34. }
  35. // Enable foreign keys in SQLite after migrations
  36. db.Exec("PRAGMA foreign_keys = ON")
  37. return &SQLiteManager{
  38. db: db,
  39. dsn: dataSourceName,
  40. }, nil
  41. }
  42. // fileExists checks if a file exists
  43. func fileExists(filename string) bool {
  44. _, err := os.Stat(filename)
  45. return !os.IsNotExist(err)
  46. }
  47. // GetDB returns the GORM database instance
  48. func (m *SQLiteManager) GetDB() *gorm.DB {
  49. return m.db
  50. }
  51. // Connect establishes a connection to the SQLite database
  52. func (m *SQLiteManager) Connect() error {
  53. // Connection is already established in NewSQLiteManager
  54. return nil
  55. }
  56. // Disconnect closes the connection to the SQLite database
  57. func (m *SQLiteManager) Disconnect() error {
  58. sqlDB, err := m.db.DB()
  59. if err != nil {
  60. return err
  61. }
  62. return sqlDB.Close()
  63. }
  64. // Migrate runs auto migration for the provided models
  65. func (m *SQLiteManager) Migrate(models ...interface{}) error {
  66. // Check if database file exists before
  67. isNewDb := !fileExists(m.dsn)
  68. // SQLite has limitations with ALTER TABLE for adding NOT NULL columns
  69. // For a new database, we can just create tables directly
  70. if isNewDb {
  71. return m.db.AutoMigrate(models...)
  72. }
  73. // For existing database, we need a more careful approach to avoid NOT NULL errors
  74. // Try to create tables that don't exist
  75. migrator := m.db.Migrator()
  76. for _, model := range models {
  77. // Check if the table exists
  78. if !migrator.HasTable(model) {
  79. // If table doesn't exist, create it
  80. if err := migrator.CreateTable(model); err != nil {
  81. return fmt.Errorf("failed to create table for %T: %w", model, err)
  82. }
  83. }
  84. }
  85. // Re-enable foreign key constraints
  86. m.db.Exec("PRAGMA foreign_keys = ON")
  87. return nil
  88. }