This commit is contained in:
Erik Winter 2024-10-03 07:32:48 +02:00
parent cd784f999d
commit 841b866e3f
3 changed files with 157 additions and 6 deletions

View File

@ -9,13 +9,15 @@ import (
)
type Memory struct {
events map[string]item.Event
mutex sync.RWMutex
events map[string]item.Event
localIDs map[int]string
mutex sync.RWMutex
}
func NewMemory() *Memory {
return &Memory{
events: make(map[string]item.Event),
events: make(map[string]item.Event),
localIDs: make(map[int]string),
}
}
@ -30,7 +32,23 @@ func (r *Memory) Find(id string) (item.Event, error) {
return event, nil
}
func (r *Memory) FindAll() ([]item.Event, error) {
func (r *Memory) FindByLocal(localID int) (item.Event, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
id, exists := r.localIDs[localID]
if !exists {
return item.Event{}, errors.New("event not found")
}
event, exists := r.events[id]
if !exists {
return item.Event{}, errors.New("id an localid mismatch")
}
return event, nil
}
func (r *Memory) FindAll() (map[int]string, []item.Event, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
@ -42,14 +60,24 @@ func (r *Memory) FindAll() ([]item.Event, error) {
return events[i].ID < events[j].ID
})
return events, nil
return r.localIDs, events, nil
}
func (r *Memory) Store(e item.Event) error {
r.mutex.Lock()
defer r.mutex.Unlock()
if _, exists := r.events[e.ID]; !exists {
cur := make([]int, 0, len(r.localIDs))
for i := range r.localIDs {
cur = append(cur, i)
}
localID := NextLocalID(cur)
r.localIDs[localID] = e.ID
}
r.events[e.ID] = e
return nil
}
@ -61,5 +89,12 @@ func (r *Memory) Delete(id string) error {
return errors.New("event not found")
}
delete(r.events, id)
for localID, eventID := range r.localIDs {
if id == eventID {
delete(r.localIDs, localID)
}
}
return nil
}

View File

@ -1,6 +1,10 @@
package storage
import "go-mod.ewintr.nl/planner/item"
import (
"sort"
"go-mod.ewintr.nl/planner/item"
)
type EventRepo interface {
Store(event item.Event) error
@ -8,3 +12,39 @@ type EventRepo interface {
FindAll() ([]item.Event, error)
Delete(id string) error
}
func NextLocalID(used []int) int {
if len(used) == 0 {
return 1
}
sort.Ints(used)
usedMax := 1
for _, u := range used {
if u > usedMax {
usedMax = u
}
}
var limit int
for limit = 1; limit <= len(used) || limit < usedMax; limit *= 10 {
}
newId := used[len(used)-1] + 1
if newId < limit {
return newId
}
usedMap := map[int]bool{}
for _, u := range used {
usedMap[u] = true
}
for i := 1; i < limit; i++ {
if _, ok := usedMap[i]; !ok {
return i
}
}
return limit
}

View File

@ -0,0 +1,76 @@
package storage_test
import (
"testing"
"go-mod.ewintr.nl/planner/plan/storage"
)
func TestNextLocalId(t *testing.T) {
for _, tc := range []struct {
name string
used []int
exp int
}{
{
name: "empty",
used: []int{},
exp: 1,
},
{
name: "not empty",
used: []int{5},
exp: 6,
},
{
name: "multiple",
used: []int{2, 3, 4},
exp: 5,
},
{
name: "holes",
used: []int{1, 5, 8},
exp: 9,
},
{
name: "expand limit",
used: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
exp: 11,
},
{
name: "wrap if possible",
used: []int{8, 9},
exp: 1,
},
{
name: "find hole",
used: []int{1, 2, 3, 4, 5, 7, 8, 9},
exp: 6,
},
{
name: "dont wrap if expanded before",
used: []int{15, 16},
exp: 17,
},
{
name: "do wrap if expanded limit is reached",
used: []int{99},
exp: 1,
},
{
name: "sync bug",
used: []int{151, 956, 955, 150, 154, 155, 145, 144,
136, 152, 148, 146, 934, 149, 937, 135, 140, 139,
143, 137, 153, 939, 138, 953, 147, 141, 938, 142,
},
exp: 957,
},
} {
t.Run(tc.name, func(t *testing.T) {
act := storage.NextLocalID(tc.used)
if tc.exp != act {
t.Errorf("exp %v, got %v", tc.exp, act)
}
})
}
}