2024-01-01 07:49:47 +00:00
|
|
|
package domain
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
import (
|
|
|
|
"cmp"
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
"net/url"
|
|
|
|
"slices"
|
2024-02-27 07:09:24 +00:00
|
|
|
"strings"
|
2024-01-01 10:20:30 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2024-01-01 07:49:47 +00:00
|
|
|
const (
|
|
|
|
playerNameMinLength = 1
|
|
|
|
playerNameMaxLength = 150
|
|
|
|
)
|
2024-01-01 10:20:30 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
const playerModelName = "Player"
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
if err := validateServerKey(serverKey); err != nil {
|
|
|
|
return Player{}, ValidationError{
|
|
|
|
Model: playerModelName,
|
|
|
|
Field: "serverKey",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
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 {
|
2024-03-11 07:37:04 +00:00
|
|
|
if p.profileURL == nil {
|
|
|
|
return &url.URL{}
|
|
|
|
}
|
2024-01-01 10:20:30 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-02-28 06:59:10 +00:00
|
|
|
func (p Player) WithRelations(tribe NullTribeMeta) PlayerWithRelations {
|
|
|
|
return PlayerWithRelations{
|
|
|
|
player: p,
|
|
|
|
tribe: tribe,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-06 06:35:26 +00:00
|
|
|
func (p Player) ToCursor() (PlayerCursor, error) {
|
|
|
|
return NewPlayerCursor(
|
|
|
|
p.id,
|
|
|
|
p.serverKey,
|
|
|
|
p.od.scoreAtt,
|
|
|
|
p.od.scoreDef,
|
|
|
|
p.od.scoreSup,
|
|
|
|
p.od.scoreTotal,
|
|
|
|
p.points,
|
|
|
|
p.deletedAt,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p Player) Meta() PlayerMeta {
|
|
|
|
return PlayerMeta{
|
|
|
|
id: p.id,
|
|
|
|
name: p.name,
|
|
|
|
profileURL: p.profileURL,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2024-01-16 06:28:03 +00:00
|
|
|
func (p Player) IsZero() bool {
|
|
|
|
return p == Player{}
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
type Players []Player
|
|
|
|
|
2024-01-06 09:26:56 +00:00
|
|
|
// 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.
|
2024-01-01 10:20:30 +00:00
|
|
|
// Both slices must be sorted in ascending order by ID.
|
2024-01-06 09:26:56 +00:00
|
|
|
// + 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
|
2024-01-01 10:20:30 +00:00
|
|
|
//nolint:prealloc
|
|
|
|
var toDelete []int
|
2024-01-06 09:26:56 +00:00
|
|
|
var params []CreateTribeChangeParams
|
2024-01-01 10:20:30 +00:00
|
|
|
|
|
|
|
for _, p := range ps {
|
2024-01-06 09:26:56 +00:00
|
|
|
if p.IsDeleted() || p.ServerKey() != serverKey {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
_, 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())
|
2024-01-06 09:26:56 +00:00
|
|
|
|
|
|
|
if p.TribeID() > 0 {
|
|
|
|
p, err := NewCreateTribeChangeParams(serverKey, p.ID(), p.TribeID(), 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
params = append(params, p)
|
|
|
|
}
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 09:26:56 +00:00
|
|
|
return toDelete, params, nil
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 06:59:10 +00:00
|
|
|
type PlayerWithRelations struct {
|
|
|
|
player Player
|
|
|
|
tribe NullTribeMeta
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerWithRelations) Player() Player {
|
|
|
|
return p.player
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerWithRelations) Tribe() NullTribeMeta {
|
|
|
|
return p.tribe
|
|
|
|
}
|
|
|
|
|
2024-03-06 06:35:26 +00:00
|
|
|
func (p PlayerWithRelations) Meta() PlayerMetaWithRelations {
|
|
|
|
return PlayerMetaWithRelations{
|
|
|
|
player: p.player.Meta(),
|
|
|
|
tribe: p.tribe,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-28 06:59:10 +00:00
|
|
|
func (p PlayerWithRelations) IsZero() bool {
|
2024-03-06 06:35:26 +00:00
|
|
|
return p.player.IsZero()
|
|
|
|
}
|
|
|
|
|
|
|
|
type PlayersWithRelations []PlayerWithRelations
|
|
|
|
|
|
|
|
type PlayerMeta struct {
|
|
|
|
id int
|
|
|
|
name string
|
|
|
|
profileURL *url.URL
|
|
|
|
}
|
|
|
|
|
|
|
|
const playerMetaModelName = "PlayerMeta"
|
|
|
|
|
|
|
|
// UnmarshalPlayerMetaFromDatabase unmarshals PlayerMeta from the database.
|
|
|
|
//
|
|
|
|
// It should be used only for unmarshalling from the database!
|
|
|
|
// You can't use UnmarshalPlayerMetaFromDatabase as constructor - It may put domain into the invalid state!
|
|
|
|
func UnmarshalPlayerMetaFromDatabase(id int, name string, rawProfileURL string) (PlayerMeta, error) {
|
|
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
|
|
|
return PlayerMeta{}, ValidationError{
|
|
|
|
Model: playerMetaModelName,
|
|
|
|
Field: "id",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
profileURL, err := parseURL(rawProfileURL)
|
|
|
|
if err != nil {
|
|
|
|
return PlayerMeta{}, ValidationError{
|
|
|
|
Model: playerMetaModelName,
|
|
|
|
Field: "profileURL",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PlayerMeta{id: id, name: name, profileURL: profileURL}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMeta) ID() int {
|
|
|
|
return p.id
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMeta) Name() string {
|
|
|
|
return p.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMeta) ProfileURL() *url.URL {
|
2024-03-11 07:37:04 +00:00
|
|
|
if p.profileURL == nil {
|
|
|
|
return &url.URL{}
|
|
|
|
}
|
2024-03-06 06:35:26 +00:00
|
|
|
return p.profileURL
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMeta) IsZero() bool {
|
|
|
|
return p == PlayerMeta{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMeta) WithRelations(tribe NullTribeMeta) PlayerMetaWithRelations {
|
|
|
|
return PlayerMetaWithRelations{
|
|
|
|
player: p,
|
|
|
|
tribe: tribe,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 09:37:44 +00:00
|
|
|
type NullPlayerMeta NullValue[PlayerMeta]
|
|
|
|
|
2024-03-11 06:41:32 +00:00
|
|
|
func (p NullPlayerMeta) WithRelations(tribe NullTribeMeta) NullPlayerMetaWithRelations {
|
|
|
|
return NullPlayerMetaWithRelations{
|
|
|
|
V: PlayerMetaWithRelations{
|
|
|
|
player: p.V,
|
|
|
|
tribe: tribe,
|
|
|
|
},
|
|
|
|
Valid: !p.IsZero(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 09:37:44 +00:00
|
|
|
func (p NullPlayerMeta) IsZero() bool {
|
|
|
|
return !p.Valid
|
|
|
|
}
|
|
|
|
|
2024-03-06 06:35:26 +00:00
|
|
|
type PlayerMetaWithRelations struct {
|
|
|
|
player PlayerMeta
|
|
|
|
tribe NullTribeMeta
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMetaWithRelations) Player() PlayerMeta {
|
|
|
|
return p.player
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMetaWithRelations) Tribe() NullTribeMeta {
|
|
|
|
return p.tribe
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p PlayerMetaWithRelations) IsZero() bool {
|
|
|
|
return p.player.IsZero()
|
|
|
|
}
|
|
|
|
|
|
|
|
type NullPlayerMetaWithRelations NullValue[PlayerMetaWithRelations]
|
|
|
|
|
|
|
|
func (p NullPlayerMetaWithRelations) IsZero() bool {
|
|
|
|
return !p.Valid
|
2024-02-28 06:59:10 +00:00
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
const createPlayerParamsModelName = "CreatePlayerParams"
|
|
|
|
|
|
|
|
// NewCreatePlayerParams constructs a slice of CreatePlayerParams based on the given parameters.
|
|
|
|
// Both slices must be sorted in ascending order by ID
|
2024-01-02 09:54:11 +00:00
|
|
|
// + if storedPlayers contains players from different servers. they must be sorted in ascending order by server key.
|
2024-01-01 10:20:30 +00:00
|
|
|
//
|
|
|
|
//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 {
|
2024-02-09 08:49:23 +00:00
|
|
|
return cmp.Or(
|
|
|
|
cmp.Compare(a.ServerKey(), serverKey),
|
|
|
|
cmp.Compare(a.ID(), b.ID()),
|
|
|
|
)
|
2024-01-01 10:20:30 +00:00
|
|
|
})
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) Base() BasePlayer {
|
|
|
|
return params.base
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) ServerKey() string {
|
|
|
|
return params.serverKey
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) BestRank() int {
|
|
|
|
return params.bestRank
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) BestRankAt() time.Time {
|
|
|
|
return params.bestRankAt
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) MostPoints() int {
|
|
|
|
return params.mostPoints
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) MostPointsAt() time.Time {
|
|
|
|
return params.mostPointsAt
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) MostVillages() int {
|
|
|
|
return params.mostVillages
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) MostVillagesAt() time.Time {
|
|
|
|
return params.mostVillagesAt
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
func (params CreatePlayerParams) LastActivityAt() time.Time {
|
|
|
|
return params.lastActivityAt
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type PlayerSort uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
PlayerSortIDASC PlayerSort = iota + 1
|
|
|
|
PlayerSortIDDESC
|
|
|
|
PlayerSortServerKeyASC
|
|
|
|
PlayerSortServerKeyDESC
|
2024-02-27 07:09:24 +00:00
|
|
|
PlayerSortODScoreAttASC
|
|
|
|
PlayerSortODScoreAttDESC
|
|
|
|
PlayerSortODScoreDefASC
|
|
|
|
PlayerSortODScoreDefDESC
|
2024-03-03 06:43:07 +00:00
|
|
|
PlayerSortODScoreSupASC
|
|
|
|
PlayerSortODScoreSupDESC
|
2024-02-27 07:09:24 +00:00
|
|
|
PlayerSortODScoreTotalASC
|
|
|
|
PlayerSortODScoreTotalDESC
|
|
|
|
PlayerSortPointsASC
|
|
|
|
PlayerSortPointsDESC
|
|
|
|
PlayerSortDeletedAtASC
|
|
|
|
PlayerSortDeletedAtDESC
|
2024-01-01 10:20:30 +00:00
|
|
|
)
|
|
|
|
|
2024-03-05 06:14:41 +00:00
|
|
|
func newPlayerSortFromString(s string) (PlayerSort, error) {
|
|
|
|
allowed := []PlayerSort{
|
|
|
|
PlayerSortODScoreAttASC,
|
|
|
|
PlayerSortODScoreAttDESC,
|
|
|
|
PlayerSortODScoreDefASC,
|
|
|
|
PlayerSortODScoreDefDESC,
|
|
|
|
PlayerSortODScoreSupASC,
|
|
|
|
PlayerSortODScoreSupDESC,
|
|
|
|
PlayerSortODScoreTotalASC,
|
|
|
|
PlayerSortODScoreTotalDESC,
|
|
|
|
PlayerSortPointsASC,
|
|
|
|
PlayerSortPointsDESC,
|
|
|
|
PlayerSortDeletedAtASC,
|
|
|
|
PlayerSortDeletedAtDESC,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range allowed {
|
|
|
|
if strings.EqualFold(a.String(), s) {
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, UnsupportedSortStringError{
|
|
|
|
Sort: s,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-02 08:49:42 +00:00
|
|
|
// IsInConflict returns true if two sorts can't be used together (e.g. PlayerSortIDASC and PlayerSortIDDESC).
|
|
|
|
func (s PlayerSort) IsInConflict(s2 PlayerSort) bool {
|
|
|
|
ss := []PlayerSort{s, s2}
|
|
|
|
slices.Sort(ss)
|
|
|
|
// ASC is always an odd number, DESC is always an even number
|
|
|
|
return (ss[0]%2 == 1 && ss[0] == ss[1]-1) || ss[0] == ss[1]
|
|
|
|
}
|
|
|
|
|
2024-02-27 07:09:24 +00:00
|
|
|
//nolint:gocyclo
|
2024-03-02 08:49:42 +00:00
|
|
|
func (s PlayerSort) String() string {
|
|
|
|
switch s {
|
|
|
|
case PlayerSortIDASC:
|
|
|
|
return "id:ASC"
|
|
|
|
case PlayerSortIDDESC:
|
|
|
|
return "id:DESC"
|
|
|
|
case PlayerSortServerKeyASC:
|
|
|
|
return "serverKey:ASC"
|
|
|
|
case PlayerSortServerKeyDESC:
|
|
|
|
return "serverKey:DESC"
|
|
|
|
case PlayerSortODScoreAttASC:
|
|
|
|
return "odScoreAtt:ASC"
|
|
|
|
case PlayerSortODScoreAttDESC:
|
|
|
|
return "odScoreAtt:DESC"
|
|
|
|
case PlayerSortODScoreDefASC:
|
|
|
|
return "odScoreDef:ASC"
|
|
|
|
case PlayerSortODScoreDefDESC:
|
|
|
|
return "odScoreDef:DESC"
|
2024-03-03 06:43:07 +00:00
|
|
|
case PlayerSortODScoreSupASC:
|
|
|
|
return "odScoreSup:ASC"
|
|
|
|
case PlayerSortODScoreSupDESC:
|
|
|
|
return "odScoreSup:DESC"
|
2024-03-02 08:49:42 +00:00
|
|
|
case PlayerSortODScoreTotalASC:
|
|
|
|
return "odScoreTotal:ASC"
|
|
|
|
case PlayerSortODScoreTotalDESC:
|
|
|
|
return "odScoreTotal:DESC"
|
|
|
|
case PlayerSortPointsASC:
|
|
|
|
return "points:ASC"
|
|
|
|
case PlayerSortPointsDESC:
|
|
|
|
return "points:DESC"
|
|
|
|
case PlayerSortDeletedAtASC:
|
|
|
|
return "deletedAt:ASC"
|
|
|
|
case PlayerSortDeletedAtDESC:
|
|
|
|
return "deletedAt:DESC"
|
2024-02-27 07:09:24 +00:00
|
|
|
default:
|
2024-03-02 08:49:42 +00:00
|
|
|
return "unknown player sort"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
type PlayerCursor struct {
|
|
|
|
id int
|
|
|
|
serverKey string
|
|
|
|
odScoreAtt int
|
|
|
|
odScoreDef int
|
2024-03-03 06:43:07 +00:00
|
|
|
odScoreSup int
|
2024-02-26 06:44:39 +00:00
|
|
|
odScoreTotal int
|
|
|
|
points int
|
|
|
|
deletedAt time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
const playerCursorModelName = "PlayerCursor"
|
|
|
|
|
|
|
|
func NewPlayerCursor(
|
|
|
|
id int,
|
|
|
|
serverKey string,
|
|
|
|
odScoreAtt int,
|
|
|
|
odScoreDef int,
|
2024-03-03 06:43:07 +00:00
|
|
|
odScoreSup int,
|
2024-02-26 06:44:39 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-03 06:43:07 +00:00
|
|
|
if err := validateIntInRange(odScoreSup, 0, math.MaxInt); err != nil {
|
|
|
|
return PlayerCursor{}, ValidationError{
|
|
|
|
Model: playerCursorModelName,
|
|
|
|
Field: "odScoreSup",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
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,
|
2024-03-03 06:43:07 +00:00
|
|
|
odScoreSup: odScoreSup,
|
2024-02-26 06:44:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-03-03 06:43:07 +00:00
|
|
|
odScoreSup, err := m.int("odScoreSup")
|
|
|
|
if err != nil {
|
|
|
|
return PlayerCursor{}, ErrInvalidCursor
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
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,
|
2024-03-03 06:43:07 +00:00
|
|
|
odScoreSup,
|
2024-02-26 06:44:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-03-03 06:43:07 +00:00
|
|
|
func (pc PlayerCursor) ODScoreSup() int {
|
|
|
|
return pc.odScoreSup
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
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},
|
2024-03-03 06:43:07 +00:00
|
|
|
{"odScoreSup", pc.odScoreSup},
|
2024-02-26 06:44:39 +00:00
|
|
|
{"odScoreTotal", pc.odScoreTotal},
|
|
|
|
{"points", pc.points},
|
|
|
|
{"deletedAt", pc.deletedAt},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
type ListPlayersParams struct {
|
|
|
|
ids []int
|
|
|
|
serverKeys []string
|
2024-02-29 06:03:36 +00:00
|
|
|
names []string
|
2024-03-04 06:11:00 +00:00
|
|
|
tribeIDs []int
|
2024-01-01 10:20:30 +00:00
|
|
|
deleted NullBool
|
|
|
|
sort []PlayerSort
|
2024-02-26 06:44:39 +00:00
|
|
|
cursor PlayerCursor
|
2024-01-01 10:20:30 +00:00
|
|
|
limit int
|
|
|
|
}
|
|
|
|
|
2024-01-27 08:37:12 +00:00
|
|
|
const (
|
2024-03-11 07:16:29 +00:00
|
|
|
PlayerListMaxLimit = 500
|
2024-01-27 08:37:12 +00:00
|
|
|
listPlayersParamsModelName = "ListPlayersParams"
|
|
|
|
)
|
2024-01-01 10:20:30 +00:00
|
|
|
|
|
|
|
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 {
|
2024-02-28 06:59:10 +00:00
|
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
2024-01-01 10:20:30 +00:00
|
|
|
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 {
|
2024-03-03 06:23:46 +00:00
|
|
|
for i, sk := range serverKeys {
|
|
|
|
if err := validateServerKey(sk); err != nil {
|
|
|
|
return SliceElementValidationError{
|
|
|
|
Model: listPlayersParamsModelName,
|
|
|
|
Field: "serverKeys",
|
|
|
|
Index: i,
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
params.serverKeys = serverKeys
|
2024-03-03 06:23:46 +00:00
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-29 06:03:36 +00:00
|
|
|
func (params *ListPlayersParams) Names() []string {
|
|
|
|
return params.names
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2024-03-06 07:20:10 +00:00
|
|
|
playerNamesMinLength = 0
|
2024-02-29 06:03:36 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-03-04 06:11:00 +00:00
|
|
|
func (params *ListPlayersParams) TribeIDs() []int {
|
|
|
|
return params.tribeIDs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListPlayersParams) SetTribeIDs(tribeIDs []int) error {
|
|
|
|
for i, id := range tribeIDs {
|
|
|
|
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
|
|
|
return SliceElementValidationError{
|
|
|
|
Model: listPlayersParamsModelName,
|
|
|
|
Field: "tribeIDs",
|
|
|
|
Index: i,
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params.tribeIDs = tribeIDs
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
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
|
2024-02-27 07:09:24 +00:00
|
|
|
playerSortMaxLength = 3
|
2024-01-01 10:20:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (params *ListPlayersParams) SetSort(sort []PlayerSort) error {
|
2024-03-02 08:49:42 +00:00
|
|
|
if err := validateSort(sort, playerSortMinLength, playerSortMaxLength); err != nil {
|
2024-01-01 10:20:30 +00:00
|
|
|
return ValidationError{
|
|
|
|
Model: listPlayersParamsModelName,
|
|
|
|
Field: "sort",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params.sort = sort
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-02-27 07:09:24 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-02 08:49:42 +00:00
|
|
|
toPrepend := make([]PlayerSort, 0, len(sort))
|
|
|
|
|
|
|
|
for i, s := range sort {
|
|
|
|
converted, err := newPlayerSortFromString(s)
|
2024-02-27 07:09:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return SliceElementValidationError{
|
|
|
|
Model: listPlayersParamsModelName,
|
|
|
|
Field: "sort",
|
|
|
|
Index: i,
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
2024-03-02 08:49:42 +00:00
|
|
|
toPrepend = append(toPrepend, converted)
|
2024-02-27 07:09:24 +00:00
|
|
|
}
|
|
|
|
|
2024-03-02 08:49:42 +00:00
|
|
|
return params.SetSort(append(toPrepend, params.sort...))
|
2024-02-27 07:09:24 +00:00
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-01-01 10:20:30 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
type ListPlayersResult struct {
|
|
|
|
players Players
|
|
|
|
self PlayerCursor
|
|
|
|
next PlayerCursor
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
const listPlayersResultModelName = "ListPlayersResult"
|
|
|
|
|
|
|
|
func NewListPlayersResult(players Players, next Player) (ListPlayersResult, error) {
|
|
|
|
var err error
|
|
|
|
res := ListPlayersResult{
|
|
|
|
players: players,
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(players) > 0 {
|
2024-03-06 06:35:26 +00:00
|
|
|
res.self, err = players[0].ToCursor()
|
2024-02-26 06:44:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return ListPlayersResult{}, ValidationError{
|
|
|
|
Model: listPlayersResultModelName,
|
|
|
|
Field: "self",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !next.IsZero() {
|
2024-03-06 06:35:26 +00:00
|
|
|
res.next, err = next.ToCursor()
|
2024-02-26 06:44:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return ListPlayersResult{}, ValidationError{
|
|
|
|
Model: listPlayersResultModelName,
|
|
|
|
Field: "next",
|
|
|
|
Err: err,
|
|
|
|
}
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
return res, nil
|
|
|
|
}
|
2024-01-01 10:20:30 +00:00
|
|
|
|
2024-02-26 06:44:39 +00:00
|
|
|
func (res ListPlayersResult) Players() Players {
|
|
|
|
return res.players
|
|
|
|
}
|
|
|
|
|
|
|
|
func (res ListPlayersResult) Self() PlayerCursor {
|
|
|
|
return res.self
|
|
|
|
}
|
|
|
|
|
|
|
|
func (res ListPlayersResult) Next() PlayerCursor {
|
|
|
|
return res.next
|
2024-01-01 10:20:30 +00:00
|
|
|
}
|
2024-02-28 06:59:10 +00:00
|
|
|
|
|
|
|
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 {
|
2024-03-06 06:35:26 +00:00
|
|
|
res.self, err = players[0].Player().ToCursor()
|
2024-02-28 06:59:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return ListPlayersWithRelationsResult{}, ValidationError{
|
|
|
|
Model: listPlayersWithRelationsResultModelName,
|
|
|
|
Field: "self",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !next.IsZero() {
|
2024-03-06 06:35:26 +00:00
|
|
|
res.next, err = next.Player().ToCursor()
|
2024-02-28 06:59:10 +00:00
|
|
|
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
|
|
|
|
}
|
2024-02-29 06:25:01 +00:00
|
|
|
|
|
|
|
type PlayerNotFoundError struct {
|
|
|
|
ID int
|
|
|
|
ServerKey string
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ ErrorWithParams = PlayerNotFoundError{}
|
|
|
|
|
|
|
|
func (e PlayerNotFoundError) Error() string {
|
|
|
|
return fmt.Sprintf("player with id %d and server key %s not found", e.ID, e.ServerKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e PlayerNotFoundError) Type() ErrorType {
|
|
|
|
return ErrorTypeNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e PlayerNotFoundError) Code() string {
|
|
|
|
return "player-not-found"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e PlayerNotFoundError) Params() map[string]any {
|
|
|
|
return map[string]any{
|
|
|
|
"ID": e.ID,
|
|
|
|
"ServerKey": e.ServerKey,
|
|
|
|
}
|
|
|
|
}
|