core/internal/domain/player.go

1210 lines
25 KiB
Go

package domain
import (
"cmp"
"fmt"
"math"
"net/url"
"slices"
"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 {
if p.profileURL == nil {
return &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(server ServerMeta, tribe NullTribeMeta) PlayerWithRelations {
return PlayerWithRelations{
player: p,
server: server,
tribe: tribe,
}
}
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,
}
}
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{}
}
// active players must be sorted in ascending order by ID
func (p Player) canBeDeleted(serverKey string, active BasePlayers) bool {
if p.IsDeleted() {
return false
}
if p.serverKey != serverKey {
return false
}
_, found := slices.BinarySearchFunc(active, p, func(a BasePlayer, b Player) int {
return cmp.Compare(a.ID(), b.id)
})
return !found
}
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.canBeDeleted(serverKey, active) {
continue
}
toDelete = append(toDelete, p.ID())
if p.TribeID() > 0 {
ctcParams, err := NewCreateTribeChangeParams(serverKey, p.ID(), p.TribeID(), 0)
if err != nil {
return nil, nil, err
}
params = append(params, ctcParams)
}
}
return toDelete, params, nil
}
type PlayerWithRelations struct {
player Player
server ServerMeta
tribe NullTribeMeta
}
func (p PlayerWithRelations) Player() Player {
return p.player
}
func (p PlayerWithRelations) Server() ServerMeta {
return p.server
}
func (p PlayerWithRelations) Tribe() NullTribeMeta {
return p.tribe
}
func (p PlayerWithRelations) Meta() PlayerMetaWithRelations {
return PlayerMetaWithRelations{
player: p.player.Meta(),
tribe: p.tribe,
}
}
func (p PlayerWithRelations) IsZero() bool {
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 {
if p.profileURL == nil {
return &url.URL{}
}
return p.profileURL
}
func (p PlayerMeta) IsZero() bool {
return p == PlayerMeta{}
}
func (p PlayerMeta) WithRelations(tribe NullTribeMeta) PlayerMetaWithRelations {
return PlayerMetaWithRelations{
player: p,
tribe: tribe,
}
}
type NullPlayerMeta NullValue[PlayerMeta]
func (p NullPlayerMeta) WithRelations(tribe NullTribeMeta) NullPlayerMetaWithRelations {
return NullPlayerMetaWithRelations{
V: PlayerMetaWithRelations{
player: p.V,
tribe: tribe,
},
Valid: !p.IsZero(),
}
}
func (p NullPlayerMeta) IsZero() bool {
return !p.Valid
}
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
}
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
// + 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
PlayerSortODScoreSupASC
PlayerSortODScoreSupDESC
PlayerSortODScoreTotalASC
PlayerSortODScoreTotalDESC
PlayerSortPointsASC
PlayerSortPointsDESC
PlayerSortDeletedAtASC
PlayerSortDeletedAtDESC
)
// IsInConflict returns true if two sorts can't be used together (e.g. PlayerSortIDASC and PlayerSortIDDESC).
func (s PlayerSort) IsInConflict(s2 PlayerSort) bool {
return isSortInConflict(s, s2)
}
//nolint:gocyclo
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"
case PlayerSortODScoreSupASC:
return "odScoreSup:ASC"
case PlayerSortODScoreSupDESC:
return "odScoreSup:DESC"
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"
default:
return "unknown player sort"
}
}
type PlayerCursor struct {
id int
serverKey string
odScoreAtt int
odScoreDef int
odScoreSup int
odScoreTotal int
points int
deletedAt time.Time
}
const playerCursorModelName = "PlayerCursor"
func NewPlayerCursor(
id int,
serverKey string,
odScoreAtt int,
odScoreDef int,
odScoreSup 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(odScoreSup, 0, math.MaxInt); err != nil {
return PlayerCursor{}, ValidationError{
Model: playerCursorModelName,
Field: "odScoreSup",
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,
odScoreSup: odScoreSup,
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
}
odScoreSup, err := m.int("odScoreSup")
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,
odScoreSup,
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) ODScoreSup() int {
return pc.odScoreSup
}
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},
{"odScoreSup", pc.odScoreSup},
{"odScoreTotal", pc.odScoreTotal},
{"points", pc.points},
{"deletedAt", pc.deletedAt},
})
}
type ListPlayersParams struct {
ids []int
serverKeys []string
versionCodes []string
names []string
tribeIDs []int
deleted NullBool
sort []PlayerSort
cursor PlayerCursor
limit int
}
const (
PlayerListMaxLimit = 500
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 {
for i, sk := range serverKeys {
if err := validateServerKey(sk); err != nil {
return SliceElementValidationError{
Model: listPlayersParamsModelName,
Field: "serverKeys",
Index: i,
Err: err,
}
}
}
params.serverKeys = serverKeys
return nil
}
func (params *ListPlayersParams) VersionCodes() []string {
return params.versionCodes
}
func (params *ListPlayersParams) SetVersionCodes(versionCodes []string) error {
for i, vc := range versionCodes {
if err := validateVersionCode(vc); err != nil {
return SliceElementValidationError{
Model: listPlayersParamsModelName,
Field: "versionCodes",
Index: i,
Err: err,
}
}
}
params.versionCodes = versionCodes
return nil
}
func (params *ListPlayersParams) Names() []string {
return params.names
}
const (
playerNamesMinLength = 0
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) 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
}
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 = 0
playerSortMaxLength = 4
)
func (params *ListPlayersParams) SetSort(sort []PlayerSort) error {
if err := validateSort(sort, playerSortMinLength, playerSortMaxLength); err != nil {
return ValidationError{
Model: listPlayersParamsModelName,
Field: "sort",
Err: err,
}
}
params.sort = sort
return nil
}
func (params *ListPlayersParams) PrependSort(sort []PlayerSort) error {
if len(sort) == 0 {
return nil
}
if err := validateSliceLen(sort, 0, max(playerSortMaxLength-len(params.sort), 0)); err != nil {
return ValidationError{
Model: listPlayersParamsModelName,
Field: "sort",
Err: err,
}
}
return params.SetSort(append(sort, params.sort...))
}
func (params *ListPlayersParams) PrependSortString(sort []string, allowed []PlayerSort, maxLength int) error {
if len(sort) == 0 {
return nil
}
if err := validateSliceLen(sort, 0, max(min(playerSortMaxLength-len(params.sort), maxLength), 0)); err != nil {
return ValidationError{
Model: listPlayersParamsModelName,
Field: "sort",
Err: err,
}
}
toPrepend := make([]PlayerSort, 0, len(sort))
for i, s := range sort {
converted, err := newSortFromString(s, allowed...)
if err != nil {
return SliceElementValidationError{
Model: listPlayersParamsModelName,
Field: "sort",
Index: i,
Err: err,
}
}
toPrepend = append(toPrepend, converted)
}
return params.SetSort(append(toPrepend, params.sort...))
}
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 {
res.self, err = players[0].ToCursor()
if err != nil {
return ListPlayersResult{}, ValidationError{
Model: listPlayersResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.ToCursor()
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 {
res.self, err = players[0].Player().ToCursor()
if err != nil {
return ListPlayersWithRelationsResult{}, ValidationError{
Model: listPlayersWithRelationsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.Player().ToCursor()
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
}
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
}
const errorCodePlayerNotFound = "player-not-found"
func (e PlayerNotFoundError) Code() string {
return errorCodePlayerNotFound
}
func (e PlayerNotFoundError) Params() map[string]any {
return map[string]any{
"ID": e.ID,
"ServerKey": e.ServerKey,
}
}