core/internal/domain/tribe_change.go

302 lines
6.5 KiB
Go

package domain
import (
"cmp"
"fmt"
"math"
"slices"
"time"
)
type TribeChange struct {
id int
serverKey string
playerID int
oldTribeID int
newTribeID int
createdAt time.Time
}
const tribeChangeModelName = "TribeChange"
// UnmarshalTribeChangeFromDatabase unmarshals TribeChange from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalTribeChangeFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalTribeChangeFromDatabase(
id int,
serverKey string,
playerID int,
oldTribeID int,
newTribeID int,
createdAt time.Time,
) (TribeChange, error) {
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return TribeChange{}, ValidationError{
Model: tribeChangeModelName,
Field: "id",
Err: err,
}
}
if err := validateServerKey(serverKey); err != nil {
return TribeChange{}, ValidationError{
Model: tribeChangeModelName,
Field: "serverKey",
Err: err,
}
}
return TribeChange{
id: id,
playerID: playerID,
oldTribeID: oldTribeID,
newTribeID: newTribeID,
serverKey: serverKey,
createdAt: createdAt,
}, nil
}
func (tc TribeChange) ID() int {
return tc.id
}
func (tc TribeChange) PlayerID() int {
return tc.playerID
}
func (tc TribeChange) OldTribeID() int {
return tc.oldTribeID
}
func (tc TribeChange) NewTribeID() int {
return tc.newTribeID
}
func (tc TribeChange) ServerKey() string {
return tc.serverKey
}
func (tc TribeChange) CreatedAt() time.Time {
return tc.createdAt
}
type TribeChanges []TribeChange
type CreateTribeChangeParams struct {
serverKey string
playerID int
newTribeID int
oldTribeID int
}
const createTribeChangeParamsModelName = "CreateTribeChangeParams"
func NewCreateTribeChangeParams(
serverKey string,
playerID int,
oldTribeID int,
newTribeID int,
) (CreateTribeChangeParams, error) {
if err := validateServerKey(serverKey); err != nil {
return CreateTribeChangeParams{}, ValidationError{
Model: createTribeChangeParamsModelName,
Field: "serverKey",
Err: err,
}
}
if err := validateIntInRange(playerID, 1, math.MaxInt); err != nil {
return CreateTribeChangeParams{}, ValidationError{
Model: createTribeChangeParamsModelName,
Field: "playerID",
Err: err,
}
}
if err := validateIntInRange(oldTribeID, 0, math.MaxInt); err != nil {
return CreateTribeChangeParams{}, ValidationError{
Model: createTribeChangeParamsModelName,
Field: "oldTribeID",
Err: err,
}
}
if err := validateIntInRange(newTribeID, 0, math.MaxInt); err != nil {
return CreateTribeChangeParams{}, ValidationError{
Model: createTribeChangeParamsModelName,
Field: "newTribeID",
Err: err,
}
}
return CreateTribeChangeParams{
serverKey: serverKey,
playerID: playerID,
oldTribeID: oldTribeID,
newTribeID: newTribeID,
}, nil
}
// NewCreateTribeChangeParamsFromPlayers constructs a slice of CreatePlayerParams based on the given parameters.
// Both slices must be sorted in ascending order by ID
// + if storedPlayers contains players from different servers. they must be sorted in ascending order by server key.
func NewCreateTribeChangeParamsFromPlayers(
serverKey string,
players BasePlayers,
storedPlayers Players,
) ([]CreateTribeChangeParams, error) {
// tribe changes happens now and then, there is no point in prereallocating this slice
//nolint:prealloc
var params []CreateTribeChangeParams
for i, player := range players {
if player.IsZero() {
return nil, fmt.Errorf("players[%d] is an empty struct", i)
}
var old Player
idx, found := slices.BinarySearchFunc(storedPlayers, player, func(a Player, b BasePlayer) int {
if res := cmp.Compare(a.ServerKey(), serverKey); res != 0 {
return res
}
return cmp.Compare(a.ID(), b.ID())
})
if found {
old = storedPlayers[idx]
}
if (old.ID() > 0 && old.TribeID() == player.TribeID()) || (old.ID() == 0 && player.TribeID() == 0) {
continue
}
p, err := NewCreateTribeChangeParams(
serverKey,
player.ID(),
old.TribeID(),
player.TribeID(),
)
if err != nil {
return nil, err
}
params = append(params, p)
}
return params, nil
}
func (params CreateTribeChangeParams) ServerKey() string {
return params.serverKey
}
func (params CreateTribeChangeParams) PlayerID() int {
return params.playerID
}
func (params CreateTribeChangeParams) OldTribeID() int {
return params.oldTribeID
}
func (params CreateTribeChangeParams) NewTribeID() int {
return params.newTribeID
}
type TribeChangeSort uint8
const (
TribeChangeSortCreatedAtASC TribeChangeSort = iota + 1
TribeChangeSortCreatedAtDESC
TribeChangeSortServerKeyASC
TribeChangeSortServerKeyDESC
)
const TribeChangeListMaxLimit = 200
type ListTribeChangesParams struct {
serverKeys []string
sort []TribeChangeSort
limit int
offset int
}
const listTribeChangesParamsModelName = "ListTribeChangesParams"
func NewListTribeChangesParams() ListTribeChangesParams {
return ListTribeChangesParams{
sort: []TribeChangeSort{
TribeChangeSortServerKeyASC,
TribeChangeSortCreatedAtASC,
},
limit: TribeChangeListMaxLimit,
}
}
func (params *ListTribeChangesParams) ServerKeys() []string {
return params.serverKeys
}
func (params *ListTribeChangesParams) SetServerKeys(serverKeys []string) error {
params.serverKeys = serverKeys
return nil
}
func (params *ListTribeChangesParams) Sort() []TribeChangeSort {
return params.sort
}
const (
tribeChangeSortMinLength = 1
tribeChangeSortMaxLength = 2
)
func (params *ListTribeChangesParams) SetSort(sort []TribeChangeSort) error {
if err := validateSliceLen(sort, tribeChangeSortMinLength, tribeChangeSortMaxLength); err != nil {
return ValidationError{
Model: listTribeChangesParamsModelName,
Field: "sort",
Err: err,
}
}
params.sort = sort
return nil
}
func (params *ListTribeChangesParams) Limit() int {
return params.limit
}
func (params *ListTribeChangesParams) SetLimit(limit int) error {
if err := validateIntInRange(limit, 1, TribeChangeListMaxLimit); err != nil {
return ValidationError{
Model: listTribeChangesParamsModelName,
Field: "limit",
Err: err,
}
}
params.limit = limit
return nil
}
func (params *ListTribeChangesParams) Offset() int {
return params.offset
}
func (params *ListTribeChangesParams) SetOffset(offset int) error {
if err := validateIntInRange(offset, 0, math.MaxInt); err != nil {
return ValidationError{
Model: listTribeChangesParamsModelName,
Field: "offset",
Err: err,
}
}
params.offset = offset
return nil
}