package domain import ( "errors" "math" "time" ) type ServerSnapshot struct { id int serverKey string numPlayers int numActivePlayers int numInactivePlayers int numTribes int numActiveTribes int numInactiveTribes int numVillages int numPlayerVillages int numBarbarianVillages int numBonusVillages int date time.Time createdAt time.Time } const serverSnapshotModelName = "ServerSnapshot" // UnmarshalServerSnapshotFromDatabase unmarshals ServerSnapshot from the database. // // It should be used only for unmarshalling from the database! // You can't use UnmarshalServerSnapshotFromDatabase as constructor - It may put domain into the invalid state! func UnmarshalServerSnapshotFromDatabase( id int, serverKey string, numPlayers int, numActivePlayers int, numInactivePlayers int, numTribes int, numActiveTribes int, numInactiveTribes int, numVillages int, numPlayerVillages int, numBarbarianVillages int, numBonusVillages int, date time.Time, createdAt time.Time, ) (ServerSnapshot, error) { if err := validateIntInRange(id, 1, math.MaxInt); err != nil { return ServerSnapshot{}, ValidationError{ Model: serverSnapshotModelName, Field: "id", Err: err, } } if err := validateServerKey(serverKey); err != nil { return ServerSnapshot{}, ValidationError{ Model: serverSnapshotModelName, Field: "serverKey", Err: err, } } return ServerSnapshot{ id: id, serverKey: serverKey, numPlayers: numPlayers, numActivePlayers: numActivePlayers, numInactivePlayers: numInactivePlayers, numTribes: numTribes, numActiveTribes: numActiveTribes, numInactiveTribes: numInactiveTribes, numVillages: numVillages, numPlayerVillages: numPlayerVillages, numBarbarianVillages: numBarbarianVillages, numBonusVillages: numBonusVillages, date: date, createdAt: createdAt, }, nil } func (ss ServerSnapshot) ID() int { return ss.id } func (ss ServerSnapshot) ServerKey() string { return ss.serverKey } func (ss ServerSnapshot) NumPlayers() int { return ss.numPlayers } func (ss ServerSnapshot) NumActivePlayers() int { return ss.numActivePlayers } func (ss ServerSnapshot) NumInactivePlayers() int { return ss.numInactivePlayers } func (ss ServerSnapshot) NumTribes() int { return ss.numTribes } func (ss ServerSnapshot) NumActiveTribes() int { return ss.numActiveTribes } func (ss ServerSnapshot) NumInactiveTribes() int { return ss.numInactiveTribes } func (ss ServerSnapshot) NumVillages() int { return ss.numVillages } func (ss ServerSnapshot) NumPlayerVillages() int { return ss.numPlayerVillages } func (ss ServerSnapshot) NumBarbarianVillages() int { return ss.numBarbarianVillages } func (ss ServerSnapshot) NumBonusVillages() int { return ss.numBonusVillages } func (ss ServerSnapshot) Date() time.Time { return ss.date } func (ss ServerSnapshot) CreatedAt() time.Time { return ss.createdAt } func (ss ServerSnapshot) WithRelations(server ServerMeta) ServerSnapshotWithRelations { return ServerSnapshotWithRelations{ snapshot: ss, server: server, } } func (ss ServerSnapshot) ToCursor() (ServerSnapshotCursor, error) { return NewServerSnapshotCursor(ss.id, ss.serverKey, ss.date) } func (ss ServerSnapshot) IsZero() bool { return ss == ServerSnapshot{} } type ServerSnapshots []ServerSnapshot type ServerSnapshotWithRelations struct { snapshot ServerSnapshot server ServerMeta } func (ts ServerSnapshotWithRelations) ServerSnapshot() ServerSnapshot { return ts.snapshot } func (ts ServerSnapshotWithRelations) Server() ServerMeta { return ts.server } func (ts ServerSnapshotWithRelations) IsZero() bool { return ts.snapshot.IsZero() } type ServerSnapshotsWithRelations []ServerSnapshotWithRelations type CreateServerSnapshotParams struct { serverKey string numPlayers int numActivePlayers int numInactivePlayers int numTribes int numActiveTribes int numInactiveTribes int numVillages int numPlayerVillages int numBarbarianVillages int numBonusVillages int date time.Time } func NewCreateServerSnapshotParams(server Server, date time.Time) (CreateServerSnapshotParams, error) { if server.IsZero() { return CreateServerSnapshotParams{}, errors.New("given server is an empty struct") } if !server.Open() { return CreateServerSnapshotParams{}, errors.New("given server is closed") } return CreateServerSnapshotParams{ serverKey: server.Key(), numPlayers: server.NumPlayers(), numActivePlayers: server.NumActivePlayers(), numInactivePlayers: server.NumInactivePlayers(), numTribes: server.NumTribes(), numActiveTribes: server.NumActiveTribes(), numInactiveTribes: server.NumInactiveTribes(), numVillages: server.NumVillages(), numPlayerVillages: server.NumPlayerVillages(), numBarbarianVillages: server.NumBarbarianVillages(), numBonusVillages: server.NumBonusVillages(), date: date, }, nil } func (params CreateServerSnapshotParams) ServerKey() string { return params.serverKey } func (params CreateServerSnapshotParams) NumPlayers() int { return params.numPlayers } func (params CreateServerSnapshotParams) NumActivePlayers() int { return params.numActivePlayers } func (params CreateServerSnapshotParams) NumInactivePlayers() int { return params.numInactivePlayers } func (params CreateServerSnapshotParams) NumTribes() int { return params.numTribes } func (params CreateServerSnapshotParams) NumActiveTribes() int { return params.numActiveTribes } func (params CreateServerSnapshotParams) NumInactiveTribes() int { return params.numInactiveTribes } func (params CreateServerSnapshotParams) NumVillages() int { return params.numVillages } func (params CreateServerSnapshotParams) NumPlayerVillages() int { return params.numPlayerVillages } func (params CreateServerSnapshotParams) NumBarbarianVillages() int { return params.numBarbarianVillages } func (params CreateServerSnapshotParams) NumBonusVillages() int { return params.numBonusVillages } func (params CreateServerSnapshotParams) Date() time.Time { return params.date } type ServerSnapshotSort uint8 const ( ServerSnapshotSortDateASC ServerSnapshotSort = iota + 1 ServerSnapshotSortDateDESC ServerSnapshotSortIDASC ServerSnapshotSortIDDESC ServerSnapshotSortServerKeyASC ServerSnapshotSortServerKeyDESC ) // IsInConflict returns true if two sorts can't be used together // (e.g. ServerSnapshotSortIDASC and ServerSnapshotSortIDDESC). func (s ServerSnapshotSort) IsInConflict(s2 ServerSnapshotSort) bool { return isSortInConflict(s, s2) } //nolint:gocyclo func (s ServerSnapshotSort) String() string { switch s { case ServerSnapshotSortDateASC: return "date:ASC" case ServerSnapshotSortDateDESC: return "date:DESC" case ServerSnapshotSortIDASC: return "id:ASC" case ServerSnapshotSortIDDESC: return "id:DESC" case ServerSnapshotSortServerKeyASC: return "serverKey:ASC" case ServerSnapshotSortServerKeyDESC: return "serverKey:DESC" default: return "unknown server snapshot sort" } } type ServerSnapshotCursor struct { id int serverKey string date time.Time } const serverSnapshotCursorModelName = "ServerSnapshotCursor" func NewServerSnapshotCursor(id int, serverKey string, date time.Time) (ServerSnapshotCursor, error) { if err := validateIntInRange(id, 1, math.MaxInt); err != nil { return ServerSnapshotCursor{}, ValidationError{ Model: serverSnapshotCursorModelName, Field: "id", Err: err, } } if err := validateServerKey(serverKey); err != nil { return ServerSnapshotCursor{}, ValidationError{ Model: serverSnapshotCursorModelName, Field: "serverKey", Err: err, } } return ServerSnapshotCursor{ id: id, serverKey: serverKey, date: date, }, nil } func decodeServerSnapshotCursor(encoded string) (ServerSnapshotCursor, error) { m, err := decodeCursor(encoded) if err != nil { return ServerSnapshotCursor{}, err } id, err := m.int("id") if err != nil { return ServerSnapshotCursor{}, ErrInvalidCursor } serverKey, err := m.string("serverKey") if err != nil { return ServerSnapshotCursor{}, ErrInvalidCursor } date, err := m.time("date") if err != nil { return ServerSnapshotCursor{}, ErrInvalidCursor } tsc, err := NewServerSnapshotCursor( id, serverKey, date, ) if err != nil { return ServerSnapshotCursor{}, ErrInvalidCursor } return tsc, nil } func (ssc ServerSnapshotCursor) ID() int { return ssc.id } func (ssc ServerSnapshotCursor) ServerKey() string { return ssc.serverKey } func (ssc ServerSnapshotCursor) Date() time.Time { return ssc.date } func (ssc ServerSnapshotCursor) IsZero() bool { return ssc == ServerSnapshotCursor{} } func (ssc ServerSnapshotCursor) Encode() string { if ssc.IsZero() { return "" } return encodeCursor([]keyValuePair{ {"id", ssc.id}, {"serverKey", ssc.serverKey}, {"date", ssc.date}, }) } type ListServerSnapshotsParams struct { serverKeys []string sort []ServerSnapshotSort cursor ServerSnapshotCursor limit int } const ( ServerSnapshotListMaxLimit = 500 listServerSnapshotsParamsModelName = "ListServerSnapshotsParams" ) func NewListServerSnapshotsParams() ListServerSnapshotsParams { return ListServerSnapshotsParams{ sort: []ServerSnapshotSort{ ServerSnapshotSortServerKeyASC, ServerSnapshotSortDateASC, ServerSnapshotSortIDASC, }, limit: ServerSnapshotListMaxLimit, } } func (params *ListServerSnapshotsParams) ServerKeys() []string { return params.serverKeys } func (params *ListServerSnapshotsParams) SetServerKeys(serverKeys []string) error { for i, sk := range serverKeys { if err := validateServerKey(sk); err != nil { return SliceElementValidationError{ Model: listServerSnapshotsParamsModelName, Field: "serverKeys", Index: i, Err: err, } } } params.serverKeys = serverKeys return nil } func (params *ListServerSnapshotsParams) Sort() []ServerSnapshotSort { return params.sort } const ( serverSnapshotSortMinLength = 0 serverSnapshotSortMaxLength = 3 ) func (params *ListServerSnapshotsParams) SetSort(sort []ServerSnapshotSort) error { if err := validateSort(sort, serverSnapshotSortMinLength, serverSnapshotSortMaxLength); err != nil { return ValidationError{ Model: listServerSnapshotsParamsModelName, Field: "sort", Err: err, } } params.sort = sort return nil } func (params *ListServerSnapshotsParams) PrependSort(sort []ServerSnapshotSort) error { if len(sort) == 0 { return nil } if err := validateSliceLen(sort, 0, max(serverSnapshotSortMaxLength-len(params.sort), 0)); err != nil { return ValidationError{ Model: listServerSnapshotsParamsModelName, Field: "sort", Err: err, } } return params.SetSort(append(sort, params.sort...)) } func (params *ListServerSnapshotsParams) PrependSortString( sort []string, allowed []ServerSnapshotSort, maxLength int, ) error { if len(sort) == 0 { return nil } if err := validateSliceLen(sort, 0, max(min(serverSnapshotSortMaxLength-len(params.sort), maxLength), 0)); err != nil { return ValidationError{ Model: listServerSnapshotsParamsModelName, Field: "sort", Err: err, } } toPrepend := make([]ServerSnapshotSort, 0, len(sort)) for i, s := range sort { converted, err := newSortFromString(s, allowed...) if err != nil { return SliceElementValidationError{ Model: listServerSnapshotsParamsModelName, Field: "sort", Index: i, Err: err, } } toPrepend = append(toPrepend, converted) } return params.SetSort(append(toPrepend, params.sort...)) } func (params *ListServerSnapshotsParams) Cursor() ServerSnapshotCursor { return params.cursor } func (params *ListServerSnapshotsParams) SetCursor(cursor ServerSnapshotCursor) error { params.cursor = cursor return nil } func (params *ListServerSnapshotsParams) SetEncodedCursor(encoded string) error { decoded, err := decodeServerSnapshotCursor(encoded) if err != nil { return ValidationError{ Model: listServerSnapshotsParamsModelName, Field: "cursor", Err: err, } } params.cursor = decoded return nil } func (params *ListServerSnapshotsParams) Limit() int { return params.limit } func (params *ListServerSnapshotsParams) SetLimit(limit int) error { if err := validateIntInRange(limit, 1, ServerSnapshotListMaxLimit); err != nil { return ValidationError{ Model: listServerSnapshotsParamsModelName, Field: "limit", Err: err, } } params.limit = limit return nil } type ListServerSnapshotsResult struct { snapshots ServerSnapshots self ServerSnapshotCursor next ServerSnapshotCursor } const listServerSnapshotsResultModelName = "ListServerSnapshotsResult" func NewListServerSnapshotsResult( snapshots ServerSnapshots, next ServerSnapshot, ) (ListServerSnapshotsResult, error) { var err error res := ListServerSnapshotsResult{ snapshots: snapshots, } if len(snapshots) > 0 { res.self, err = snapshots[0].ToCursor() if err != nil { return ListServerSnapshotsResult{}, ValidationError{ Model: listServerSnapshotsResultModelName, Field: "self", Err: err, } } } if !next.IsZero() { res.next, err = next.ToCursor() if err != nil { return ListServerSnapshotsResult{}, ValidationError{ Model: listServerSnapshotsResultModelName, Field: "next", Err: err, } } } return res, nil } func (res ListServerSnapshotsResult) ServerSnapshots() ServerSnapshots { return res.snapshots } func (res ListServerSnapshotsResult) Self() ServerSnapshotCursor { return res.self } func (res ListServerSnapshotsResult) Next() ServerSnapshotCursor { return res.next } type ListServerSnapshotsWithRelationsResult struct { snapshots ServerSnapshotsWithRelations self ServerSnapshotCursor next ServerSnapshotCursor } const listServerSnapshotsWithRelationsResultModelName = "ListServerSnapshotsWithRelationsResult" func NewListServerSnapshotsWithRelationsResult( snapshots ServerSnapshotsWithRelations, next ServerSnapshotWithRelations, ) (ListServerSnapshotsWithRelationsResult, error) { var err error res := ListServerSnapshotsWithRelationsResult{ snapshots: snapshots, } if len(snapshots) > 0 { res.self, err = snapshots[0].ServerSnapshot().ToCursor() if err != nil { return ListServerSnapshotsWithRelationsResult{}, ValidationError{ Model: listServerSnapshotsWithRelationsResultModelName, Field: "self", Err: err, } } } if !next.IsZero() { res.next, err = next.ServerSnapshot().ToCursor() if err != nil { return ListServerSnapshotsWithRelationsResult{}, ValidationError{ Model: listServerSnapshotsWithRelationsResultModelName, Field: "next", Err: err, } } } return res, nil } func (res ListServerSnapshotsWithRelationsResult) ServerSnapshots() ServerSnapshotsWithRelations { return res.snapshots } func (res ListServerSnapshotsWithRelationsResult) Self() ServerSnapshotCursor { return res.self } func (res ListServerSnapshotsWithRelationsResult) Next() ServerSnapshotCursor { return res.next }