From 850e4a27d8577f9e4135f8c9c96e2064fa13903d Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Mon, 24 Mar 2025 06:27:05 +0100 Subject: [PATCH] Backup databases before migrating --- database.go | 7 ++++--- migrator.go | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/database.go b/database.go index a075054..4122f0e 100644 --- a/database.go +++ b/database.go @@ -8,8 +8,9 @@ import ( // Db holds a connection to a SQLite database. type Db struct { - Db *sqlite.Conn - lock sync.Mutex + Db *sqlite.Conn + source string + lock sync.Mutex } // OpenDb opens a new connection to a SQLite database. @@ -21,7 +22,7 @@ func OpenDb(databaseSource string) (*Db, error) { if err != nil { return nil, err } - return &Db{Db: conn}, nil + return &Db{Db: conn, source: databaseSource}, nil } // Close closes the database. diff --git a/migrator.go b/migrator.go index 68bc011..7c4b258 100644 --- a/migrator.go +++ b/migrator.go @@ -4,6 +4,7 @@ import ( "fmt" "io/fs" "log" + "os" "path" "strconv" "strings" @@ -40,6 +41,20 @@ func (d *Db) MigrateDb(filesystem ReadDirFileFS, directory string) error { } log.Printf("Current version is %d, max migration version is %d", currentVersion, latestVersion) + // Create a backup if we're not on the latest version + if currentVersion != latestVersion && d.source != ":memory:" { + target := d.source + ".backup." + strconv.Itoa(currentVersion) + log.Printf("Creating backup of database to %s", target) + data, err := d.Db.Serialize("main") + if err != nil { + return fmt.Errorf("error serializing database: %v", err) + } + err = os.WriteFile(target, data, 0644) + if err != nil { + return fmt.Errorf("error writing backup: %v", err) + } + } + // If we are no up-to-date, bring the db up-to-date for currentVersion != latestVersion { targetVersion := currentVersion + 1