Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Add missing Targets to ui.target.order after seeding #536

Merged
merged 2 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions migration/v10/model/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ type Setting struct {
Value JSON `gorm:"type:json"`
}

//
// With updates the value of the Setting with the json representation
// of the `value` parameter.
func (r *Setting) With(value interface{}) (err error) {
r.Value, err = json.Marshal(value)
if err != nil {
err = liberr.Wrap(err)
}
return
}

//
// As unmarshalls the value of the Setting into the `ptr` parameter.
func (r *Setting) As(ptr interface{}) (err error) {
err = json.Unmarshal(r.Value, ptr)
if err != nil {
err = liberr.Wrap(err)
}
return
}

type Bucket struct {
Model
Path string `gorm:"<-:create;uniqueIndex"`
Expand Down
81 changes: 76 additions & 5 deletions seed/target.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package seed

import (
"container/list"
"encoding/json"
"errors"
"fmt"
Expand All @@ -10,6 +11,8 @@ import (
"gorm.io/gorm"
)

const UITargetOrder = "ui.target.order"

//
// Target applies Target seeds.
type Target struct {
Expand All @@ -34,7 +37,7 @@ func (r *Target) With(seed libseed.Seed) (err error) {
func (r *Target) Apply(db *gorm.DB) (err error) {
log.Info("Applying Targets", "count", len(r.targets))

ids := []uint{}
var seedIds []uint
for i := range r.targets {
t := r.targets[i]
target, found, fErr := r.find(db, "uuid = ?", t.UUID)
Expand Down Expand Up @@ -92,16 +95,84 @@ func (r *Target) Apply(db *gorm.DB) (err error) {
err = liberr.Wrap(result.Error)
return
}
ids = append(ids, target.ID)
seedIds = append(seedIds, target.ID)
}

err = r.reorder(db, seedIds)
if err != nil {
return
}
return
}

//
// reorder updates the value of the ui.target.order setting
// to add any missing target ids. (namely, newly added targets.)
func (r *Target) reorder(db *gorm.DB, seedIds []uint) (err error) {
targets := []model.Target{}
result := db.Find(&targets)
if result.Error != nil {
err = liberr.Wrap(err)
return
}
var targetIds []uint
for _, t := range targets {
targetIds = append(targetIds, t.ID)
}

s := model.Setting{}
result = db.First(&s, "key", UITargetOrder)
if result.Error != nil {
err = liberr.Wrap(err)
return
}
userOrder := []uint{}
_ = s.As(&userOrder)
_ = s.With(merge(userOrder, seedIds, targetIds))

value, _ := json.Marshal(ids)
uiOrder := model.Setting{Key: "ui.target.order", Value: value}
result := db.Where("key", "ui.target.order").Updates(uiOrder)
result = db.Where("key", UITargetOrder).Updates(s)
if result.Error != nil {
err = liberr.Wrap(err)
return
}
return
}

//
// merge new targets into the user's custom target order.
// params:
// userOrder: slice of target IDs in the user's desired order
// seedOrder: slice of target IDs in seedfile order
// ids: slice of ids of all the targets in the DB
func merge(userOrder []uint, seedOrder []uint, ids []uint) (mergedOrder []uint) {
ll := list.New()
known := make(map[uint]*list.Element)
for _, id := range userOrder {
known[id] = ll.PushBack(id)
}
for i, id := range seedOrder {
if _, found := known[id]; found {
continue
}
if i == 0 {
known[id] = ll.PushFront(id)
} else {
known[id] = ll.InsertAfter(id, known[seedOrder[i-1]])
}
}

for _, id := range ids {
if _, found := known[id]; found {
continue
}
ll.PushBack(id)
}

for ll.Len() > 0 {
e := ll.Front()
mergedOrder = append(mergedOrder, e.Value.(uint))
ll.Remove(e)
}

return
}
Expand Down
24 changes: 24 additions & 0 deletions seed/target_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package seed

import (
"github.com/onsi/gomega"
"testing"
)

func TestMerge(t *testing.T) {
g := gomega.NewWithT(t)

// the seed contains 10 targets in a given order, 3 of which are new
seedOrder := []uint{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// the user has set up a custom order for the 7 targets that already exist in the db
userOrder := []uint{6, 9, 5, 4, 1, 3, 2}
// the DB in total has 13 targets including the 3 newly seeded ones and 3 that were pre-existing
// in the DB not not represented in the ordering due to a previous bug.
allIds := []uint{11, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// we expect the newly added targets to be woven into the user's custom ordering, with any targets
// that had previously been dropped on the floor being added to the end of the ordering.
expectedOrder := []uint{6, 7, 8, 9, 10, 5, 4, 1, 3, 2, 11, 12, 13}

mergedOrder := merge(userOrder, seedOrder, allIds)
g.Expect(mergedOrder).To(gomega.Equal(expectedOrder))
}