diff --git a/store/migrate.go b/store/migrate.go index ed7e7ed..6be87d4 100644 --- a/store/migrate.go +++ b/store/migrate.go @@ -1,8 +1,8 @@ package store import ( - "bytes" "encoding/json" + "log/slog" "time" "go.etcd.io/bbolt" @@ -10,7 +10,8 @@ import ( "github.com/ayoisaiah/focus/internal/models" ) -func migrateSessions(tx *bbolt.Tx) error { +// Change session key to RFC3339Nano and update duration to nanoseconds +func migrateSessions_v1_4_0(tx *bbolt.Tx) error { bucket := tx.Bucket([]byte(sessionBucket)) cur := bucket.Cursor() @@ -23,14 +24,22 @@ func migrateSessions(tx *bbolt.Tx) error { return err } + // s.Duration was in minutes, but must now be changed to nanoseconds + s.Duration = time.Duration(s.Duration) * time.Minute + newKey := []byte(s.StartTime.Format(time.RFC3339Nano)) - err = bucket.Put(newKey, v) + err = cur.Delete() if err != nil { return err } - err = cur.Delete() + b, err := json.Marshal(s) + if err != nil { + return err + } + + err = bucket.Put(newKey, b) if err != nil { return err } @@ -39,33 +48,15 @@ func migrateSessions(tx *bbolt.Tx) error { return nil } -func migrateTimers(tx *bbolt.Tx) error { +// Delete all exisiting timers as it won't be possible to resume paused sessions +// after migrating the sessions +func migrateTimers_v1_4_0(tx *bbolt.Tx) error { bucket := tx.Bucket([]byte(timerBucket)) cur := bucket.Cursor() - type timer struct { - DateStarted time.Time `json:"date_started"` - } - - for k, v := cur.First(); k != nil; k, v = cur.Next() { - var t timer - - err := json.Unmarshal(v, &t) - if err != nil { - return err - } - - newKey := []byte(t.DateStarted.Format(time.RFC3339Nano)) - - v = bytes.Replace(v, []byte("date_started"), []byte("start_time"), 1) - - err = bucket.Put(newKey, v) - if err != nil { - return err - } - - err = cur.Delete() + for k, _ := cur.First(); k != nil; k, _ = cur.Next() { + err := cur.Delete() if err != nil { return err } @@ -74,11 +65,15 @@ func migrateTimers(tx *bbolt.Tx) error { return nil } -func (c *Client) migrate(tx *bbolt.Tx) error { - err := migrateSessions(tx) +func (c *Client) migrate_v1_4_0(tx *bbolt.Tx) error { + slog.Info( + "running db migrations to v1.4.0 format", + ) + + err := migrateSessions_v1_4_0(tx) if err != nil { return err } - return migrateTimers(tx) + return migrateTimers_v1_4_0(tx) } diff --git a/store/store.go b/store/store.go index 3fa216c..6e1bcf9 100644 --- a/store/store.go +++ b/store/store.go @@ -10,6 +10,7 @@ import ( "time" bolt "go.etcd.io/bbolt" + "golang.org/x/exp/slog" "github.com/ayoisaiah/focus/config" "github.com/ayoisaiah/focus/internal/models" @@ -292,11 +293,23 @@ func NewClient(dbFilePath string) (*Client, error) { bucket := tx.Bucket([]byte(focusBucket)) version := string(bucket.Get([]byte("version"))) - if version != config.Version { - err = c.migrate(tx) + // prior to v1.4.0, no version info was stored in the database + // if upgrading from earlier version, run migrations to meet + // current database format + // Does nothing for new users + if version == "" { + err = c.migrate_v1_4_0(tx) if err != nil { return err } + } + + if version != config.Version { + slog.Info( + "updating db version", + slog.Any("previous_version", version), + slog.Any("new_version", config.Version), + ) return bucket.Put([]byte("version"), []byte(config.Version)) }