refactor: tribe - cursor pagination (#60)
Reviewed-on: twhelp/corev3#60
This commit is contained in:
parent
6a4e896cd4
commit
25efaacc01
|
@ -111,17 +111,25 @@ func (repo *TribeBunRepository) UpdateDominance(ctx context.Context, serverKey s
|
|||
return nil
|
||||
}
|
||||
|
||||
func (repo *TribeBunRepository) List(ctx context.Context, params domain.ListTribesParams) (domain.Tribes, error) {
|
||||
func (repo *TribeBunRepository) List(
|
||||
ctx context.Context,
|
||||
params domain.ListTribesParams,
|
||||
) (domain.ListTribesResult, error) {
|
||||
var tribes bunmodel.Tribes
|
||||
|
||||
if err := repo.db.NewSelect().
|
||||
Model(&tribes).
|
||||
Apply(listTribesParamsApplier{params: params}.apply).
|
||||
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, fmt.Errorf("couldn't select tribes from the db: %w", err)
|
||||
return domain.ListTribesResult{}, fmt.Errorf("couldn't select tribes from the db: %w", err)
|
||||
}
|
||||
|
||||
return tribes.ToDomain()
|
||||
converted, err := tribes.ToDomain()
|
||||
if err != nil {
|
||||
return domain.ListTribesResult{}, err
|
||||
}
|
||||
|
||||
return domain.NewListTribesResult(separateListResultAndNext(converted, params.Limit()))
|
||||
}
|
||||
|
||||
func (repo *TribeBunRepository) Delete(ctx context.Context, serverKey string, ids ...int) error {
|
||||
|
@ -153,10 +161,6 @@ func (a listTribesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
q = q.Where("tribe.id IN (?)", bun.In(ids))
|
||||
}
|
||||
|
||||
if idGT := a.params.IDGT(); idGT.Valid {
|
||||
q = q.Where("tribe.id > ?", idGT.Value)
|
||||
}
|
||||
|
||||
if serverKeys := a.params.ServerKeys(); len(serverKeys) > 0 {
|
||||
q = q.Where("tribe.server_key IN (?)", bun.In(serverKeys))
|
||||
}
|
||||
|
@ -184,5 +188,93 @@ func (a listTribesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
}
|
||||
}
|
||||
|
||||
return q.Limit(a.params.Limit()).Offset(a.params.Offset())
|
||||
return q.Limit(a.params.Limit() + 1).Apply(a.applyCursor)
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (a listTribesParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
if a.params.Cursor().IsZero() {
|
||||
return q
|
||||
}
|
||||
|
||||
q.WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
cursorID := a.params.Cursor().ID()
|
||||
cursorServerKey := a.params.Cursor().ServerKey()
|
||||
|
||||
sort := a.params.Sort()
|
||||
sortLen := len(sort)
|
||||
|
||||
// based on https://github.com/prisma/prisma/issues/19159#issuecomment-1713389245
|
||||
|
||||
switch {
|
||||
case sortLen == 1:
|
||||
switch sort[0] {
|
||||
case domain.TribeSortIDASC:
|
||||
q = q.Where("tribe.id >= ?", cursorID)
|
||||
case domain.TribeSortIDDESC:
|
||||
q = q.Where("tribe.id <= ?", cursorID)
|
||||
case domain.TribeSortServerKeyASC, domain.TribeSortServerKeyDESC:
|
||||
return q.Err(errSortNoUniqueField)
|
||||
default:
|
||||
return q.Err(errUnsupportedSortValue)
|
||||
}
|
||||
case sortLen > 1:
|
||||
q.WhereGroup(" OR ", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
switch sort[0] {
|
||||
case domain.TribeSortIDASC:
|
||||
q = q.Where("tribe.id > ?", cursorID)
|
||||
case domain.TribeSortIDDESC:
|
||||
q = q.Where("tribe.id < ?", cursorID)
|
||||
case domain.TribeSortServerKeyASC:
|
||||
q = q.Where("tribe.server_key > ?", cursorServerKey)
|
||||
case domain.TribeSortServerKeyDESC:
|
||||
q = q.Where("tribe.server_key < ?", cursorServerKey)
|
||||
default:
|
||||
return q.Err(errUnsupportedSortValue)
|
||||
}
|
||||
|
||||
for i := 1; i < sortLen; i++ {
|
||||
q.WhereGroup(" OR ", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
current := sort[i]
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
s := sort[j]
|
||||
|
||||
switch s {
|
||||
case domain.TribeSortIDASC,
|
||||
domain.TribeSortIDDESC:
|
||||
q = q.Where("tribe.id = ?", cursorID)
|
||||
case domain.TribeSortServerKeyASC,
|
||||
domain.TribeSortServerKeyDESC:
|
||||
q = q.Where("tribe.server_key = ?", cursorServerKey)
|
||||
default:
|
||||
return q.Err(errUnsupportedSortValue)
|
||||
}
|
||||
}
|
||||
|
||||
switch current {
|
||||
case domain.TribeSortIDASC:
|
||||
q = q.Where("tribe.id >= ?", cursorID)
|
||||
case domain.TribeSortIDDESC:
|
||||
q = q.Where("tribe.id <= ?", cursorID)
|
||||
case domain.TribeSortServerKeyASC:
|
||||
q = q.Where("tribe.server_key >= ?", cursorServerKey)
|
||||
case domain.TribeSortServerKeyDESC:
|
||||
q = q.Where("tribe.server_key <= ?", cursorServerKey)
|
||||
default:
|
||||
return q.Err(errUnsupportedSortValue)
|
||||
}
|
||||
|
||||
return q
|
||||
})
|
||||
}
|
||||
|
||||
return q
|
||||
})
|
||||
}
|
||||
|
||||
return q
|
||||
})
|
||||
|
||||
return q
|
||||
}
|
||||
|
|
|
@ -129,6 +129,8 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
|
|||
assert.True(t, slices.IsSortedFunc(servers, func(a, b domain.Server) int {
|
||||
return cmp.Compare(a.Key(), b.Key())
|
||||
}))
|
||||
assert.False(t, res.Self().IsZero())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
|
@ -486,6 +488,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
|
|||
assertResult: func(t *testing.T, params domain.ListServersParams, res domain.ListServersResult) {
|
||||
t.Helper()
|
||||
assert.Len(t, res.Servers(), params.Limit())
|
||||
assert.False(t, res.Next().IsZero())
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
|
|
|
@ -24,7 +24,7 @@ type serverRepository interface {
|
|||
type tribeRepository interface {
|
||||
CreateOrUpdate(ctx context.Context, params ...domain.CreateTribeParams) error
|
||||
UpdateDominance(ctx context.Context, serverKey string, numPlayerVillages int) error
|
||||
List(ctx context.Context, params domain.ListTribesParams) (domain.Tribes, error)
|
||||
List(ctx context.Context, params domain.ListTribesParams) (domain.ListTribesResult, error)
|
||||
Delete(ctx context.Context, serverKey string, ids ...int) error
|
||||
}
|
||||
|
||||
|
|
|
@ -91,8 +91,9 @@ func testTribeSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repos
|
|||
Valid: true,
|
||||
}))
|
||||
|
||||
tribes, err := repos.tribe.List(ctx, listTribesParams)
|
||||
res, err := repos.tribe.List(ctx, listTribesParams)
|
||||
require.NoError(t, err)
|
||||
tribes := res.Tribes()
|
||||
require.NotEmpty(t, tribes)
|
||||
|
||||
date := time.Now()
|
||||
|
|
|
@ -3,7 +3,6 @@ package adapter_test
|
|||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"testing"
|
||||
|
@ -39,8 +38,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
require.NoError(t, listParams.SetIDs(ids))
|
||||
require.NoError(t, listParams.SetServerKeys([]string{params[0].ServerKey()}))
|
||||
|
||||
tribes, err := repos.tribe.List(ctx, listParams)
|
||||
res, err := repos.tribe.List(ctx, listParams)
|
||||
require.NoError(t, err)
|
||||
tribes := res.Tribes()
|
||||
assert.Len(t, tribes, len(params))
|
||||
for i, p := range params {
|
||||
idx := slices.IndexFunc(tribes, func(tribe domain.Tribe) bool {
|
||||
|
@ -150,10 +150,10 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
}))
|
||||
require.NoError(t, listTribesParams.SetServerKeys([]string{tt.serverKey}))
|
||||
|
||||
tribes, err := repos.tribe.List(ctx, listTribesParams)
|
||||
res, err := repos.tribe.List(ctx, listTribesParams)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, tribes)
|
||||
for _, tr := range tribes {
|
||||
assert.NotEmpty(t, res)
|
||||
for _, tr := range res.Tribes() {
|
||||
if tt.numPlayerVillages == 0 {
|
||||
assert.InDelta(t, 0.0, tr.Dominance(), 0.001)
|
||||
continue
|
||||
|
@ -170,17 +170,11 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
|
||||
repos := newRepos(t)
|
||||
|
||||
tribes, listTribesErr := repos.tribe.List(ctx, domain.NewListTribesParams())
|
||||
require.NoError(t, listTribesErr)
|
||||
require.NotEmpty(t, tribes)
|
||||
randTribe := tribes[0]
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
params func(t *testing.T) domain.ListTribesParams
|
||||
assertTribes func(t *testing.T, params domain.ListTribesParams, tribes domain.Tribes)
|
||||
assertResult func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult)
|
||||
assertError func(t *testing.T, err error)
|
||||
assertTotal func(t *testing.T, params domain.ListTribesParams, total int)
|
||||
}{
|
||||
{
|
||||
name: "OK: default params",
|
||||
|
@ -188,8 +182,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
t.Helper()
|
||||
return domain.NewListTribesParams()
|
||||
},
|
||||
assertTribes: func(t *testing.T, _ domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, len(tribes))
|
||||
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||
return cmp.Or(
|
||||
|
@ -197,15 +192,13 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
cmp.Compare(a.ID(), b.ID()),
|
||||
)
|
||||
}))
|
||||
assert.False(t, res.Self().IsZero())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: sort=[serverKey DESC, id DESC]",
|
||||
|
@ -215,8 +208,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
require.NoError(t, params.SetSort([]domain.TribeSort{domain.TribeSortServerKeyDESC, domain.TribeSortIDDESC}))
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, _ domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, len(tribes))
|
||||
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||
return cmp.Or(
|
||||
|
@ -229,26 +223,32 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("OK: ids=[%d] serverKeys=[%s]", randTribe.ID(), randTribe.ServerKey()),
|
||||
name: "OK: ids serverKeys",
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
|
||||
res, err := repos.tribe.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, len(res.Tribes()))
|
||||
randTribe := res.Tribes()[0]
|
||||
|
||||
require.NoError(t, params.SetIDs([]int{randTribe.ID()}))
|
||||
require.NoError(t, params.SetServerKeys([]string{randTribe.ServerKey()}))
|
||||
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, params domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
|
||||
ids := params.IDs()
|
||||
serverKeys := params.ServerKeys()
|
||||
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, tribes)
|
||||
for _, tr := range tribes {
|
||||
assert.True(t, slices.Contains(ids, tr.ID()))
|
||||
assert.True(t, slices.Contains(serverKeys, tr.ServerKey()))
|
||||
|
@ -258,37 +258,6 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("OK: idGT=%d", randTribe.ID()),
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
params := domain.NewListTribesParams()
|
||||
require.NoError(t, params.SetIDGT(domain.NullInt{
|
||||
Value: randTribe.ID(),
|
||||
Valid: true,
|
||||
}))
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, params domain.ListTribesParams, tribes domain.Tribes) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, tribes)
|
||||
for _, tr := range tribes {
|
||||
assert.Greater(t, tr.ID(), params.IDGT().Value, tr.ID())
|
||||
}
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: deleted=true",
|
||||
|
@ -301,8 +270,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
}))
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, _ domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, tribes)
|
||||
for _, s := range tribes {
|
||||
assert.True(t, s.IsDeleted())
|
||||
|
@ -312,10 +282,6 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: deleted=false",
|
||||
|
@ -328,8 +294,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
}))
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, _ domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, tribes)
|
||||
for _, s := range tribes {
|
||||
assert.False(t, s.IsDeleted())
|
||||
|
@ -339,31 +306,146 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: offset=1 limit=2",
|
||||
name: "OK: cursor serverKeys sort=[id ASC]",
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
require.NoError(t, params.SetOffset(1))
|
||||
require.NoError(t, params.SetLimit(2))
|
||||
|
||||
res, err := repos.tribe.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(res.Tribes()), 2)
|
||||
|
||||
require.NoError(t, params.SetSort([]domain.TribeSort{domain.TribeSortIDASC}))
|
||||
require.NoError(t, params.SetServerKeys([]string{res.Tribes()[1].ServerKey()}))
|
||||
require.NoError(t, params.SetCursor(domaintest.NewTribeCursor(t, func(cfg *domaintest.TribeCursorConfig) {
|
||||
cfg.ID = res.Tribes()[1].ID()
|
||||
})))
|
||||
|
||||
return params
|
||||
},
|
||||
assertTribes: func(t *testing.T, params domain.ListTribesParams, tribes domain.Tribes) {
|
||||
assertResult: func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
assert.Len(t, tribes, params.Limit())
|
||||
|
||||
serverKeys := params.ServerKeys()
|
||||
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, len(tribes))
|
||||
for _, tr := range res.Tribes() {
|
||||
assert.GreaterOrEqual(t, tr.ID(), params.Cursor().ID())
|
||||
assert.True(t, slices.Contains(serverKeys, tr.ServerKey()))
|
||||
}
|
||||
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||
return cmp.Compare(a.ID(), b.ID())
|
||||
}))
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
assertTotal: func(t *testing.T, _ domain.ListTribesParams, total int) {
|
||||
},
|
||||
{
|
||||
name: "OK: cursor sort=[serverKey ASC, id ASC]",
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
assert.NotEmpty(t, total)
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
require.NoError(t, params.SetSort([]domain.TribeSort{
|
||||
domain.TribeSortServerKeyASC,
|
||||
domain.TribeSortIDASC,
|
||||
}))
|
||||
|
||||
res, err := repos.tribe.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(res.Tribes()), 2)
|
||||
|
||||
require.NoError(t, params.SetCursor(domaintest.NewTribeCursor(t, func(cfg *domaintest.TribeCursorConfig) {
|
||||
cfg.ID = res.Tribes()[1].ID()
|
||||
cfg.ServerKey = res.Tribes()[1].ServerKey()
|
||||
})))
|
||||
|
||||
return params
|
||||
},
|
||||
assertResult: func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, len(tribes))
|
||||
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||
return cmp.Or(
|
||||
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||
cmp.Compare(a.ID(), b.ID()),
|
||||
)
|
||||
}))
|
||||
assert.GreaterOrEqual(t, tribes[0].ID(), params.Cursor().ID())
|
||||
for _, tr := range res.Tribes() {
|
||||
assert.GreaterOrEqual(t, tr.ServerKey(), params.Cursor().ServerKey())
|
||||
}
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: cursor sort=[serverKey DESC, id DESC]",
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
require.NoError(t, params.SetSort([]domain.TribeSort{
|
||||
domain.TribeSortServerKeyDESC,
|
||||
domain.TribeSortIDDESC,
|
||||
}))
|
||||
|
||||
res, err := repos.tribe.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, len(res.Tribes()), 2)
|
||||
|
||||
require.NoError(t, params.SetCursor(domaintest.NewTribeCursor(t, func(cfg *domaintest.TribeCursorConfig) {
|
||||
cfg.ID = res.Tribes()[1].ID()
|
||||
cfg.ServerKey = res.Tribes()[1].ServerKey()
|
||||
})))
|
||||
|
||||
return params
|
||||
},
|
||||
assertResult: func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
tribes := res.Tribes()
|
||||
assert.NotEmpty(t, len(tribes))
|
||||
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||
return cmp.Or(
|
||||
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||
cmp.Compare(a.ID(), b.ID()),
|
||||
) * -1
|
||||
}))
|
||||
assert.LessOrEqual(t, tribes[0].ID(), params.Cursor().ID())
|
||||
for _, tr := range res.Tribes() {
|
||||
assert.LessOrEqual(t, tr.ServerKey(), params.Cursor().ServerKey())
|
||||
}
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: limit=2",
|
||||
params: func(t *testing.T) domain.ListTribesParams {
|
||||
t.Helper()
|
||||
params := domain.NewListTribesParams()
|
||||
require.NoError(t, params.SetLimit(2))
|
||||
return params
|
||||
},
|
||||
assertResult: func(t *testing.T, params domain.ListTribesParams, res domain.ListTribesResult) {
|
||||
t.Helper()
|
||||
assert.Len(t, res.Tribes(), params.Limit())
|
||||
assert.False(t, res.Next().IsZero())
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -378,7 +460,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
|
||||
res, err := repos.tribe.List(ctx, params)
|
||||
tt.assertError(t, err)
|
||||
tt.assertTribes(t, params, res)
|
||||
tt.assertResult(t, params, res)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -406,8 +488,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{Value: false, Valid: true}))
|
||||
require.NoError(t, listTribesParams.SetServerKeys(serverKeys))
|
||||
|
||||
tribes, err := repos.tribe.List(ctx, listTribesParams)
|
||||
res, err := repos.tribe.List(ctx, listTribesParams)
|
||||
require.NoError(t, err)
|
||||
tribes := res.Tribes()
|
||||
|
||||
var serverKey string
|
||||
var ids []int
|
||||
|
@ -430,9 +513,9 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
|||
require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{Valid: false}))
|
||||
require.NoError(t, listTribesParams.SetServerKeys(serverKeys))
|
||||
|
||||
tribes, err = repos.tribe.List(ctx, listTribesParams)
|
||||
res, err = repos.tribe.List(ctx, listTribesParams)
|
||||
require.NoError(t, err)
|
||||
for _, tr := range tribes {
|
||||
for _, tr := range res.Tribes() {
|
||||
if tr.ServerKey() == serverKey && slices.Contains(ids, tr.ID()) {
|
||||
if slices.Contains(idsToDelete, tr.ID()) {
|
||||
assert.WithinDuration(t, time.Now(), tr.DeletedAt(), time.Minute)
|
||||
|
|
|
@ -40,6 +40,7 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
|||
assert.True(t, slices.IsSortedFunc(res.Versions(), func(a, b domain.Version) int {
|
||||
return cmp.Compare(a.Code(), b.Code())
|
||||
}))
|
||||
assert.False(t, res.Self().IsZero())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
type TribeRepository interface {
|
||||
CreateOrUpdate(ctx context.Context, params ...domain.CreateTribeParams) error
|
||||
UpdateDominance(ctx context.Context, serverKey string, numPlayerVillages int) error
|
||||
List(ctx context.Context, params domain.ListTribesParams) (domain.Tribes, error)
|
||||
List(ctx context.Context, params domain.ListTribesParams) (domain.ListTribesResult, error)
|
||||
// Delete marks players with the given serverKey and ids as deleted (sets deleted at to now).
|
||||
//
|
||||
// https://en.wiktionary.org/wiki/soft_deletion
|
||||
|
@ -98,12 +98,12 @@ func (svc *TribeService) createOrUpdateChunk(ctx context.Context, serverKey stri
|
|||
return err
|
||||
}
|
||||
|
||||
storedTribes, err := svc.repo.List(ctx, listParams)
|
||||
res, err := svc.repo.List(ctx, listParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createParams, err := domain.NewCreateTribeParams(serverKey, tribes, storedTribes)
|
||||
createParams, err := domain.NewCreateTribeParams(serverKey, tribes, res.Tribes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -132,21 +132,17 @@ func (svc *TribeService) delete(ctx context.Context, serverKey string, tribes do
|
|||
var toDelete []int
|
||||
|
||||
for {
|
||||
storedTribes, err := svc.repo.List(ctx, listParams)
|
||||
res, err := svc.repo.List(ctx, listParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toDelete = append(toDelete, res.Tribes().Delete(serverKey, tribes)...)
|
||||
|
||||
if len(storedTribes) == 0 {
|
||||
if res.Next().IsZero() {
|
||||
break
|
||||
}
|
||||
|
||||
toDelete = append(toDelete, storedTribes.Delete(serverKey, tribes)...)
|
||||
|
||||
if err = listParams.SetIDGT(domain.NullInt{
|
||||
Value: storedTribes[len(storedTribes)-1].ID(),
|
||||
Valid: true,
|
||||
}); err != nil {
|
||||
if err = listParams.SetCursor(res.Next()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +154,6 @@ func (svc *TribeService) UpdateDominance(ctx context.Context, payload domain.Vil
|
|||
return svc.repo.UpdateDominance(ctx, payload.ServerKey(), payload.NumPlayerVillages())
|
||||
}
|
||||
|
||||
func (svc *TribeService) List(ctx context.Context, params domain.ListTribesParams) (domain.Tribes, error) {
|
||||
func (svc *TribeService) List(ctx context.Context, params domain.ListTribesParams) (domain.ListTribesResult, error) {
|
||||
return svc.repo.List(ctx, params)
|
||||
}
|
||||
|
|
|
@ -53,10 +53,11 @@ func (svc *TribeSnapshotService) Create(
|
|||
}
|
||||
|
||||
for {
|
||||
tribes, err := svc.tribeSvc.List(ctx, listTribesParams)
|
||||
res, err := svc.tribeSvc.List(ctx, listTribesParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", serverKey, err)
|
||||
}
|
||||
tribes := res.Tribes()
|
||||
|
||||
if len(tribes) == 0 {
|
||||
break
|
||||
|
@ -71,10 +72,11 @@ func (svc *TribeSnapshotService) Create(
|
|||
return fmt.Errorf("%s: %w", serverKey, err)
|
||||
}
|
||||
|
||||
if err = listTribesParams.SetIDGT(domain.NullInt{
|
||||
Value: tribes[len(tribes)-1].ID(),
|
||||
Valid: true,
|
||||
}); err != nil {
|
||||
if res.Next().IsZero() {
|
||||
break
|
||||
}
|
||||
|
||||
if err = listTribesParams.SetCursor(res.Next()); err != nil {
|
||||
return fmt.Errorf("%s: %w", serverKey, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ func NewServerCursor(tb TestingTB, opts ...func(cfg *ServerCursorConfig)) domain
|
|||
opt(cfg)
|
||||
}
|
||||
|
||||
vc, err := domain.NewServerCursor(cfg.Key, cfg.Open)
|
||||
sc, err := domain.NewServerCursor(cfg.Key, cfg.Open)
|
||||
require.NoError(tb, err)
|
||||
|
||||
return vc
|
||||
return sc
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
|
|
|
@ -12,6 +12,29 @@ func RandTribeTag() string {
|
|||
return gofakeit.LetterN(5)
|
||||
}
|
||||
|
||||
type TribeCursorConfig struct {
|
||||
ID int
|
||||
ServerKey string
|
||||
}
|
||||
|
||||
func NewTribeCursor(tb TestingTB, opts ...func(cfg *TribeCursorConfig)) domain.TribeCursor {
|
||||
tb.Helper()
|
||||
|
||||
cfg := &TribeCursorConfig{
|
||||
ID: RandID(),
|
||||
ServerKey: RandServerKey(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
tc, err := domain.NewTribeCursor(cfg.ID, cfg.ServerKey)
|
||||
require.NoError(tb, err)
|
||||
|
||||
return tc
|
||||
}
|
||||
|
||||
type TribeConfig struct {
|
||||
ID int
|
||||
ServerKey string
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -368,14 +369,85 @@ const (
|
|||
TribeSortServerKeyDESC
|
||||
)
|
||||
|
||||
type TribeCursor struct {
|
||||
id int
|
||||
serverKey string
|
||||
}
|
||||
|
||||
const tribeCursorModelName = "TribeCursor"
|
||||
|
||||
func NewTribeCursor(id int, serverKey string) (TribeCursor, error) {
|
||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
||||
return TribeCursor{}, ValidationError{
|
||||
Model: tribeCursorModelName,
|
||||
Field: "id",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateServerKey(serverKey); err != nil {
|
||||
return TribeCursor{}, ValidationError{
|
||||
Model: tribeCursorModelName,
|
||||
Field: "serverKey",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
return TribeCursor{
|
||||
id: id,
|
||||
serverKey: serverKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeTribeCursor(encoded string) (TribeCursor, error) {
|
||||
m, err := decodeCursor(encoded)
|
||||
if err != nil {
|
||||
return TribeCursor{}, err
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(m["id"])
|
||||
if err != nil {
|
||||
return TribeCursor{}, ErrInvalidCursor
|
||||
}
|
||||
|
||||
tc, err := NewTribeCursor(id, m["serverKey"])
|
||||
if err != nil {
|
||||
return TribeCursor{}, ErrInvalidCursor
|
||||
}
|
||||
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
func (tc TribeCursor) ID() int {
|
||||
return tc.id
|
||||
}
|
||||
|
||||
func (tc TribeCursor) ServerKey() string {
|
||||
return tc.serverKey
|
||||
}
|
||||
|
||||
func (tc TribeCursor) IsZero() bool {
|
||||
return tc == TribeCursor{}
|
||||
}
|
||||
|
||||
func (tc TribeCursor) Encode() string {
|
||||
if tc.IsZero() {
|
||||
return ""
|
||||
}
|
||||
|
||||
return encodeCursor([][2]string{
|
||||
{"id", strconv.Itoa(tc.id)},
|
||||
{"serverKey", tc.serverKey},
|
||||
})
|
||||
}
|
||||
|
||||
type ListTribesParams struct {
|
||||
ids []int
|
||||
idGT NullInt
|
||||
serverKeys []string
|
||||
deleted NullBool
|
||||
sort []TribeSort
|
||||
cursor TribeCursor
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -414,26 +486,6 @@ func (params *ListTribesParams) SetIDs(ids []int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) IDGT() NullInt {
|
||||
return params.idGT
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) SetIDGT(idGT NullInt) error {
|
||||
if idGT.Valid {
|
||||
if err := validateIntInRange(idGT.Value, 0, math.MaxInt); err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
Field: "idGT",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.idGT = idGT
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) ServerKeys() []string {
|
||||
return params.serverKeys
|
||||
}
|
||||
|
@ -475,6 +527,30 @@ func (params *ListTribesParams) SetSort(sort []TribeSort) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) Cursor() TribeCursor {
|
||||
return params.cursor
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) SetCursor(cursor TribeCursor) error {
|
||||
params.cursor = cursor
|
||||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) SetEncodedCursor(encoded string) error {
|
||||
decoded, err := decodeTribeCursor(encoded)
|
||||
if err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
Field: "cursor",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
params.cursor = decoded
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) Limit() int {
|
||||
return params.limit
|
||||
}
|
||||
|
@ -493,20 +569,53 @@ func (params *ListTribesParams) SetLimit(limit int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) Offset() int {
|
||||
return params.offset
|
||||
type ListTribesResult struct {
|
||||
tribes Tribes
|
||||
self TribeCursor
|
||||
next TribeCursor
|
||||
}
|
||||
|
||||
func (params *ListTribesParams) SetOffset(offset int) error {
|
||||
if err := validateIntInRange(offset, 0, math.MaxInt); err != nil {
|
||||
return ValidationError{
|
||||
Model: listTribesParamsModelName,
|
||||
Field: "offset",
|
||||
const listTribesResultModelName = "ListTribesResult"
|
||||
|
||||
func NewListTribesResult(tribes Tribes, next Tribe) (ListTribesResult, error) {
|
||||
var err error
|
||||
res := ListTribesResult{
|
||||
tribes: tribes,
|
||||
}
|
||||
|
||||
if len(tribes) > 0 {
|
||||
res.self, err = NewTribeCursor(tribes[0].ID(), tribes[0].ServerKey())
|
||||
if err != nil {
|
||||
return ListTribesResult{}, ValidationError{
|
||||
Model: listTribesResultModelName,
|
||||
Field: "self",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.offset = offset
|
||||
if !next.IsZero() {
|
||||
res.next, err = NewTribeCursor(next.ID(), next.ServerKey())
|
||||
if err != nil {
|
||||
return ListTribesResult{}, ValidationError{
|
||||
Model: listTribesResultModelName,
|
||||
Field: "next",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (res ListTribesResult) Tribes() Tribes {
|
||||
return res.tribes
|
||||
}
|
||||
|
||||
func (res ListTribesResult) Self() TribeCursor {
|
||||
return res.self
|
||||
}
|
||||
|
||||
func (res ListTribesResult) Next() TribeCursor {
|
||||
return res.next
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||
"gitea.dwysokinski.me/twhelp/corev3/internal/domain/domaintest"
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -179,6 +180,81 @@ func TestNewCreateTribeParams(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewTribeCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
validTribeCursor := domaintest.NewTribeCursor(t)
|
||||
|
||||
type args struct {
|
||||
id int
|
||||
serverKey string
|
||||
}
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
args args
|
||||
expectedErr error
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
id: validTribeCursor.ID(),
|
||||
serverKey: validTribeCursor.ServerKey(),
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "ERR: id < 1",
|
||||
args: args{
|
||||
id: 0,
|
||||
serverKey: validTribeCursor.ServerKey(),
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "TribeCursor",
|
||||
Field: "id",
|
||||
Err: domain.MinGreaterEqualError{
|
||||
Min: 1,
|
||||
Current: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, serverKeyTest := range newServerKeyValidationTests() {
|
||||
tests = append(tests, test{
|
||||
name: serverKeyTest.name,
|
||||
args: args{
|
||||
id: validTribeCursor.ID(),
|
||||
serverKey: serverKeyTest.key,
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "TribeCursor",
|
||||
Field: "serverKey",
|
||||
Err: serverKeyTest.expectedErr,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tc, err := domain.NewTribeCursor(tt.args.id, tt.args.serverKey)
|
||||
require.ErrorIs(t, err, tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.args.id, tc.ID())
|
||||
assert.Equal(t, tt.args.serverKey, tc.ServerKey())
|
||||
assert.NotEmpty(t, tc.Encode())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetIDs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -241,63 +317,6 @@ func TestListTribesParams_SetIDs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetIDGT(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
idGT domain.NullInt
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
idGT: domain.NullInt{
|
||||
Value: domaintest.RandID(),
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: value < 0",
|
||||
args: args{
|
||||
idGT: domain.NullInt{
|
||||
Value: -1,
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "idGT",
|
||||
Err: domain.MinGreaterEqualError{
|
||||
Min: 0,
|
||||
Current: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
|
||||
require.ErrorIs(t, params.SetIDGT(tt.args.idGT), tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.args.idGT, params.IDGT())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -372,6 +391,90 @@ func TestListTribesParams_SetSort(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetEncodedCursor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
validCursor := domaintest.NewTribeCursor(t)
|
||||
|
||||
type args struct {
|
||||
cursor string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedCursor domain.TribeCursor
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
cursor: validCursor.Encode(),
|
||||
},
|
||||
expectedCursor: validCursor,
|
||||
},
|
||||
{
|
||||
name: "ERR: len(cursor) < 1",
|
||||
args: args{
|
||||
cursor: "",
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "cursor",
|
||||
Err: domain.LenOutOfRangeError{
|
||||
Min: 1,
|
||||
Max: 1000,
|
||||
Current: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(cursor) > 1000",
|
||||
args: args{
|
||||
cursor: gofakeit.LetterN(1001),
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "cursor",
|
||||
Err: domain.LenOutOfRangeError{
|
||||
Min: 1,
|
||||
Max: 1000,
|
||||
Current: 1001,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: malformed base64",
|
||||
args: args{
|
||||
cursor: "112345",
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "cursor",
|
||||
Err: domain.ErrInvalidCursor,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
|
||||
require.ErrorIs(t, params.SetEncodedCursor(tt.args.cursor), tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.expectedCursor.ID(), params.Cursor().ID())
|
||||
assert.Equal(t, tt.expectedCursor.ServerKey(), params.Cursor().ServerKey())
|
||||
assert.Equal(t, tt.args.cursor, params.Cursor().Encode())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -437,53 +540,46 @@ func TestListTribesParams_SetLimit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListTribesParams_SetOffset(t *testing.T) {
|
||||
func TestNewListTribesResult(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
offset int
|
||||
servers := domain.Tribes{
|
||||
domaintest.NewTribe(t),
|
||||
domaintest.NewTribe(t),
|
||||
domaintest.NewTribe(t),
|
||||
}
|
||||
next := domaintest.NewTribe(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
offset: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: offset < 0",
|
||||
args: args{
|
||||
offset: -1,
|
||||
},
|
||||
expectedErr: domain.ValidationError{
|
||||
Model: "ListTribesParams",
|
||||
Field: "offset",
|
||||
Err: domain.MinGreaterEqualError{
|
||||
Min: 0,
|
||||
Current: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Run("OK: with next", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := domain.NewListTribesParams()
|
||||
|
||||
require.ErrorIs(t, params.SetOffset(tt.args.offset), tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.args.offset, params.Offset())
|
||||
res, err := domain.NewListTribesResult(servers, next)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, servers, res.Tribes())
|
||||
assert.Equal(t, servers[0].ID(), res.Self().ID())
|
||||
assert.Equal(t, servers[0].ServerKey(), res.Self().ServerKey())
|
||||
assert.Equal(t, next.ID(), res.Next().ID())
|
||||
assert.Equal(t, next.ServerKey(), res.Next().ServerKey())
|
||||
})
|
||||
|
||||
t.Run("OK: without next", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := domain.NewListTribesResult(servers, domain.Tribe{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, servers, res.Tribes())
|
||||
assert.Equal(t, servers[0].ID(), res.Self().ID())
|
||||
assert.Equal(t, servers[0].ServerKey(), res.Self().ServerKey())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
})
|
||||
|
||||
t.Run("OK: 0 versions", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := domain.NewListTribesResult(nil, domain.Tribe{})
|
||||
require.NoError(t, err)
|
||||
assert.Zero(t, res.Tribes())
|
||||
assert.True(t, res.Self().IsZero())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,19 +290,16 @@ func TestDataSync(t *testing.T) {
|
|||
allTribes := make(domain.Tribes, 0, len(expectedTribes))
|
||||
|
||||
for {
|
||||
tribes, err := tribeRepo.List(ctx, listParams)
|
||||
res, err := tribeRepo.List(ctx, listParams)
|
||||
require.NoError(collect, err)
|
||||
|
||||
if len(tribes) == 0 {
|
||||
allTribes = append(allTribes, res.Tribes()...)
|
||||
|
||||
if res.Next().IsZero() {
|
||||
break
|
||||
}
|
||||
|
||||
allTribes = append(allTribes, tribes...)
|
||||
|
||||
require.NoError(collect, listParams.SetIDGT(domain.NullInt{
|
||||
Value: tribes[len(tribes)-1].ID(),
|
||||
Valid: true,
|
||||
}))
|
||||
require.NoError(collect, listParams.SetCursor(res.Next()))
|
||||
}
|
||||
|
||||
if !assert.Len(collect, allTribes, len(expectedTribes)) {
|
||||
|
|
|
@ -190,19 +190,16 @@ func TestSnapshotCreation(t *testing.T) {
|
|||
var allTribes domain.Tribes
|
||||
|
||||
for {
|
||||
tribes, err := tribeRepo.List(ctx, listTribesParams)
|
||||
res, err := tribeRepo.List(ctx, listTribesParams)
|
||||
require.NoError(collect, err)
|
||||
|
||||
if len(tribes) == 0 {
|
||||
allTribes = append(allTribes, res.Tribes()...)
|
||||
|
||||
if res.Next().IsZero() {
|
||||
break
|
||||
}
|
||||
|
||||
allTribes = append(allTribes, tribes...)
|
||||
|
||||
require.NoError(collect, listTribesParams.SetIDGT(domain.NullInt{
|
||||
Value: tribes[len(tribes)-1].ID(),
|
||||
Valid: true,
|
||||
}))
|
||||
require.NoError(collect, listTribesParams.SetCursor(res.Next()))
|
||||
}
|
||||
|
||||
listSnapshotsParams := domain.NewListTribeSnapshotsParams()
|
||||
|
|
Loading…
Reference in New Issue
Block a user