Skip to content

Commit

Permalink
db: Generate new user UUIDs for 3->4 migration
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-goode committed Dec 24, 2024
1 parent 760e252 commit 63cc5c2
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 13 deletions.
31 changes: 18 additions & 13 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
mapset "github.com/deckarep/golang-set/v2"
"github.com/google/uuid"
"github.com/samber/mo"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
Expand Down Expand Up @@ -257,13 +258,25 @@ func Migrate(config *Config, dbPath mo.Option[string], db *gorm.DB, alreadyExist
}
if userVersion == 3 && targetUserVersion >= 4 {
// Version 3 to 4
// Split Users and Players
// Split Users and Players. We will replace each user's UUID (their
// primary key) with a new random one to avoid confusion between
// user UUIDs and player UUIDs. The easiest way to do this is to
// load all users into memory, remove them from the DB, then
// re-insert them. This is bad, and in the future we should (1)
// avoid changing primary keys at all and (2) perform migrations
// like this either entirely in SQL or in batches.

var v3Users []V3User
if err := tx.Preload("Clients").Find(&v3Users).Error; err != nil {
return err
}

if err := tx.Exec(`
DROP TABLE users;
DROP TABLE clients;
`).Error; err != nil {
return err
}
if err := tx.AutoMigrate(&V4User{}); err != nil {
return err
}
Expand All @@ -274,29 +287,21 @@ func Migrate(config *Config, dbPath mo.Option[string], db *gorm.DB, alreadyExist
return err
}

// Drop player_name and offline_uuid, they have non-null
// constraints and SQLite has no mechanism to remove them
if err := tx.Migrator().DropColumn(&V4User{}, "player_name"); err != nil {
return err
}
if err := tx.Migrator().DropColumn(&V4User{}, "offline_uuid"); err != nil {
return err
}

allUsernames := mapset.NewSet[string]()
for _, v3User := range v3Users {
allUsernames.Add(v3User.Username)
}

users := make([]V4User, 0, len(v3Users))
for _, v3User := range v3Users {
newUUID := uuid.New().String()
clients := make([]V4Client, 0, len(v3User.Clients))
for _, v3Client := range v3User.Clients {
clients = append(clients, V4Client{
UUID: v3Client.UUID,
ClientToken: v3Client.ClientToken,
Version: v3Client.Version,
UserUUID: v3Client.UserUUID,
UserUUID: newUUID,
PlayerUUID: MakeNullString(&v3Client.UserUUID),
})
}
Expand All @@ -317,12 +322,12 @@ func Migrate(config *Config, dbPath mo.Option[string], db *gorm.DB, alreadyExist
ServerID: v3User.ServerID,
FallbackPlayer: v3User.FallbackPlayer,
Clients: clients,
UserUUID: v3User.UUID,
UserUUID: newUUID,
}
user := V4User{
IsAdmin: v3User.IsAdmin,
IsLocked: v3User.IsLocked,
UUID: v3User.UUID,
UUID: newUUID,
Username: v3User.Username,
PasswordSalt: v3User.PasswordSalt,
PasswordHash: v3User.PasswordHash,
Expand Down
2 changes: 2 additions & 0 deletions db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ func (ts *TestSuite) testMigrate3To4(t *testing.T) {
assert.Nil(t, db.First(&v4User).Error)
assert.Equal(t, 1, len(v4User.Players))
player := v4User.Players[0]
assert.NotEqual(t, v3User.UUID, v4User.UUID)
assert.Equal(t, v3User.UUID, player.UUID)
assert.Equal(t, v3User.OfflineUUID, player.OfflineUUID)
assert.Equal(t, *UnmakeNullString(&v3User.SkinHash), *UnmakeNullString(&player.SkinHash))
assert.Equal(t, *UnmakeNullString(&v3User.CapeHash), *UnmakeNullString(&player.CapeHash))
Expand Down

0 comments on commit 63cc5c2

Please sign in to comment.