47 lines
1.6 KiB
Go
47 lines
1.6 KiB
Go
package domain
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// ErrReorderInvalidIDSet means ordered_ids is not an exact permutation of the current entities in scope.
|
|
var ErrReorderInvalidIDSet = errors.New("ordered_ids must list every id in this scope exactly once, with no duplicates")
|
|
|
|
// ReorderIDsRequest is the body for batch reorder endpoints (drag-and-drop UI).
|
|
// Send "ordered_ids": [] in display order. Must include every id in that scope (use GET list) when there is at least one entity.
|
|
type ReorderIDsRequest struct {
|
|
OrderedIDs []int64 `json:"ordered_ids"`
|
|
}
|
|
|
|
// ValidateReorderPermutation checks that ordered contains the same multiset of ids as expected (new order vs current scope).
|
|
func ValidateReorderPermutation(ordered, expected []int64) error {
|
|
if len(expected) == 0 {
|
|
if len(ordered) == 0 {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("%w: no entities exist in this scope", ErrReorderInvalidIDSet)
|
|
}
|
|
if len(ordered) != len(expected) {
|
|
return fmt.Errorf("%w: want %d ids, got %d", ErrReorderInvalidIDSet, len(expected), len(ordered))
|
|
}
|
|
seen := make(map[int64]struct{}, len(ordered))
|
|
for _, id := range ordered {
|
|
if _, dup := seen[id]; dup {
|
|
return fmt.Errorf("%w: duplicate id %d", ErrReorderInvalidIDSet, id)
|
|
}
|
|
seen[id] = struct{}{}
|
|
}
|
|
a := append([]int64(nil), expected...)
|
|
b := append([]int64(nil), ordered...)
|
|
sort.Slice(a, func(i, j int) bool { return a[i] < a[j] })
|
|
sort.Slice(b, func(i, j int) bool { return b[i] < b[j] })
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return fmt.Errorf("%w: id set does not match current scope", ErrReorderInvalidIDSet)
|
|
}
|
|
}
|
|
return nil
|
|
}
|