960 lines
20 KiB
Go
960 lines
20 KiB
Go
package domain
|
|
|
|
import (
|
|
"cmp"
|
|
"fmt"
|
|
"math"
|
|
"net/url"
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
playerNameMinLength = 1
|
|
playerNameMaxLength = 150
|
|
)
|
|
|
|
type Player struct {
|
|
id int
|
|
serverKey string
|
|
name string
|
|
numVillages int
|
|
points int
|
|
rank int
|
|
tribeID int
|
|
od OpponentsDefeated
|
|
profileURL *url.URL
|
|
bestRank int
|
|
bestRankAt time.Time
|
|
mostPoints int
|
|
mostPointsAt time.Time
|
|
mostVillages int
|
|
mostVillagesAt time.Time
|
|
lastActivityAt time.Time
|
|
createdAt time.Time
|
|
deletedAt time.Time
|
|
}
|
|
|
|
const playerModelName = "Player"
|
|
|
|
// UnmarshalPlayerFromDatabase unmarshals Player from the database.
|
|
//
|
|
// It should be used only for unmarshalling from the database!
|
|
// You can't use UnmarshalPlayerFromDatabase as constructor - It may put domain into the invalid state!
|
|
func UnmarshalPlayerFromDatabase(
|
|
id int,
|
|
serverKey string,
|
|
name string,
|
|
numVillages int,
|
|
points int,
|
|
rank int,
|
|
tribeID int,
|
|
od OpponentsDefeated,
|
|
rawProfileURL string,
|
|
bestRank int,
|
|
bestRankAt time.Time,
|
|
mostPoints int,
|
|
mostPointsAt time.Time,
|
|
mostVillages int,
|
|
mostVillagesAt time.Time,
|
|
lastActivityAt time.Time,
|
|
createdAt time.Time,
|
|
deletedAt time.Time,
|
|
) (Player, error) {
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
|
return Player{}, ValidationError{
|
|
Model: playerModelName,
|
|
Field: "id",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateServerKey(serverKey); err != nil {
|
|
return Player{}, ValidationError{
|
|
Model: playerModelName,
|
|
Field: "serverKey",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
profileURL, err := parseURL(rawProfileURL)
|
|
if err != nil {
|
|
return Player{}, ValidationError{
|
|
Model: playerModelName,
|
|
Field: "profileURL",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
return Player{
|
|
id: id,
|
|
serverKey: serverKey,
|
|
name: name,
|
|
numVillages: numVillages,
|
|
points: points,
|
|
rank: rank,
|
|
tribeID: tribeID,
|
|
od: od,
|
|
profileURL: profileURL,
|
|
bestRank: bestRank,
|
|
bestRankAt: bestRankAt,
|
|
mostPoints: mostPoints,
|
|
mostPointsAt: mostPointsAt,
|
|
mostVillages: mostVillages,
|
|
mostVillagesAt: mostVillagesAt,
|
|
lastActivityAt: lastActivityAt,
|
|
createdAt: createdAt,
|
|
deletedAt: deletedAt,
|
|
}, nil
|
|
}
|
|
|
|
func (p Player) ID() int {
|
|
return p.id
|
|
}
|
|
|
|
func (p Player) ServerKey() string {
|
|
return p.serverKey
|
|
}
|
|
|
|
func (p Player) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p Player) NumVillages() int {
|
|
return p.numVillages
|
|
}
|
|
|
|
func (p Player) Points() int {
|
|
return p.points
|
|
}
|
|
|
|
func (p Player) Rank() int {
|
|
return p.rank
|
|
}
|
|
|
|
func (p Player) TribeID() int {
|
|
return p.tribeID
|
|
}
|
|
|
|
func (p Player) OD() OpponentsDefeated {
|
|
return p.od
|
|
}
|
|
|
|
func (p Player) ProfileURL() *url.URL {
|
|
return p.profileURL
|
|
}
|
|
|
|
func (p Player) BestRank() int {
|
|
return p.bestRank
|
|
}
|
|
|
|
func (p Player) BestRankAt() time.Time {
|
|
return p.bestRankAt
|
|
}
|
|
|
|
func (p Player) MostPoints() int {
|
|
return p.mostPoints
|
|
}
|
|
|
|
func (p Player) MostPointsAt() time.Time {
|
|
return p.mostPointsAt
|
|
}
|
|
|
|
func (p Player) MostVillages() int {
|
|
return p.mostVillages
|
|
}
|
|
|
|
func (p Player) MostVillagesAt() time.Time {
|
|
return p.mostVillagesAt
|
|
}
|
|
|
|
func (p Player) LastActivityAt() time.Time {
|
|
return p.lastActivityAt
|
|
}
|
|
|
|
func (p Player) CreatedAt() time.Time {
|
|
return p.createdAt
|
|
}
|
|
|
|
func (p Player) DeletedAt() time.Time {
|
|
return p.deletedAt
|
|
}
|
|
|
|
func (p Player) WithRelations(tribe NullTribeMeta) PlayerWithRelations {
|
|
return PlayerWithRelations{
|
|
player: p,
|
|
tribe: tribe,
|
|
}
|
|
}
|
|
|
|
func (p Player) Base() BasePlayer {
|
|
return BasePlayer{
|
|
id: p.id,
|
|
name: p.name,
|
|
numVillages: p.numVillages,
|
|
points: p.points,
|
|
rank: p.rank,
|
|
tribeID: p.tribeID,
|
|
od: p.od,
|
|
profileURL: p.profileURL,
|
|
}
|
|
}
|
|
|
|
func (p Player) IsDeleted() bool {
|
|
return !p.deletedAt.IsZero()
|
|
}
|
|
|
|
func (p Player) IsZero() bool {
|
|
return p == Player{}
|
|
}
|
|
|
|
type Players []Player
|
|
|
|
// Delete finds all players with the given serverKey that are not in the given slice with active players
|
|
// and returns their ids + tribe changes that must be created.
|
|
// Both slices must be sorted in ascending order by ID.
|
|
// + if ps contains players from different servers. they must be sorted in ascending order by server key.
|
|
func (ps Players) Delete(serverKey string, active BasePlayers) ([]int, []CreateTribeChangeParams, error) {
|
|
// players are deleted now and then, there is no point in prereallocating these slices
|
|
//nolint:prealloc
|
|
var toDelete []int
|
|
var params []CreateTribeChangeParams
|
|
|
|
for _, p := range ps {
|
|
if p.IsDeleted() || p.ServerKey() != serverKey {
|
|
continue
|
|
}
|
|
|
|
_, found := slices.BinarySearchFunc(active, p, func(a BasePlayer, b Player) int {
|
|
return cmp.Compare(a.ID(), b.ID())
|
|
})
|
|
if found {
|
|
continue
|
|
}
|
|
|
|
toDelete = append(toDelete, p.ID())
|
|
|
|
if p.TribeID() > 0 {
|
|
p, err := NewCreateTribeChangeParams(serverKey, p.ID(), p.TribeID(), 0)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
params = append(params, p)
|
|
}
|
|
}
|
|
|
|
return toDelete, params, nil
|
|
}
|
|
|
|
type PlayerWithRelations struct {
|
|
player Player
|
|
tribe NullTribeMeta
|
|
}
|
|
|
|
func (p PlayerWithRelations) Player() Player {
|
|
return p.player
|
|
}
|
|
|
|
func (p PlayerWithRelations) Tribe() NullTribeMeta {
|
|
return p.tribe
|
|
}
|
|
|
|
func (p PlayerWithRelations) IsZero() bool {
|
|
return p.player.IsZero() && p.tribe.IsZero()
|
|
}
|
|
|
|
type CreatePlayerParams struct {
|
|
base BasePlayer
|
|
serverKey string
|
|
bestRank int
|
|
bestRankAt time.Time
|
|
mostPoints int
|
|
mostPointsAt time.Time
|
|
mostVillages int
|
|
mostVillagesAt time.Time
|
|
lastActivityAt time.Time
|
|
}
|
|
|
|
type PlayersWithRelations []PlayerWithRelations
|
|
|
|
const createPlayerParamsModelName = "CreatePlayerParams"
|
|
|
|
// NewCreatePlayerParams 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.
|
|
//
|
|
//nolint:gocyclo
|
|
func NewCreatePlayerParams(serverKey string, players BasePlayers, storedPlayers Players) ([]CreatePlayerParams, error) {
|
|
if err := validateServerKey(serverKey); err != nil {
|
|
return nil, ValidationError{
|
|
Model: createPlayerParamsModelName,
|
|
Field: "serverKey",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
params := make([]CreatePlayerParams, 0, len(players))
|
|
|
|
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 {
|
|
return cmp.Or(
|
|
cmp.Compare(a.ServerKey(), serverKey),
|
|
cmp.Compare(a.ID(), b.ID()),
|
|
)
|
|
})
|
|
if found {
|
|
old = storedPlayers[idx]
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
p := CreatePlayerParams{
|
|
base: player,
|
|
serverKey: serverKey,
|
|
bestRank: player.Rank(),
|
|
bestRankAt: now,
|
|
mostPoints: player.Points(),
|
|
mostPointsAt: now,
|
|
mostVillages: player.NumVillages(),
|
|
mostVillagesAt: now,
|
|
lastActivityAt: now,
|
|
}
|
|
|
|
if old.ID() > 0 {
|
|
if old.MostPoints() >= p.MostPoints() {
|
|
p.mostPoints = old.MostPoints()
|
|
p.mostPointsAt = old.MostPointsAt()
|
|
}
|
|
|
|
if old.MostVillages() >= p.MostVillages() {
|
|
p.mostVillages = old.MostVillages()
|
|
p.mostVillagesAt = old.MostVillagesAt()
|
|
}
|
|
|
|
if old.BestRank() <= p.BestRank() {
|
|
p.bestRank = old.BestRank()
|
|
p.bestRankAt = old.BestRankAt()
|
|
}
|
|
|
|
//nolint:lll
|
|
if player.Points() <= old.Points() && player.NumVillages() <= old.NumVillages() && player.OD().ScoreAtt() <= old.OD().ScoreAtt() {
|
|
p.lastActivityAt = old.LastActivityAt()
|
|
}
|
|
}
|
|
|
|
params = append(params, p)
|
|
}
|
|
|
|
return params, nil
|
|
}
|
|
|
|
func (params CreatePlayerParams) Base() BasePlayer {
|
|
return params.base
|
|
}
|
|
|
|
func (params CreatePlayerParams) ServerKey() string {
|
|
return params.serverKey
|
|
}
|
|
|
|
func (params CreatePlayerParams) BestRank() int {
|
|
return params.bestRank
|
|
}
|
|
|
|
func (params CreatePlayerParams) BestRankAt() time.Time {
|
|
return params.bestRankAt
|
|
}
|
|
|
|
func (params CreatePlayerParams) MostPoints() int {
|
|
return params.mostPoints
|
|
}
|
|
|
|
func (params CreatePlayerParams) MostPointsAt() time.Time {
|
|
return params.mostPointsAt
|
|
}
|
|
|
|
func (params CreatePlayerParams) MostVillages() int {
|
|
return params.mostVillages
|
|
}
|
|
|
|
func (params CreatePlayerParams) MostVillagesAt() time.Time {
|
|
return params.mostVillagesAt
|
|
}
|
|
|
|
func (params CreatePlayerParams) LastActivityAt() time.Time {
|
|
return params.lastActivityAt
|
|
}
|
|
|
|
type PlayerSort uint8
|
|
|
|
const (
|
|
PlayerSortIDASC PlayerSort = iota + 1
|
|
PlayerSortIDDESC
|
|
PlayerSortServerKeyASC
|
|
PlayerSortServerKeyDESC
|
|
PlayerSortODScoreAttASC
|
|
PlayerSortODScoreAttDESC
|
|
PlayerSortODScoreDefASC
|
|
PlayerSortODScoreDefDESC
|
|
PlayerSortODScoreTotalASC
|
|
PlayerSortODScoreTotalDESC
|
|
PlayerSortPointsASC
|
|
PlayerSortPointsDESC
|
|
PlayerSortDeletedAtASC
|
|
PlayerSortDeletedAtDESC
|
|
)
|
|
|
|
//nolint:gocyclo
|
|
func newPlayerSortFromString(s string) (PlayerSort, error) {
|
|
switch strings.ToLower(s) {
|
|
case "odscoreatt:asc":
|
|
return PlayerSortODScoreAttASC, nil
|
|
case "odscoreatt:desc":
|
|
return PlayerSortODScoreAttDESC, nil
|
|
case "odscoredef:asc":
|
|
return PlayerSortODScoreDefASC, nil
|
|
case "odscoredef:desc":
|
|
return PlayerSortODScoreDefDESC, nil
|
|
case "odscoretotal:asc":
|
|
return PlayerSortODScoreTotalASC, nil
|
|
case "odscoretotal:desc":
|
|
return PlayerSortODScoreTotalDESC, nil
|
|
case "points:asc":
|
|
return PlayerSortPointsASC, nil
|
|
case "points:desc":
|
|
return PlayerSortPointsDESC, nil
|
|
case "deletedat:asc":
|
|
return PlayerSortDeletedAtASC, nil
|
|
case "deletedat:desc":
|
|
return PlayerSortDeletedAtDESC, nil
|
|
default:
|
|
return 0, UnsupportedSortStringError{
|
|
Sort: s,
|
|
}
|
|
}
|
|
}
|
|
|
|
type PlayerCursor struct {
|
|
id int
|
|
serverKey string
|
|
odScoreAtt int
|
|
odScoreDef int
|
|
odScoreTotal int
|
|
points int
|
|
deletedAt time.Time
|
|
}
|
|
|
|
const playerCursorModelName = "PlayerCursor"
|
|
|
|
func NewPlayerCursor(
|
|
id int,
|
|
serverKey string,
|
|
odScoreAtt int,
|
|
odScoreDef int,
|
|
odScoreTotal int,
|
|
points int,
|
|
deletedAt time.Time,
|
|
) (PlayerCursor, error) {
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "id",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateServerKey(serverKey); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "serverKey",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateIntInRange(odScoreAtt, 0, math.MaxInt); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "odScoreAtt",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateIntInRange(odScoreDef, 0, math.MaxInt); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "odScoreDef",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateIntInRange(odScoreTotal, 0, math.MaxInt); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "odScoreTotal",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
|
return PlayerCursor{}, ValidationError{
|
|
Model: playerCursorModelName,
|
|
Field: "points",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
return PlayerCursor{
|
|
id: id,
|
|
serverKey: serverKey,
|
|
odScoreAtt: odScoreAtt,
|
|
odScoreDef: odScoreDef,
|
|
odScoreTotal: odScoreTotal,
|
|
points: points,
|
|
deletedAt: deletedAt,
|
|
}, nil
|
|
}
|
|
|
|
//nolint:gocyclo
|
|
func decodePlayerCursor(encoded string) (PlayerCursor, error) {
|
|
m, err := decodeCursor(encoded)
|
|
if err != nil {
|
|
return PlayerCursor{}, err
|
|
}
|
|
|
|
id, err := m.int("id")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
serverKey, err := m.string("serverKey")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
odScoreAtt, err := m.int("odScoreAtt")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
odScoreDef, err := m.int("odScoreDef")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
odScoreTotal, err := m.int("odScoreTotal")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
points, err := m.int("points")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
deletedAt, err := m.time("deletedAt")
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
pc, err := NewPlayerCursor(
|
|
id,
|
|
serverKey,
|
|
odScoreAtt,
|
|
odScoreDef,
|
|
odScoreTotal,
|
|
points,
|
|
deletedAt,
|
|
)
|
|
if err != nil {
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
}
|
|
|
|
return pc, nil
|
|
}
|
|
|
|
func (pc PlayerCursor) ID() int {
|
|
return pc.id
|
|
}
|
|
|
|
func (pc PlayerCursor) ServerKey() string {
|
|
return pc.serverKey
|
|
}
|
|
|
|
func (pc PlayerCursor) ODScoreAtt() int {
|
|
return pc.odScoreAtt
|
|
}
|
|
|
|
func (pc PlayerCursor) ODScoreDef() int {
|
|
return pc.odScoreDef
|
|
}
|
|
|
|
func (pc PlayerCursor) ODScoreTotal() int {
|
|
return pc.odScoreTotal
|
|
}
|
|
|
|
func (pc PlayerCursor) Points() int {
|
|
return pc.points
|
|
}
|
|
|
|
func (pc PlayerCursor) DeletedAt() time.Time {
|
|
return pc.deletedAt
|
|
}
|
|
|
|
func (pc PlayerCursor) IsZero() bool {
|
|
return pc == PlayerCursor{}
|
|
}
|
|
|
|
func (pc PlayerCursor) Encode() string {
|
|
if pc.IsZero() {
|
|
return ""
|
|
}
|
|
|
|
return encodeCursor([]keyValuePair{
|
|
{"id", pc.id},
|
|
{"serverKey", pc.serverKey},
|
|
{"odScoreAtt", pc.odScoreAtt},
|
|
{"odScoreDef", pc.odScoreDef},
|
|
{"odScoreTotal", pc.odScoreTotal},
|
|
{"points", pc.points},
|
|
{"deletedAt", pc.deletedAt},
|
|
})
|
|
}
|
|
|
|
type ListPlayersParams struct {
|
|
ids []int
|
|
serverKeys []string
|
|
names []string
|
|
deleted NullBool
|
|
sort []PlayerSort
|
|
cursor PlayerCursor
|
|
limit int
|
|
}
|
|
|
|
const (
|
|
PlayerListMaxLimit = 200
|
|
listPlayersParamsModelName = "ListPlayersParams"
|
|
)
|
|
|
|
func NewListPlayersParams() ListPlayersParams {
|
|
return ListPlayersParams{
|
|
sort: []PlayerSort{
|
|
PlayerSortServerKeyASC,
|
|
PlayerSortIDASC,
|
|
},
|
|
limit: PlayerListMaxLimit,
|
|
}
|
|
}
|
|
|
|
func (params *ListPlayersParams) IDs() []int {
|
|
return params.ids
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetIDs(ids []int) error {
|
|
for i, id := range ids {
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
|
return SliceElementValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "ids",
|
|
Index: i,
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
params.ids = ids
|
|
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) ServerKeys() []string {
|
|
return params.serverKeys
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetServerKeys(serverKeys []string) error {
|
|
params.serverKeys = serverKeys
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) Names() []string {
|
|
return params.names
|
|
}
|
|
|
|
const (
|
|
playerNamesMinLength = 1
|
|
playerNamesMaxLength = 100
|
|
)
|
|
|
|
func (params *ListPlayersParams) SetNames(names []string) error {
|
|
if err := validateSliceLen(names, playerNamesMinLength, playerNamesMaxLength); err != nil {
|
|
return ValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "names",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
for i, n := range names {
|
|
if err := validateStringLen(n, playerNameMinLength, playerNameMaxLength); err != nil {
|
|
return SliceElementValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "names",
|
|
Index: i,
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
params.names = names
|
|
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) Deleted() NullBool {
|
|
return params.deleted
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetDeleted(deleted NullBool) error {
|
|
params.deleted = deleted
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) Sort() []PlayerSort {
|
|
return params.sort
|
|
}
|
|
|
|
const (
|
|
playerSortMinLength = 1
|
|
playerSortMaxLength = 3
|
|
)
|
|
|
|
func (params *ListPlayersParams) SetSort(sort []PlayerSort) error {
|
|
if err := validateSliceLen(sort, playerSortMinLength, playerSortMaxLength); err != nil {
|
|
return ValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "sort",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
params.sort = sort
|
|
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) PrependSortString(sort []string) error {
|
|
if err := validateSliceLen(sort, playerSortMinLength, max(playerSortMaxLength-len(params.sort), 0)); err != nil {
|
|
return ValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "sort",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
for i := len(sort) - 1; i >= 0; i-- {
|
|
converted, err := newPlayerSortFromString(sort[i])
|
|
if err != nil {
|
|
return SliceElementValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "sort",
|
|
Index: i,
|
|
Err: err,
|
|
}
|
|
}
|
|
params.sort = append([]PlayerSort{converted}, params.sort...)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) Cursor() PlayerCursor {
|
|
return params.cursor
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetCursor(cursor PlayerCursor) error {
|
|
params.cursor = cursor
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetEncodedCursor(encoded string) error {
|
|
decoded, err := decodePlayerCursor(encoded)
|
|
if err != nil {
|
|
return ValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "cursor",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
params.cursor = decoded
|
|
|
|
return nil
|
|
}
|
|
|
|
func (params *ListPlayersParams) Limit() int {
|
|
return params.limit
|
|
}
|
|
|
|
func (params *ListPlayersParams) SetLimit(limit int) error {
|
|
if err := validateIntInRange(limit, 1, PlayerListMaxLimit); err != nil {
|
|
return ValidationError{
|
|
Model: listPlayersParamsModelName,
|
|
Field: "limit",
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
params.limit = limit
|
|
|
|
return nil
|
|
}
|
|
|
|
type ListPlayersResult struct {
|
|
players Players
|
|
self PlayerCursor
|
|
next PlayerCursor
|
|
}
|
|
|
|
const listPlayersResultModelName = "ListPlayersResult"
|
|
|
|
func NewListPlayersResult(players Players, next Player) (ListPlayersResult, error) {
|
|
var err error
|
|
res := ListPlayersResult{
|
|
players: players,
|
|
}
|
|
|
|
if len(players) > 0 {
|
|
od := players[0].OD()
|
|
res.self, err = NewPlayerCursor(
|
|
players[0].ID(),
|
|
players[0].ServerKey(),
|
|
od.ScoreAtt(),
|
|
od.ScoreDef(),
|
|
od.ScoreTotal(),
|
|
players[0].Points(),
|
|
players[0].DeletedAt(),
|
|
)
|
|
if err != nil {
|
|
return ListPlayersResult{}, ValidationError{
|
|
Model: listPlayersResultModelName,
|
|
Field: "self",
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
if !next.IsZero() {
|
|
od := next.OD()
|
|
res.next, err = NewPlayerCursor(
|
|
next.ID(),
|
|
next.ServerKey(),
|
|
od.ScoreAtt(),
|
|
od.ScoreDef(),
|
|
od.ScoreTotal(),
|
|
next.Points(),
|
|
next.DeletedAt(),
|
|
)
|
|
if err != nil {
|
|
return ListPlayersResult{}, ValidationError{
|
|
Model: listPlayersResultModelName,
|
|
Field: "next",
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (res ListPlayersResult) Players() Players {
|
|
return res.players
|
|
}
|
|
|
|
func (res ListPlayersResult) Self() PlayerCursor {
|
|
return res.self
|
|
}
|
|
|
|
func (res ListPlayersResult) Next() PlayerCursor {
|
|
return res.next
|
|
}
|
|
|
|
type ListPlayersWithRelationsResult struct {
|
|
players PlayersWithRelations
|
|
self PlayerCursor
|
|
next PlayerCursor
|
|
}
|
|
|
|
const listPlayersWithRelationsResultModelName = "ListPlayersWithRelationsResult"
|
|
|
|
func NewListPlayersWithRelationsResult(
|
|
players PlayersWithRelations,
|
|
next PlayerWithRelations,
|
|
) (ListPlayersWithRelationsResult, error) {
|
|
var err error
|
|
res := ListPlayersWithRelationsResult{
|
|
players: players,
|
|
}
|
|
|
|
if len(players) > 0 {
|
|
player := players[0].Player()
|
|
od := player.OD()
|
|
res.self, err = NewPlayerCursor(
|
|
player.ID(),
|
|
player.ServerKey(),
|
|
od.ScoreAtt(),
|
|
od.ScoreDef(),
|
|
od.ScoreTotal(),
|
|
player.Points(),
|
|
player.DeletedAt(),
|
|
)
|
|
if err != nil {
|
|
return ListPlayersWithRelationsResult{}, ValidationError{
|
|
Model: listPlayersWithRelationsResultModelName,
|
|
Field: "self",
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
if !next.IsZero() {
|
|
fmt.Println(next.IsZero())
|
|
player := next.Player()
|
|
od := player.OD()
|
|
res.next, err = NewPlayerCursor(
|
|
player.ID(),
|
|
player.ServerKey(),
|
|
od.ScoreAtt(),
|
|
od.ScoreDef(),
|
|
od.ScoreTotal(),
|
|
player.Points(),
|
|
player.DeletedAt(),
|
|
)
|
|
if err != nil {
|
|
return ListPlayersWithRelationsResult{}, ValidationError{
|
|
Model: listPlayersWithRelationsResultModelName,
|
|
Field: "next",
|
|
Err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (res ListPlayersWithRelationsResult) Players() PlayersWithRelations {
|
|
return res.players
|
|
}
|
|
|
|
func (res ListPlayersWithRelationsResult) Self() PlayerCursor {
|
|
return res.self
|
|
}
|
|
|
|
func (res ListPlayersWithRelationsResult) Next() PlayerCursor {
|
|
return res.next
|
|
}
|