Skip to content

Commit

Permalink
Merge new targets into the existing ordering
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Lucidi <[email protected]>
  • Loading branch information
mansam committed Oct 24, 2023
1 parent 9564a2c commit 2403e86
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 17 deletions.
70 changes: 53 additions & 17 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 Down Expand Up @@ -36,6 +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))

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 @@ -93,9 +95,10 @@ func (r *Target) Apply(db *gorm.DB) (err error) {
err = liberr.Wrap(result.Error)
return
}
seedIds = append(seedIds, target.ID)
}

err = r.reorder(db)
err = r.reorder(db, seedIds)
if err != nil {
return
}
Expand All @@ -105,34 +108,28 @@ func (r *Target) Apply(db *gorm.DB) (err error) {
//
// 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) (err error) {
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
}
ordering := []uint{}
_ = s.As(&ordering)
known := make(map[uint]bool)
for _, id := range ordering {
known[id] = true
}
for _, t := range targets {
if !known[t.ID] {
ordering = append(ordering, t.ID)
}
}
err = s.With(ordering)
if err != nil {
return
}
userOrder := []uint{}
_ = s.As(&userOrder)
_ = s.With(merge(userOrder, seedIds, targetIds))

result = db.Where("key", UITargetOrder).Updates(s)
if result.Error != nil {
err = liberr.Wrap(err)
Expand All @@ -141,6 +138,45 @@ func (r *Target) reorder(db *gorm.DB) (err error) {
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
}

//
// Convenience method to find a Target.
func (r *Target) find(db *gorm.DB, conditions ...interface{}) (t *model.Target, found bool, err error) {
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))
}

0 comments on commit 2403e86

Please sign in to comment.