Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
23880225e0 | |||
36568adf46 | |||
847f5d6b85 | |||
86d78c0f0c | |||
51a6270812 | |||
4db3fee03f | |||
cf3eb9053d | |||
9d5987f74c | |||
4ca2ea9361 | |||
6e2c54679e | |||
7de443c652 |
|
@ -505,6 +505,9 @@ issues:
|
||||||
linters:
|
linters:
|
||||||
- gosec
|
- gosec
|
||||||
- gocyclo
|
- gocyclo
|
||||||
|
- path: server_map.go
|
||||||
|
linters:
|
||||||
|
- mnd
|
||||||
- path: _test\.go
|
- path: _test\.go
|
||||||
text: add-constant
|
text: add-constant
|
||||||
- path: bun/migrations
|
- path: bun/migrations
|
||||||
|
|
|
@ -6,7 +6,7 @@ repos:
|
||||||
stages: [commit-msg]
|
stages: [commit-msg]
|
||||||
additional_dependencies: ["@commitlint/config-conventional"]
|
additional_dependencies: ["@commitlint/config-conventional"]
|
||||||
- repo: https://github.com/golangci/golangci-lint
|
- repo: https://github.com/golangci/golangci-lint
|
||||||
rev: v1.58.1
|
rev: v1.59.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: golangci-lint
|
- id: golangci-lint
|
||||||
- repo: https://github.com/hadolint/hadolint
|
- repo: https://github.com/hadolint/hadolint
|
||||||
|
|
|
@ -42,7 +42,7 @@ steps:
|
||||||
- go test -parallel 2 -race -coverprofile=coverage.txt -covermode=atomic ./...
|
- go test -parallel 2 -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
image: golangci/golangci-lint:v1.58
|
image: golangci/golangci-lint:v1.59
|
||||||
pull: true
|
pull: true
|
||||||
depends_on:
|
depends_on:
|
||||||
- generate
|
- generate
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -16,7 +16,7 @@ install-git-hooks:
|
||||||
.PHONY: install-golangci-lint
|
.PHONY: install-golangci-lint
|
||||||
install-golangci-lint:
|
install-golangci-lint:
|
||||||
@echo "Installing github.com/golangci/golangci-lint..."
|
@echo "Installing github.com/golangci/golangci-lint..."
|
||||||
@(test -f $(GOLANGCI_LINT_PATH) && echo "github.com/golangci/golangci-lint is already installed. Skipping...") || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.58.1
|
@(test -f $(GOLANGCI_LINT_PATH) && echo "github.com/golangci/golangci-lint is already installed. Skipping...") || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.59.0
|
||||||
|
|
||||||
.PHONY: install-oapi-codegen
|
.PHONY: install-oapi-codegen
|
||||||
install-oapi-codegen:
|
install-oapi-codegen:
|
||||||
|
|
120
api/openapi3.yml
120
api/openapi3.yml
|
@ -471,6 +471,25 @@ paths:
|
||||||
$ref: "#/components/responses/ListTribeChangesResponse"
|
$ref: "#/components/responses/ListTribeChangesResponse"
|
||||||
default:
|
default:
|
||||||
$ref: "#/components/responses/ErrorResponse"
|
$ref: "#/components/responses/ErrorResponse"
|
||||||
|
/v2/versions/{versionCode}/servers/{serverKey}/snapshots:
|
||||||
|
get:
|
||||||
|
operationId: listServerServerSnapshots
|
||||||
|
tags:
|
||||||
|
- versions
|
||||||
|
- servers
|
||||||
|
- snapshots
|
||||||
|
description: List the given server's snapshots
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/VersionCodePathParam"
|
||||||
|
- $ref: "#/components/parameters/ServerKeyPathParam"
|
||||||
|
- $ref: "#/components/parameters/CursorQueryParam"
|
||||||
|
- $ref: "#/components/parameters/LimitQueryParam"
|
||||||
|
- $ref: "#/components/parameters/ServerSnapshotSortQueryParam"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: "#/components/responses/ListServerSnapshotsResponse"
|
||||||
|
default:
|
||||||
|
$ref: "#/components/responses/ErrorResponse"
|
||||||
/v2/versions/{versionCode}/servers/{serverKey}/tribes/{tribeId}/snapshots:
|
/v2/versions/{versionCode}/servers/{serverKey}/tribes/{tribeId}/snapshots:
|
||||||
get:
|
get:
|
||||||
operationId: listTribeTribeSnapshots
|
operationId: listTribeTribeSnapshots
|
||||||
|
@ -1594,6 +1613,52 @@ components:
|
||||||
createdAt:
|
createdAt:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
ServerSnapshot:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- server
|
||||||
|
- numPlayers
|
||||||
|
- numActivePlayers
|
||||||
|
- numInactivePlayers
|
||||||
|
- numTribes
|
||||||
|
- numActiveTribes
|
||||||
|
- numInactiveTribes
|
||||||
|
- numVillages
|
||||||
|
- numBarbarianVillages
|
||||||
|
- numBonusVillages
|
||||||
|
- numPlayerVillages
|
||||||
|
- date
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: "#/components/schemas/IntId"
|
||||||
|
server:
|
||||||
|
$ref: "#/components/schemas/ServerMeta"
|
||||||
|
numPlayers:
|
||||||
|
type: integer
|
||||||
|
description: numActivePlayers+numInactivePlayers
|
||||||
|
numActivePlayers:
|
||||||
|
type: integer
|
||||||
|
numInactivePlayers:
|
||||||
|
type: integer
|
||||||
|
numTribes:
|
||||||
|
type: integer
|
||||||
|
description: numActiveTribes+numInactiveTribes
|
||||||
|
numActiveTribes:
|
||||||
|
type: integer
|
||||||
|
numInactiveTribes:
|
||||||
|
type: integer
|
||||||
|
numVillages:
|
||||||
|
type: integer
|
||||||
|
numBarbarianVillages:
|
||||||
|
type: integer
|
||||||
|
numBonusVillages:
|
||||||
|
type: integer
|
||||||
|
numPlayerVillages:
|
||||||
|
type: integer
|
||||||
|
date:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
TribeSnapshot:
|
TribeSnapshot:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
@ -1675,7 +1740,7 @@ components:
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/CursorString"
|
- $ref: "#/components/schemas/CursorString"
|
||||||
PaginationResponse:
|
Pagination:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
cursor:
|
cursor:
|
||||||
|
@ -1729,6 +1794,8 @@ components:
|
||||||
- odScoreTotal:DESC
|
- odScoreTotal:DESC
|
||||||
- points:ASC
|
- points:ASC
|
||||||
- points:DESC
|
- points:DESC
|
||||||
|
- mostPoints:ASC
|
||||||
|
- mostPoints:DESC
|
||||||
- dominance:ASC
|
- dominance:ASC
|
||||||
- dominance:DESC
|
- dominance:DESC
|
||||||
- deletedAt:ASC
|
- deletedAt:ASC
|
||||||
|
@ -1769,6 +1836,8 @@ components:
|
||||||
- odScoreTotal:DESC
|
- odScoreTotal:DESC
|
||||||
- points:ASC
|
- points:ASC
|
||||||
- points:DESC
|
- points:DESC
|
||||||
|
- mostPoints:ASC
|
||||||
|
- mostPoints:DESC
|
||||||
- deletedAt:ASC
|
- deletedAt:ASC
|
||||||
- deletedAt:DESC
|
- deletedAt:DESC
|
||||||
maxItems: 2
|
maxItems: 2
|
||||||
|
@ -1840,6 +1909,20 @@ components:
|
||||||
- date:ASC
|
- date:ASC
|
||||||
- date:DESC
|
- date:DESC
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
ServerSnapshotSortQueryParam:
|
||||||
|
name: sort
|
||||||
|
in: query
|
||||||
|
description: Order matters!
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
default:
|
||||||
|
- date:ASC
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- date:ASC
|
||||||
|
- date:DESC
|
||||||
|
maxItems: 1
|
||||||
PlayerSnapshotSortQueryParam:
|
PlayerSnapshotSortQueryParam:
|
||||||
name: sort
|
name: sort
|
||||||
in: query
|
in: query
|
||||||
|
@ -1905,7 +1988,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -1931,7 +2014,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -1990,7 +2073,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2016,7 +2099,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2031,7 +2114,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2057,7 +2140,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2083,7 +2166,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2098,7 +2181,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2107,13 +2190,28 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/TribeChange"
|
$ref: "#/components/schemas/TribeChange"
|
||||||
|
ListServerSnapshotsResponse:
|
||||||
|
description: ""
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/Pagination"
|
||||||
|
- type: object
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/ServerSnapshot"
|
||||||
ListTribeSnapshotsResponse:
|
ListTribeSnapshotsResponse:
|
||||||
description: ""
|
description: ""
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
@ -2128,7 +2226,7 @@ components:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "#/components/schemas/PaginationResponse"
|
- $ref: "#/components/schemas/Pagination"
|
||||||
- type: object
|
- type: object
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM --platform=$BUILDPLATFORM alpine:3.19
|
FROM alpine:3.20
|
||||||
LABEL maintainer="contact@twhelp.app"
|
LABEL maintainer="contact@twhelp.app"
|
||||||
|
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
|
|
|
@ -1,33 +1,27 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/importer"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"go/types"
|
"go/types"
|
||||||
"io/fs"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if _, err := os.Stat("./go.mod"); errors.Is(err, os.ErrNotExist) {
|
if err := generateYAML("gitea.dwysokinski.me/twhelp/core/internal/domain"); err != nil {
|
||||||
log.Fatalln("go.mod not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := generateYAML("./internal/domain"); err != nil {
|
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateYAML(root string) error {
|
func generateYAML(pkgPattern string) error {
|
||||||
m, err := getErrorCodesFromFolder(root)
|
m, err := getErrorCodesFromPackage(pkgPattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,6 +42,8 @@ func generateYAML(root string) error {
|
||||||
enum = append(enum, c)
|
enum = append(enum, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slices.Sort(enum)
|
||||||
|
|
||||||
return yaml.NewEncoder(os.Stdout).Encode(struct {
|
return yaml.NewEncoder(os.Stdout).Encode(struct {
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Description string `yaml:"description"`
|
Description string `yaml:"description"`
|
||||||
|
@ -60,27 +56,25 @@ func generateYAML(root string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
func getErrorCodesFromFolder(root string) (map[string]string, error) {
|
func getErrorCodesFromPackage(pkgPattern string) (map[string]string, error) {
|
||||||
fset := token.NewFileSet()
|
pkg, err := packages.Load(&packages.Config{
|
||||||
|
Tests: false,
|
||||||
astDomainPkg, err := parseDomainPackage(fset, root)
|
Mode: packages.NeedName |
|
||||||
|
packages.NeedFiles |
|
||||||
|
packages.NeedCompiledGoFiles |
|
||||||
|
packages.NeedTypes |
|
||||||
|
packages.NeedTypesInfo |
|
||||||
|
packages.NeedSyntax,
|
||||||
|
}, pkgPattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(pkg) == 0 {
|
||||||
conf := types.Config{Importer: importer.Default()}
|
return nil, fmt.Errorf("'%s': pkg not found", pkgPattern)
|
||||||
|
|
||||||
files := make([]*ast.File, 0, len(astDomainPkg.Files))
|
|
||||||
for _, f := range astDomainPkg.Files {
|
|
||||||
files = append(files, f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
domainPkg, err := conf.Check(astDomainPkg.Name, fset, files, nil)
|
domainPkg := pkg[0]
|
||||||
if err != nil {
|
scope := domainPkg.Types.Scope()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
scope := domainPkg.Scope()
|
|
||||||
|
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
|
|
||||||
for _, n := range scope.Names() {
|
for _, n := range scope.Names() {
|
||||||
|
@ -95,14 +89,21 @@ func getErrorCodesFromFolder(root string) (map[string]string, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
f := astDomainPkg.Files[fset.File(c.Pos()).Name()]
|
filename := domainPkg.Fset.File(c.Pos()).Name()
|
||||||
position := fset.Position(c.Pos())
|
fileIdx := slices.IndexFunc(domainPkg.GoFiles, func(f string) bool {
|
||||||
commentMap := ast.NewCommentMap(fset, f, f.Comments)
|
return f == filename
|
||||||
|
})
|
||||||
|
if fileIdx < 0 {
|
||||||
|
return nil, fmt.Errorf("'%s': file not found", filename)
|
||||||
|
}
|
||||||
|
f := domainPkg.Syntax[fileIdx]
|
||||||
|
position := domainPkg.Fset.Position(c.Pos())
|
||||||
|
commentMap := ast.NewCommentMap(domainPkg.Fset, f, f.Comments)
|
||||||
|
|
||||||
var desc string
|
var desc string
|
||||||
|
|
||||||
for _, decl := range f.Decls {
|
for _, decl := range f.Decls {
|
||||||
declPosition := fset.Position(decl.Pos())
|
declPosition := domainPkg.Fset.Position(decl.Pos())
|
||||||
if declPosition.Filename != position.Filename || declPosition.Line != position.Line {
|
if declPosition.Filename != position.Filename || declPosition.Line != position.Line {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -123,27 +124,3 @@ func getErrorCodesFromFolder(root string) (map[string]string, error) {
|
||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDomainPackage(fset *token.FileSet, root string) (*ast.Package, error) {
|
|
||||||
pkgs, err := parser.ParseDir(fset, root, func(info fs.FileInfo) bool {
|
|
||||||
if info.IsDir() && info.Name() != root {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.IsDir() || strings.HasSuffix(info.Name(), "_test.go") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}, parser.AllErrors|parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
astDomainPkg, ok := pkgs["domain"]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("domain pkg not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return astDomainPkg, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,8 +59,9 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func newBunDBFromFlags(c *cli.Context) (*bun.DB, error) {
|
func newBunDBFromFlags(c *cli.Context, applicationName string) (*bun.DB, error) {
|
||||||
return newBunDB(bundDBConfig{
|
return newBunDB(bundDBConfig{
|
||||||
|
applicationName: applicationName,
|
||||||
connectionString: c.String(dbFlagConnectionString.Name),
|
connectionString: c.String(dbFlagConnectionString.Name),
|
||||||
maxOpenConns: c.Int(dbFlagMaxOpenConns.Name),
|
maxOpenConns: c.Int(dbFlagMaxOpenConns.Name),
|
||||||
maxIdleConns: c.Int(dbFlagMaxIdleConns.Name),
|
maxIdleConns: c.Int(dbFlagMaxIdleConns.Name),
|
||||||
|
@ -72,6 +73,7 @@ func newBunDBFromFlags(c *cli.Context) (*bun.DB, error) {
|
||||||
|
|
||||||
type bundDBConfig struct {
|
type bundDBConfig struct {
|
||||||
connectionString string
|
connectionString string
|
||||||
|
applicationName string
|
||||||
maxOpenConns int
|
maxOpenConns int
|
||||||
maxIdleConns int
|
maxIdleConns int
|
||||||
connMaxLifetime time.Duration
|
connMaxLifetime time.Duration
|
||||||
|
@ -99,6 +101,7 @@ func newSQLDB(cfg bundDBConfig) *sql.DB {
|
||||||
pgdriver.WithDSN(cfg.connectionString),
|
pgdriver.WithDSN(cfg.connectionString),
|
||||||
pgdriver.WithReadTimeout(cfg.readTimeout),
|
pgdriver.WithReadTimeout(cfg.readTimeout),
|
||||||
pgdriver.WithWriteTimeout(cfg.writeTimeout),
|
pgdriver.WithWriteTimeout(cfg.writeTimeout),
|
||||||
|
pgdriver.WithApplicationName(cfg.applicationName),
|
||||||
))
|
))
|
||||||
db.SetMaxOpenConns(cfg.maxOpenConns)
|
db.SetMaxOpenConns(cfg.maxOpenConns)
|
||||||
db.SetMaxIdleConns(cfg.maxIdleConns)
|
db.SetMaxIdleConns(cfg.maxIdleConns)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/ThreeDotsLabs/watermill-amqp/v2/pkg/amqp"
|
"github.com/ThreeDotsLabs/watermill-amqp/v2/pkg/amqp"
|
||||||
"github.com/ThreeDotsLabs/watermill/message"
|
"github.com/ThreeDotsLabs/watermill/message"
|
||||||
"github.com/ThreeDotsLabs/watermill/message/router/middleware"
|
"github.com/ThreeDotsLabs/watermill/message/router/middleware"
|
||||||
|
"github.com/ettle/strcase"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
@ -346,7 +347,7 @@ func runConsumer(c *cli.Context, name string, registerHandlers registerConsumerH
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, strcase.ToSnake(name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ var cmdDB = &cli.Command{
|
||||||
|
|
||||||
logger := loggerFromCtx(c.Context)
|
logger := loggerFromCtx(c.Context)
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ var cmdDB = &cli.Command{
|
||||||
|
|
||||||
logger := loggerFromCtx(c.Context)
|
logger := loggerFromCtx(c.Context)
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ var (
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "data_sync_job")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ var (
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "ennoblement_sync_job")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ var (
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "snapshot_creation_job")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ var (
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "cleanup_job")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ var cmdServe = &cli.Command{
|
||||||
logger := loggerFromCtx(c.Context)
|
logger := loggerFromCtx(c.Context)
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c, "api")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ var cmdServe = &cli.Command{
|
||||||
villageRepo := adapter.NewVillageBunRepository(bunDB)
|
villageRepo := adapter.NewVillageBunRepository(bunDB)
|
||||||
ennoblementRepo := adapter.NewEnnoblementBunRepository(bunDB)
|
ennoblementRepo := adapter.NewEnnoblementBunRepository(bunDB)
|
||||||
tribeChangeRepo := adapter.NewTribeChangeBunRepository(bunDB)
|
tribeChangeRepo := adapter.NewTribeChangeBunRepository(bunDB)
|
||||||
|
serverSnapshotRepo := adapter.NewServerSnapshotBunRepository(bunDB)
|
||||||
tribeSnapshotRepo := adapter.NewTribeSnapshotBunRepository(bunDB)
|
tribeSnapshotRepo := adapter.NewTribeSnapshotBunRepository(bunDB)
|
||||||
playerSnapshotRepo := adapter.NewPlayerSnapshotBunRepository(bunDB)
|
playerSnapshotRepo := adapter.NewPlayerSnapshotBunRepository(bunDB)
|
||||||
|
|
||||||
|
@ -124,6 +125,7 @@ var cmdServe = &cli.Command{
|
||||||
playerSvc := app.NewPlayerService(playerRepo, tribeChangeSvc, nil, nil)
|
playerSvc := app.NewPlayerService(playerRepo, tribeChangeSvc, nil, nil)
|
||||||
villageSvc := app.NewVillageService(villageRepo, nil, nil)
|
villageSvc := app.NewVillageService(villageRepo, nil, nil)
|
||||||
ennoblementSvc := app.NewEnnoblementService(ennoblementRepo, nil, nil)
|
ennoblementSvc := app.NewEnnoblementService(ennoblementRepo, nil, nil)
|
||||||
|
serverSnapshotSvc := app.NewServerSnapshotService(serverSnapshotRepo, serverSvc, nil)
|
||||||
tribeSnapshotSvc := app.NewTribeSnapshotService(tribeSnapshotRepo, tribeSvc, nil)
|
tribeSnapshotSvc := app.NewTribeSnapshotService(tribeSnapshotRepo, tribeSvc, nil)
|
||||||
playerSnapshotSvc := app.NewPlayerSnapshotService(playerSnapshotRepo, playerSvc, nil)
|
playerSnapshotSvc := app.NewPlayerSnapshotService(playerSnapshotRepo, playerSvc, nil)
|
||||||
|
|
||||||
|
@ -160,6 +162,7 @@ var cmdServe = &cli.Command{
|
||||||
villageSvc,
|
villageSvc,
|
||||||
ennoblementSvc,
|
ennoblementSvc,
|
||||||
tribeChangeSvc,
|
tribeChangeSvc,
|
||||||
|
serverSnapshotSvc,
|
||||||
tribeSnapshotSvc,
|
tribeSnapshotSvc,
|
||||||
playerSnapshotSvc,
|
playerSnapshotSvc,
|
||||||
port.WithOpenAPIConfig(oapiCfg),
|
port.WithOpenAPIConfig(oapiCfg),
|
||||||
|
|
9
go.mod
9
go.mod
|
@ -10,8 +10,8 @@ require (
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
github.com/elliotchance/phpserialize v1.4.0
|
github.com/elliotchance/phpserialize v1.4.0
|
||||||
github.com/ettle/strcase v0.2.0
|
github.com/ettle/strcase v0.2.0
|
||||||
github.com/getkin/kin-openapi v0.124.0
|
github.com/getkin/kin-openapi v0.125.0
|
||||||
github.com/go-chi/chi/v5 v5.0.12
|
github.com/go-chi/chi/v5 v5.0.14
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
@ -28,7 +28,9 @@ require (
|
||||||
github.com/uptrace/bun/extra/bundebug v1.2.1
|
github.com/uptrace/bun/extra/bundebug v1.2.1
|
||||||
github.com/urfave/cli/v2 v2.27.2
|
github.com/urfave/cli/v2 v2.27.2
|
||||||
go.uber.org/automaxprocs v1.5.3
|
go.uber.org/automaxprocs v1.5.3
|
||||||
|
golang.org/x/image v0.17.0
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.7.0
|
||||||
|
golang.org/x/tools v0.19.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,7 +45,7 @@ require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/cli v20.10.17+incompatible // indirect
|
github.com/docker/cli v20.10.17+incompatible // indirect
|
||||||
github.com/docker/docker v20.10.7+incompatible // indirect
|
github.com/docker/docker v20.10.11+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
@ -90,7 +92,6 @@ require (
|
||||||
golang.org/x/crypto v0.21.0 // indirect
|
golang.org/x/crypto v0.21.0 // indirect
|
||||||
golang.org/x/mod v0.16.0 // indirect
|
golang.org/x/mod v0.16.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/tools v0.19.0 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
mellium.im/sasl v0.3.1 // indirect
|
mellium.im/sasl v0.3.1 // indirect
|
||||||
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
|
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
|
||||||
|
|
14
go.sum
14
go.sum
|
@ -40,8 +40,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
|
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
|
||||||
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
|
github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo=
|
||||||
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
|
@ -55,10 +55,10 @@ github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp
|
||||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||||
github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M=
|
github.com/getkin/kin-openapi v0.125.0 h1:jyQCyf2qXS1qvs2U00xQzkGCqYPhEhZDmSmVt65fXno=
|
||||||
github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
|
github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
|
||||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0=
|
||||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||||
|
@ -233,6 +233,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/image v0.17.0 h1:nTRVVdajgB8zCMZVsViyzhnMKPwYeroEERRC64JuLco=
|
||||||
|
golang.org/x/image v0.17.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
|
|
|
@ -280,6 +280,9 @@ func (a listPlayersParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQue
|
||||||
case domain.PlayerSortPointsASC,
|
case domain.PlayerSortPointsASC,
|
||||||
domain.PlayerSortPointsDESC:
|
domain.PlayerSortPointsDESC:
|
||||||
el.value = cursor.Points()
|
el.value = cursor.Points()
|
||||||
|
case domain.PlayerSortMostPointsASC,
|
||||||
|
domain.PlayerSortMostPointsDESC:
|
||||||
|
el.value = cursor.MostPoints()
|
||||||
case domain.PlayerSortDeletedAtASC,
|
case domain.PlayerSortDeletedAtASC,
|
||||||
domain.PlayerSortDeletedAtDESC:
|
domain.PlayerSortDeletedAtDESC:
|
||||||
el.value = cursor.DeletedAt()
|
el.value = cursor.DeletedAt()
|
||||||
|
@ -326,6 +329,10 @@ func (a listPlayersParamsApplier) sortToColumnAndDirection(
|
||||||
return "player.points", sortDirectionASC, nil
|
return "player.points", sortDirectionASC, nil
|
||||||
case domain.PlayerSortPointsDESC:
|
case domain.PlayerSortPointsDESC:
|
||||||
return "player.points", sortDirectionDESC, nil
|
return "player.points", sortDirectionDESC, nil
|
||||||
|
case domain.PlayerSortMostPointsASC:
|
||||||
|
return "player.most_points", sortDirectionASC, nil
|
||||||
|
case domain.PlayerSortMostPointsDESC:
|
||||||
|
return "player.most_points", sortDirectionDESC, nil
|
||||||
case domain.PlayerSortDeletedAtASC:
|
case domain.PlayerSortDeletedAtASC:
|
||||||
return "COALESCE(player.deleted_at, '0001-01-01 00:00:00+00:00')", sortDirectionASC, nil
|
return "COALESCE(player.deleted_at, '0001-01-01 00:00:00+00:00')", sortDirectionASC, nil
|
||||||
case domain.PlayerSortDeletedAtDESC:
|
case domain.PlayerSortDeletedAtDESC:
|
||||||
|
|
|
@ -81,6 +81,33 @@ func (repo *ServerSnapshotBunRepository) List(
|
||||||
return domain.NewListServerSnapshotsResult(separateListResultAndNext(converted, params.Limit()))
|
return domain.NewListServerSnapshotsResult(separateListResultAndNext(converted, params.Limit()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *ServerSnapshotBunRepository) ListWithRelations(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListServerSnapshotsParams,
|
||||||
|
) (domain.ListServerSnapshotsWithRelationsResult, error) {
|
||||||
|
var serverSnapshots bunmodel.ServerSnapshots
|
||||||
|
|
||||||
|
if err := repo.db.NewSelect().
|
||||||
|
Model(&serverSnapshots).
|
||||||
|
Apply(listServerSnapshotsParamsApplier{params: params}.apply).
|
||||||
|
Relation("Server", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||||
|
return q.Column(bunmodel.ServerMetaColumns...)
|
||||||
|
}).
|
||||||
|
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return domain.ListServerSnapshotsWithRelationsResult{}, fmt.Errorf(
|
||||||
|
"couldn't select server snapshots from the db: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
converted, err := serverSnapshots.ToDomainWithRelations()
|
||||||
|
if err != nil {
|
||||||
|
return domain.ListServerSnapshotsWithRelationsResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.NewListServerSnapshotsWithRelationsResult(separateListResultAndNext(converted, params.Limit()))
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *ServerSnapshotBunRepository) Delete(ctx context.Context, serverKey string, dateLTE time.Time) error {
|
func (repo *ServerSnapshotBunRepository) Delete(ctx context.Context, serverKey string, dateLTE time.Time) error {
|
||||||
if _, err := repo.db.NewDelete().
|
if _, err := repo.db.NewDelete().
|
||||||
Model((*bunmodel.ServerSnapshot)(nil)).
|
Model((*bunmodel.ServerSnapshot)(nil)).
|
||||||
|
|
|
@ -241,6 +241,9 @@ func (a listTribesParamsApplier) applyCursor(q *bun.SelectQuery) *bun.SelectQuer
|
||||||
case domain.TribeSortPointsASC,
|
case domain.TribeSortPointsASC,
|
||||||
domain.TribeSortPointsDESC:
|
domain.TribeSortPointsDESC:
|
||||||
el.value = cursor.Points()
|
el.value = cursor.Points()
|
||||||
|
case domain.TribeSortMostPointsASC,
|
||||||
|
domain.TribeSortMostPointsDESC:
|
||||||
|
el.value = cursor.MostPoints()
|
||||||
case domain.TribeSortDominanceASC,
|
case domain.TribeSortDominanceASC,
|
||||||
domain.TribeSortDominanceDESC:
|
domain.TribeSortDominanceDESC:
|
||||||
el.value = cursor.Dominance()
|
el.value = cursor.Dominance()
|
||||||
|
@ -286,6 +289,10 @@ func (a listTribesParamsApplier) sortToColumnAndDirection(
|
||||||
return "tribe.points", sortDirectionASC, nil
|
return "tribe.points", sortDirectionASC, nil
|
||||||
case domain.TribeSortPointsDESC:
|
case domain.TribeSortPointsDESC:
|
||||||
return "tribe.points", sortDirectionDESC, nil
|
return "tribe.points", sortDirectionDESC, nil
|
||||||
|
case domain.TribeSortMostPointsASC:
|
||||||
|
return "tribe.most_points", sortDirectionASC, nil
|
||||||
|
case domain.TribeSortMostPointsDESC:
|
||||||
|
return "tribe.most_points", sortDirectionDESC, nil
|
||||||
case domain.TribeSortDominanceASC:
|
case domain.TribeSortDominanceASC:
|
||||||
return "tribe.dominance", sortDirectionASC, nil
|
return "tribe.dominance", sortDirectionASC, nil
|
||||||
case domain.TribeSortDominanceDESC:
|
case domain.TribeSortDominanceDESC:
|
||||||
|
|
|
@ -276,6 +276,56 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints ASC, serverKey ASC, id ASC]",
|
||||||
|
params: func(t *testing.T) domain.ListPlayersParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListPlayersParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.PlayerSort{
|
||||||
|
domain.PlayerSortMostPointsASC,
|
||||||
|
domain.PlayerSortServerKeyASC,
|
||||||
|
domain.PlayerSortIDASC,
|
||||||
|
}))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, _ domain.ListPlayersParams, res domain.ListPlayersResult) {
|
||||||
|
t.Helper()
|
||||||
|
players := res.Players()
|
||||||
|
assert.NotEmpty(t, players)
|
||||||
|
assert.True(t, slices.IsSortedFunc(players, func(a, b domain.Player) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints(), b.MostPoints()),
|
||||||
|
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||||
|
cmp.Compare(a.ID(), b.ID()),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints DESC, serverKey ASC, id ASC]",
|
||||||
|
params: func(t *testing.T) domain.ListPlayersParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListPlayersParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.PlayerSort{
|
||||||
|
domain.PlayerSortMostPointsDESC,
|
||||||
|
domain.PlayerSortServerKeyASC,
|
||||||
|
domain.PlayerSortIDASC,
|
||||||
|
}))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, _ domain.ListPlayersParams, res domain.ListPlayersResult) {
|
||||||
|
t.Helper()
|
||||||
|
players := res.Players()
|
||||||
|
assert.NotEmpty(t, players)
|
||||||
|
assert.True(t, slices.IsSortedFunc(players, func(a, b domain.Player) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints(), b.MostPoints())*-1,
|
||||||
|
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||||
|
cmp.Compare(a.ID(), b.ID()),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: sort=[deletedAt ASC, serverKey ASC, id ASC]",
|
name: "OK: sort=[deletedAt ASC, serverKey ASC, id ASC]",
|
||||||
params: func(t *testing.T) domain.ListPlayersParams {
|
params: func(t *testing.T) domain.ListPlayersParams {
|
||||||
|
|
|
@ -115,7 +115,7 @@ func testServerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repo
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("List", func(t *testing.T) {
|
t.Run("List & ListWithRelations", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
repos := newRepos(t)
|
repos := newRepos(t)
|
||||||
|
@ -405,6 +405,14 @@ func testServerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repo
|
||||||
res, err := repos.serverSnapshot.List(ctx, params)
|
res, err := repos.serverSnapshot.List(ctx, params)
|
||||||
assertError(t, err)
|
assertError(t, err)
|
||||||
tt.assertResult(t, params, res)
|
tt.assertResult(t, params, res)
|
||||||
|
|
||||||
|
resWithRelations, err := repos.serverSnapshot.ListWithRelations(ctx, params)
|
||||||
|
assertError(t, err)
|
||||||
|
require.Len(t, resWithRelations.ServerSnapshots(), len(res.ServerSnapshots()))
|
||||||
|
for i, ss := range resWithRelations.ServerSnapshots() {
|
||||||
|
assert.Equal(t, res.ServerSnapshots()[i], ss.ServerSnapshot())
|
||||||
|
assert.Equal(t, ss.ServerSnapshot().ServerKey(), ss.Server().Key())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -70,6 +70,10 @@ type tribeChangeRepository interface {
|
||||||
type serverSnapshotRepository interface {
|
type serverSnapshotRepository interface {
|
||||||
Create(ctx context.Context, params ...domain.CreateServerSnapshotParams) error
|
Create(ctx context.Context, params ...domain.CreateServerSnapshotParams) error
|
||||||
List(ctx context.Context, params domain.ListServerSnapshotsParams) (domain.ListServerSnapshotsResult, error)
|
List(ctx context.Context, params domain.ListServerSnapshotsParams) (domain.ListServerSnapshotsResult, error)
|
||||||
|
ListWithRelations(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListServerSnapshotsParams,
|
||||||
|
) (domain.ListServerSnapshotsWithRelationsResult, error)
|
||||||
Delete(ctx context.Context, serverKey string, dateLTE time.Time) error
|
Delete(ctx context.Context, serverKey string, dateLTE time.Time) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -339,6 +339,56 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints ASC, serverKey ASC, id ASC]",
|
||||||
|
params: func(t *testing.T) domain.ListTribesParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListTribesParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.TribeSort{
|
||||||
|
domain.TribeSortMostPointsASC,
|
||||||
|
domain.TribeSortServerKeyASC,
|
||||||
|
domain.TribeSortIDASC,
|
||||||
|
}))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||||
|
t.Helper()
|
||||||
|
tribes := res.Tribes()
|
||||||
|
assert.NotEmpty(t, tribes)
|
||||||
|
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints(), b.MostPoints()),
|
||||||
|
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||||
|
cmp.Compare(a.ID(), b.ID()),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints DESC, serverKey ASC, id ASC]",
|
||||||
|
params: func(t *testing.T) domain.ListTribesParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListTribesParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.TribeSort{
|
||||||
|
domain.TribeSortMostPointsDESC,
|
||||||
|
domain.TribeSortServerKeyASC,
|
||||||
|
domain.TribeSortIDASC,
|
||||||
|
}))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, _ domain.ListTribesParams, res domain.ListTribesResult) {
|
||||||
|
t.Helper()
|
||||||
|
tribes := res.Tribes()
|
||||||
|
assert.NotEmpty(t, tribes)
|
||||||
|
assert.True(t, slices.IsSortedFunc(tribes, func(a, b domain.Tribe) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints(), b.MostPoints())*-1,
|
||||||
|
cmp.Compare(a.ServerKey(), b.ServerKey()),
|
||||||
|
cmp.Compare(a.ID(), b.ID()),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: sort=[deletedAt ASC, serverKey ASC, id ASC]",
|
name: "OK: sort=[deletedAt ASC, serverKey ASC, id ASC]",
|
||||||
params: func(t *testing.T) domain.ListTribesParams {
|
params: func(t *testing.T) domain.ListTribesParams {
|
||||||
|
|
1408
internal/adapter/testdata/fixture.yml
vendored
1408
internal/adapter/testdata/fixture.yml
vendored
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,10 @@ type ServerSnapshotRepository interface {
|
||||||
// Create persists tribe snapshots in a store (e.g. Postgres).
|
// Create persists tribe snapshots in a store (e.g. Postgres).
|
||||||
// Duplicates are ignored.
|
// Duplicates are ignored.
|
||||||
Create(ctx context.Context, params ...domain.CreateServerSnapshotParams) error
|
Create(ctx context.Context, params ...domain.CreateServerSnapshotParams) error
|
||||||
|
ListWithRelations(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListServerSnapshotsParams,
|
||||||
|
) (domain.ListServerSnapshotsWithRelationsResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerSnapshotService struct {
|
type ServerSnapshotService struct {
|
||||||
|
@ -27,7 +31,6 @@ func NewServerSnapshotService(
|
||||||
return &ServerSnapshotService{repo: repo, serverSvc: serverSvc, pub: pub}
|
return &ServerSnapshotService{repo: repo, serverSvc: serverSvc, pub: pub}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo
|
|
||||||
func (svc *ServerSnapshotService) Create(
|
func (svc *ServerSnapshotService) Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
createSnapshotsCmdPayload domain.CreateSnapshotsCmdPayload,
|
createSnapshotsCmdPayload domain.CreateSnapshotsCmdPayload,
|
||||||
|
@ -60,3 +63,10 @@ func (svc *ServerSnapshotService) Create(
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *ServerSnapshotService) ListWithRelations(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListServerSnapshotsParams,
|
||||||
|
) (domain.ListServerSnapshotsWithRelationsResult, error) {
|
||||||
|
return svc.repo.ListWithRelations(ctx, params)
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ type ServerSnapshot struct {
|
||||||
|
|
||||||
ID int `bun:"id,pk,autoincrement,identity"`
|
ID int `bun:"id,pk,autoincrement,identity"`
|
||||||
ServerKey string `bun:"server_key,nullzero"`
|
ServerKey string `bun:"server_key,nullzero"`
|
||||||
|
Server Server `bun:"server,rel:belongs-to,join:server_key=key"`
|
||||||
NumPlayers int `bun:"num_players"`
|
NumPlayers int `bun:"num_players"`
|
||||||
NumActivePlayers int `bun:"num_active_players"`
|
NumActivePlayers int `bun:"num_active_players"`
|
||||||
NumInactivePlayers int `bun:"num_inactive_players"`
|
NumInactivePlayers int `bun:"num_inactive_players"`
|
||||||
|
@ -55,8 +56,26 @@ func (ss ServerSnapshot) ToDomain() (domain.ServerSnapshot, error) {
|
||||||
return converted, nil
|
return converted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss ServerSnapshot) ToDomainWithRelations() (domain.ServerSnapshotWithRelations, error) {
|
||||||
|
converted, err := ss.ToDomain()
|
||||||
|
if err != nil {
|
||||||
|
return domain.ServerSnapshotWithRelations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := ss.Server.ToMeta()
|
||||||
|
if err != nil {
|
||||||
|
return domain.ServerSnapshotWithRelations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted.WithRelations(server), nil
|
||||||
|
}
|
||||||
|
|
||||||
type ServerSnapshots []ServerSnapshot
|
type ServerSnapshots []ServerSnapshot
|
||||||
|
|
||||||
func (sss ServerSnapshots) ToDomain() (domain.ServerSnapshots, error) {
|
func (sss ServerSnapshots) ToDomain() (domain.ServerSnapshots, error) {
|
||||||
return sliceToDomain(sss)
|
return sliceToDomain(sss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sss ServerSnapshots) ToDomainWithRelations() (domain.ServerSnapshotsWithRelations, error) {
|
||||||
|
return sliceToDomainWithRelations(sss)
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func NewBaseEnnoblement(
|
||||||
points int,
|
points int,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (BaseEnnoblement, error) {
|
) (BaseEnnoblement, error) {
|
||||||
if err := validateIntInRange(villageID, 1, math.MaxInt); err != nil {
|
if err := validateInRange(villageID, 1, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "villageID",
|
Field: "villageID",
|
||||||
|
@ -34,7 +34,7 @@ func NewBaseEnnoblement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(newOwnerID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(newOwnerID, 0, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "newOwnerID",
|
Field: "newOwnerID",
|
||||||
|
@ -42,7 +42,7 @@ func NewBaseEnnoblement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(newTribeID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(newTribeID, 0, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "newTribeID",
|
Field: "newTribeID",
|
||||||
|
@ -50,7 +50,7 @@ func NewBaseEnnoblement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(oldOwnerID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(oldOwnerID, 0, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "oldOwnerID",
|
Field: "oldOwnerID",
|
||||||
|
@ -58,7 +58,7 @@ func NewBaseEnnoblement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(oldTribeID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(oldTribeID, 0, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "oldTribeID",
|
Field: "oldTribeID",
|
||||||
|
@ -66,7 +66,7 @@ func NewBaseEnnoblement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return BaseEnnoblement{}, ValidationError{
|
return BaseEnnoblement{}, ValidationError{
|
||||||
Model: baseEnnoblementModelName,
|
Model: baseEnnoblementModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
|
|
@ -56,7 +56,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "villageID",
|
Field: "villageID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -76,7 +76,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "newOwnerID",
|
Field: "newOwnerID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -96,7 +96,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "newTribeID",
|
Field: "newTribeID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -116,7 +116,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "oldOwnerID",
|
Field: "oldOwnerID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -136,7 +136,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "oldTribeID",
|
Field: "oldTribeID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -156,7 +156,7 @@ func TestNewBaseEnnoblement(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseEnnoblement",
|
Model: "BaseEnnoblement",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,7 @@ func NewBasePlayer(
|
||||||
od OpponentsDefeated,
|
od OpponentsDefeated,
|
||||||
profileURL *url.URL,
|
profileURL *url.URL,
|
||||||
) (BasePlayer, error) {
|
) (BasePlayer, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return BasePlayer{}, ValidationError{
|
return BasePlayer{}, ValidationError{
|
||||||
Model: basePlayerModelName,
|
Model: basePlayerModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -44,7 +44,7 @@ func NewBasePlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numVillages, 0, math.MaxInt); err != nil {
|
||||||
return BasePlayer{}, ValidationError{
|
return BasePlayer{}, ValidationError{
|
||||||
Model: basePlayerModelName,
|
Model: basePlayerModelName,
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
|
@ -52,7 +52,7 @@ func NewBasePlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return BasePlayer{}, ValidationError{
|
return BasePlayer{}, ValidationError{
|
||||||
Model: basePlayerModelName,
|
Model: basePlayerModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
@ -60,7 +60,7 @@ func NewBasePlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(rank, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rank, 0, math.MaxInt); err != nil {
|
||||||
return BasePlayer{}, ValidationError{
|
return BasePlayer{}, ValidationError{
|
||||||
Model: basePlayerModelName,
|
Model: basePlayerModelName,
|
||||||
Field: "rank",
|
Field: "rank",
|
||||||
|
@ -68,7 +68,7 @@ func NewBasePlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(tribeID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(tribeID, 0, math.MaxInt); err != nil {
|
||||||
return BasePlayer{}, ValidationError{
|
return BasePlayer{}, ValidationError{
|
||||||
Model: basePlayerModelName,
|
Model: basePlayerModelName,
|
||||||
Field: "tribeID",
|
Field: "tribeID",
|
||||||
|
|
|
@ -60,7 +60,7 @@ func TestNewBasePlayer(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BasePlayer",
|
Model: "BasePlayer",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -125,7 +125,7 @@ func TestNewBasePlayer(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BasePlayer",
|
Model: "BasePlayer",
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -146,7 +146,7 @@ func TestNewBasePlayer(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BasePlayer",
|
Model: "BasePlayer",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -167,7 +167,7 @@ func TestNewBasePlayer(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BasePlayer",
|
Model: "BasePlayer",
|
||||||
Field: "rank",
|
Field: "rank",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -188,7 +188,7 @@ func TestNewBasePlayer(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BasePlayer",
|
Model: "BasePlayer",
|
||||||
Field: "tribeID",
|
Field: "tribeID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,7 +33,7 @@ func NewBaseTribe(
|
||||||
od OpponentsDefeated,
|
od OpponentsDefeated,
|
||||||
profileURL *url.URL,
|
profileURL *url.URL,
|
||||||
) (BaseTribe, error) {
|
) (BaseTribe, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -60,7 +60,7 @@ func NewBaseTribe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numMembers, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numMembers, 0, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "numMembers",
|
Field: "numMembers",
|
||||||
|
@ -68,7 +68,7 @@ func NewBaseTribe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numVillages, 0, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
|
@ -76,7 +76,7 @@ func NewBaseTribe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
@ -84,7 +84,7 @@ func NewBaseTribe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(allPoints, 0, math.MaxInt); err != nil {
|
if err := validateInRange(allPoints, 0, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "allPoints",
|
Field: "allPoints",
|
||||||
|
@ -92,7 +92,7 @@ func NewBaseTribe(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(rank, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rank, 0, math.MaxInt); err != nil {
|
||||||
return BaseTribe{}, ValidationError{
|
return BaseTribe{}, ValidationError{
|
||||||
Model: baseTribeModelName,
|
Model: baseTribeModelName,
|
||||||
Field: "rank",
|
Field: "rank",
|
||||||
|
|
|
@ -81,7 +81,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -200,7 +200,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "numMembers",
|
Field: "numMembers",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -223,7 +223,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -246,7 +246,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -269,7 +269,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "allPoints",
|
Field: "allPoints",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -292,7 +292,7 @@ func TestNewBaseTribe(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseTribe",
|
Model: "BaseTribe",
|
||||||
Field: "rank",
|
Field: "rank",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@ func NewBaseVillage(
|
||||||
playerID int,
|
playerID int,
|
||||||
profileURL *url.URL,
|
profileURL *url.URL,
|
||||||
) (BaseVillage, error) {
|
) (BaseVillage, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -45,7 +45,7 @@ func NewBaseVillage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
@ -53,7 +53,7 @@ func NewBaseVillage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(x, 0, math.MaxInt); err != nil {
|
if err := validateInRange(x, 0, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "x",
|
Field: "x",
|
||||||
|
@ -61,7 +61,7 @@ func NewBaseVillage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(y, 0, math.MaxInt); err != nil {
|
if err := validateInRange(y, 0, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "y",
|
Field: "y",
|
||||||
|
@ -77,7 +77,7 @@ func NewBaseVillage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(bonus, 0, math.MaxInt); err != nil {
|
if err := validateInRange(bonus, 0, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "bonus",
|
Field: "bonus",
|
||||||
|
@ -85,7 +85,7 @@ func NewBaseVillage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(playerID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(playerID, 0, math.MaxInt); err != nil {
|
||||||
return BaseVillage{}, ValidationError{
|
return BaseVillage{}, ValidationError{
|
||||||
Model: baseVillageModelName,
|
Model: baseVillageModelName,
|
||||||
Field: "playerID",
|
Field: "playerID",
|
||||||
|
|
|
@ -63,7 +63,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -131,7 +131,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -153,7 +153,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "x",
|
Field: "x",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -175,7 +175,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "y",
|
Field: "y",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -243,7 +243,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "bonus",
|
Field: "bonus",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -265,7 +265,7 @@ func TestNewBaseVillage(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "BaseVillage",
|
Model: "BaseVillage",
|
||||||
Field: "playerID",
|
Field: "playerID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,7 @@ type PlayerCursorConfig struct {
|
||||||
ODScoreSup int
|
ODScoreSup int
|
||||||
ODScoreTotal int
|
ODScoreTotal int
|
||||||
Points int
|
Points int
|
||||||
|
MostPoints int
|
||||||
DeletedAt time.Time
|
DeletedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ func NewPlayerCursor(tb TestingTB, opts ...func(cfg *PlayerCursorConfig)) domain
|
||||||
ODScoreSup: gofakeit.IntRange(0, math.MaxInt),
|
ODScoreSup: gofakeit.IntRange(0, math.MaxInt),
|
||||||
ODScoreTotal: gofakeit.IntRange(0, math.MaxInt),
|
ODScoreTotal: gofakeit.IntRange(0, math.MaxInt),
|
||||||
Points: gofakeit.IntRange(0, math.MaxInt),
|
Points: gofakeit.IntRange(0, math.MaxInt),
|
||||||
|
MostPoints: gofakeit.IntRange(0, math.MaxInt),
|
||||||
DeletedAt: time.Time{},
|
DeletedAt: time.Time{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ func NewPlayerCursor(tb TestingTB, opts ...func(cfg *PlayerCursorConfig)) domain
|
||||||
cfg.ODScoreSup,
|
cfg.ODScoreSup,
|
||||||
cfg.ODScoreTotal,
|
cfg.ODScoreTotal,
|
||||||
cfg.Points,
|
cfg.Points,
|
||||||
|
cfg.MostPoints,
|
||||||
cfg.DeletedAt,
|
cfg.DeletedAt,
|
||||||
)
|
)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
|
@ -83,16 +83,16 @@ func NewServer(tb TestingTB, opts ...func(cfg *ServerConfig)) domain.Server {
|
||||||
cfg.URL.String(),
|
cfg.URL.String(),
|
||||||
cfg.Open,
|
cfg.Open,
|
||||||
cfg.Special,
|
cfg.Special,
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
0,
|
gofakeit.IntRange(0, 100000),
|
||||||
NewServerConfig(tb),
|
NewServerConfig(tb),
|
||||||
NewBuildingInfo(tb),
|
NewBuildingInfo(tb),
|
||||||
NewUnitInfo(tb),
|
NewUnitInfo(tb),
|
||||||
|
|
|
@ -20,7 +20,9 @@ func NewServerConfig(tb TestingTB) domain.ServerConfig {
|
||||||
domain.ServerConfigBuildings{},
|
domain.ServerConfigBuildings{},
|
||||||
domain.ServerConfigSnob{},
|
domain.ServerConfigSnob{},
|
||||||
domain.ServerConfigAlly{Limit: gofakeit.IntRange(1, 20)},
|
domain.ServerConfigAlly{Limit: gofakeit.IntRange(1, 20)},
|
||||||
domain.ServerConfigCoord{},
|
domain.ServerConfigCoord{
|
||||||
|
MapSize: gofakeit.IntRange(1000, 1000),
|
||||||
|
},
|
||||||
domain.ServerConfigSitter{},
|
domain.ServerConfigSitter{},
|
||||||
domain.ServerConfigSleep{},
|
domain.ServerConfigSleep{},
|
||||||
domain.ServerConfigNight{},
|
domain.ServerConfigNight{},
|
||||||
|
|
|
@ -100,3 +100,38 @@ func NewServerSnapshot(tb TestingTB, opts ...func(cfg *ServerSnapshotConfig)) do
|
||||||
|
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServerSnapshotWithRelationsConfig struct {
|
||||||
|
ServerSnapshotOptions []func(cfg *ServerSnapshotConfig)
|
||||||
|
ServerOptions []func(cfg *ServerConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerSnapshotWithRelations(
|
||||||
|
tb TestingTB,
|
||||||
|
opts ...func(cfg *ServerSnapshotWithRelationsConfig),
|
||||||
|
) domain.ServerSnapshotWithRelations {
|
||||||
|
tb.Helper()
|
||||||
|
|
||||||
|
cfg := &ServerSnapshotWithRelationsConfig{}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
ss := NewServerSnapshot(tb, cfg.ServerSnapshotOptions...)
|
||||||
|
|
||||||
|
if ss.ServerKey() != "" {
|
||||||
|
cfg.ServerOptions = append([]func(cfg *ServerConfig){
|
||||||
|
func(cfg *ServerConfig) {
|
||||||
|
cfg.Key = ss.ServerKey()
|
||||||
|
},
|
||||||
|
}, cfg.ServerOptions...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tribe domain.ServerMeta
|
||||||
|
if len(cfg.ServerOptions) > 0 {
|
||||||
|
tribe = NewServer(tb, cfg.ServerOptions...).Meta()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.WithRelations(tribe)
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ type TribeCursorConfig struct {
|
||||||
ODScoreDef int
|
ODScoreDef int
|
||||||
ODScoreTotal int
|
ODScoreTotal int
|
||||||
Points int
|
Points int
|
||||||
|
MostPoints int
|
||||||
Dominance float64
|
Dominance float64
|
||||||
DeletedAt time.Time
|
DeletedAt time.Time
|
||||||
}
|
}
|
||||||
|
@ -34,6 +35,7 @@ func NewTribeCursor(tb TestingTB, opts ...func(cfg *TribeCursorConfig)) domain.T
|
||||||
ODScoreDef: gofakeit.IntRange(0, math.MaxInt),
|
ODScoreDef: gofakeit.IntRange(0, math.MaxInt),
|
||||||
ODScoreTotal: gofakeit.IntRange(0, math.MaxInt),
|
ODScoreTotal: gofakeit.IntRange(0, math.MaxInt),
|
||||||
Points: gofakeit.IntRange(0, math.MaxInt),
|
Points: gofakeit.IntRange(0, math.MaxInt),
|
||||||
|
MostPoints: gofakeit.IntRange(0, math.MaxInt),
|
||||||
Dominance: gofakeit.Float64Range(0.1, 99.9),
|
Dominance: gofakeit.Float64Range(0.1, 99.9),
|
||||||
DeletedAt: time.Time{},
|
DeletedAt: time.Time{},
|
||||||
}
|
}
|
||||||
|
@ -49,6 +51,7 @@ func NewTribeCursor(tb TestingTB, opts ...func(cfg *TribeCursorConfig)) domain.T
|
||||||
cfg.ODScoreDef,
|
cfg.ODScoreDef,
|
||||||
cfg.ODScoreTotal,
|
cfg.ODScoreTotal,
|
||||||
cfg.Points,
|
cfg.Points,
|
||||||
|
cfg.MostPoints,
|
||||||
cfg.Dominance,
|
cfg.Dominance,
|
||||||
cfg.DeletedAt,
|
cfg.DeletedAt,
|
||||||
)
|
)
|
||||||
|
|
|
@ -37,6 +37,8 @@ func NewVillageCursor(tb TestingTB, opts ...func(cfg *VillageCursorConfig)) doma
|
||||||
type VillageConfig struct {
|
type VillageConfig struct {
|
||||||
ID int
|
ID int
|
||||||
ServerKey string
|
ServerKey string
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
PlayerID int
|
PlayerID int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +48,8 @@ func NewVillage(tb TestingTB, opts ...func(cfg *VillageConfig)) domain.Village {
|
||||||
cfg := &VillageConfig{
|
cfg := &VillageConfig{
|
||||||
ID: RandID(),
|
ID: RandID(),
|
||||||
ServerKey: RandServerKey(),
|
ServerKey: RandServerKey(),
|
||||||
|
X: gofakeit.IntRange(1, 999),
|
||||||
|
Y: gofakeit.IntRange(1, 999),
|
||||||
PlayerID: gofakeit.IntRange(0, 10000),
|
PlayerID: gofakeit.IntRange(0, 10000),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +62,8 @@ func NewVillage(tb TestingTB, opts ...func(cfg *VillageConfig)) domain.Village {
|
||||||
cfg.ServerKey,
|
cfg.ServerKey,
|
||||||
gofakeit.LetterN(50),
|
gofakeit.LetterN(50),
|
||||||
gofakeit.IntRange(1, 10000),
|
gofakeit.IntRange(1, 10000),
|
||||||
gofakeit.IntRange(1, 999),
|
cfg.X,
|
||||||
gofakeit.IntRange(1, 999),
|
cfg.Y,
|
||||||
gofakeit.LetterN(3),
|
gofakeit.LetterN(3),
|
||||||
0,
|
0,
|
||||||
cfg.PlayerID,
|
cfg.PlayerID,
|
||||||
|
|
|
@ -37,7 +37,7 @@ func UnmarshalEnnoblementFromDatabase(
|
||||||
points int,
|
points int,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (Ennoblement, error) {
|
) (Ennoblement, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return Ennoblement{}, ValidationError{
|
return Ennoblement{}, ValidationError{
|
||||||
Model: ennoblementModelName,
|
Model: ennoblementModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -265,7 +265,7 @@ type EnnoblementCursor struct {
|
||||||
const ennoblementCursorModelName = "EnnoblementCursor"
|
const ennoblementCursorModelName = "EnnoblementCursor"
|
||||||
|
|
||||||
func NewEnnoblementCursor(id int, serverKey string, createdAt time.Time) (EnnoblementCursor, error) {
|
func NewEnnoblementCursor(id int, serverKey string, createdAt time.Time) (EnnoblementCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return EnnoblementCursor{}, ValidationError{
|
return EnnoblementCursor{}, ValidationError{
|
||||||
Model: ennoblementCursorModelName,
|
Model: ennoblementCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -405,7 +405,7 @@ func (params *ListEnnoblementsParams) VillageIDs() []int {
|
||||||
|
|
||||||
func (params *ListEnnoblementsParams) SetVillageIDs(villageIDs []int) error {
|
func (params *ListEnnoblementsParams) SetVillageIDs(villageIDs []int) error {
|
||||||
for i, id := range villageIDs {
|
for i, id := range villageIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listEnnoblementsParamsModelName,
|
Model: listEnnoblementsParamsModelName,
|
||||||
Field: "villageIDs",
|
Field: "villageIDs",
|
||||||
|
@ -426,7 +426,7 @@ func (params *ListEnnoblementsParams) PlayerIDs() []int {
|
||||||
|
|
||||||
func (params *ListEnnoblementsParams) SetPlayerIDs(playerIDs []int) error {
|
func (params *ListEnnoblementsParams) SetPlayerIDs(playerIDs []int) error {
|
||||||
for i, id := range playerIDs {
|
for i, id := range playerIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listEnnoblementsParamsModelName,
|
Model: listEnnoblementsParamsModelName,
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
|
@ -447,7 +447,7 @@ func (params *ListEnnoblementsParams) TribeIDs() []int {
|
||||||
|
|
||||||
func (params *ListEnnoblementsParams) SetTribeIDs(tribeIDs []int) error {
|
func (params *ListEnnoblementsParams) SetTribeIDs(tribeIDs []int) error {
|
||||||
for i, id := range tribeIDs {
|
for i, id := range tribeIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listEnnoblementsParamsModelName,
|
Model: listEnnoblementsParamsModelName,
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
|
@ -579,7 +579,7 @@ func (params *ListEnnoblementsParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListEnnoblementsParams) SetLimit(limit int) error {
|
func (params *ListEnnoblementsParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, EnnoblementListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, EnnoblementListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listEnnoblementsParamsModelName,
|
Model: listEnnoblementsParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -141,7 +141,7 @@ func TestNewEnnoblementCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "EnnoblementCursor",
|
Model: "EnnoblementCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -276,7 +276,7 @@ func TestListEnnoblementsParams_SetVillageIDs(t *testing.T) {
|
||||||
Model: "ListEnnoblementsParams",
|
Model: "ListEnnoblementsParams",
|
||||||
Field: "villageIDs",
|
Field: "villageIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -336,7 +336,7 @@ func TestListEnnoblementsParams_SetPlayerIDs(t *testing.T) {
|
||||||
Model: "ListEnnoblementsParams",
|
Model: "ListEnnoblementsParams",
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -396,7 +396,7 @@ func TestListEnnoblementsParams_SetTribeIDs(t *testing.T) {
|
||||||
Model: "ListEnnoblementsParams",
|
Model: "ListEnnoblementsParams",
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -957,7 +957,7 @@ func TestListEnnoblementsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListEnnoblementsParams",
|
Model: "ListEnnoblementsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -971,7 +971,7 @@ func TestListEnnoblementsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListEnnoblementsParams",
|
Model: "ListEnnoblementsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.EnnoblementListMaxLimit,
|
Max: domain.EnnoblementListMaxLimit,
|
||||||
Current: domain.EnnoblementListMaxLimit + 1,
|
Current: domain.EnnoblementListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,7 +149,7 @@ func NewTribesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numTribes, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numTribes, 0, math.MaxInt); err != nil {
|
||||||
return TribesSyncedEventPayload{}, ValidationError{
|
return TribesSyncedEventPayload{}, ValidationError{
|
||||||
Model: tribesSyncedEventPayloadModelName,
|
Model: tribesSyncedEventPayloadModelName,
|
||||||
Field: "numTribes",
|
Field: "numTribes",
|
||||||
|
@ -157,7 +157,7 @@ func NewTribesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numActiveTribes, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numActiveTribes, 0, math.MaxInt); err != nil {
|
||||||
return TribesSyncedEventPayload{}, ValidationError{
|
return TribesSyncedEventPayload{}, ValidationError{
|
||||||
Model: tribesSyncedEventPayloadModelName,
|
Model: tribesSyncedEventPayloadModelName,
|
||||||
Field: "numActiveTribes",
|
Field: "numActiveTribes",
|
||||||
|
@ -239,7 +239,7 @@ func NewPlayersSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numPlayers, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numPlayers, 0, math.MaxInt); err != nil {
|
||||||
return PlayersSyncedEventPayload{}, ValidationError{
|
return PlayersSyncedEventPayload{}, ValidationError{
|
||||||
Model: playersSyncedEventPayloadModelName,
|
Model: playersSyncedEventPayloadModelName,
|
||||||
Field: "numPlayers",
|
Field: "numPlayers",
|
||||||
|
@ -247,7 +247,7 @@ func NewPlayersSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numActivePlayers, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numActivePlayers, 0, math.MaxInt); err != nil {
|
||||||
return PlayersSyncedEventPayload{}, ValidationError{
|
return PlayersSyncedEventPayload{}, ValidationError{
|
||||||
Model: playersSyncedEventPayloadModelName,
|
Model: playersSyncedEventPayloadModelName,
|
||||||
Field: "numActivePlayers",
|
Field: "numActivePlayers",
|
||||||
|
@ -333,7 +333,7 @@ func NewVillagesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numVillages, 0, math.MaxInt); err != nil {
|
||||||
return VillagesSyncedEventPayload{}, ValidationError{
|
return VillagesSyncedEventPayload{}, ValidationError{
|
||||||
Model: villagesSyncedEventPayloadModelName,
|
Model: villagesSyncedEventPayloadModelName,
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
|
@ -341,7 +341,7 @@ func NewVillagesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numPlayerVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numPlayerVillages, 0, math.MaxInt); err != nil {
|
||||||
return VillagesSyncedEventPayload{}, ValidationError{
|
return VillagesSyncedEventPayload{}, ValidationError{
|
||||||
Model: villagesSyncedEventPayloadModelName,
|
Model: villagesSyncedEventPayloadModelName,
|
||||||
Field: "numPlayerVillages",
|
Field: "numPlayerVillages",
|
||||||
|
@ -349,7 +349,7 @@ func NewVillagesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numBarbarianVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numBarbarianVillages, 0, math.MaxInt); err != nil {
|
||||||
return VillagesSyncedEventPayload{}, ValidationError{
|
return VillagesSyncedEventPayload{}, ValidationError{
|
||||||
Model: villagesSyncedEventPayloadModelName,
|
Model: villagesSyncedEventPayloadModelName,
|
||||||
Field: "numBarbarianVillages",
|
Field: "numBarbarianVillages",
|
||||||
|
@ -357,7 +357,7 @@ func NewVillagesSyncedEventPayload(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(numBonusVillages, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numBonusVillages, 0, math.MaxInt); err != nil {
|
||||||
return VillagesSyncedEventPayload{}, ValidationError{
|
return VillagesSyncedEventPayload{}, ValidationError{
|
||||||
Model: villagesSyncedEventPayloadModelName,
|
Model: villagesSyncedEventPayloadModelName,
|
||||||
Field: "numBonusVillages",
|
Field: "numBonusVillages",
|
||||||
|
|
|
@ -25,7 +25,7 @@ func NewOpponentsDefeated(
|
||||||
rankTotal int,
|
rankTotal int,
|
||||||
scoreTotal int,
|
scoreTotal int,
|
||||||
) (OpponentsDefeated, error) {
|
) (OpponentsDefeated, error) {
|
||||||
if err := validateIntInRange(rankAtt, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rankAtt, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "rankAtt",
|
Field: "rankAtt",
|
||||||
|
@ -33,7 +33,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(scoreAtt, 0, math.MaxInt); err != nil {
|
if err := validateInRange(scoreAtt, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "scoreAtt",
|
Field: "scoreAtt",
|
||||||
|
@ -41,7 +41,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(rankDef, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rankDef, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "rankDef",
|
Field: "rankDef",
|
||||||
|
@ -49,7 +49,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(scoreDef, 0, math.MaxInt); err != nil {
|
if err := validateInRange(scoreDef, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "scoreDef",
|
Field: "scoreDef",
|
||||||
|
@ -57,7 +57,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(rankSup, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rankSup, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "rankSup",
|
Field: "rankSup",
|
||||||
|
@ -65,7 +65,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(scoreSup, 0, math.MaxInt); err != nil {
|
if err := validateInRange(scoreSup, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "scoreSup",
|
Field: "scoreSup",
|
||||||
|
@ -73,7 +73,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(rankTotal, 0, math.MaxInt); err != nil {
|
if err := validateInRange(rankTotal, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "rankTotal",
|
Field: "rankTotal",
|
||||||
|
@ -81,7 +81,7 @@ func NewOpponentsDefeated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(scoreTotal, 0, math.MaxInt); err != nil {
|
if err := validateInRange(scoreTotal, 0, math.MaxInt); err != nil {
|
||||||
return OpponentsDefeated{}, ValidationError{
|
return OpponentsDefeated{}, ValidationError{
|
||||||
Model: opponentsDefeatedModelName,
|
Model: opponentsDefeatedModelName,
|
||||||
Field: "scoreTotal",
|
Field: "scoreTotal",
|
||||||
|
|
|
@ -58,7 +58,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "rankAtt",
|
Field: "rankAtt",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -79,7 +79,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "scoreAtt",
|
Field: "scoreAtt",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -100,7 +100,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "rankDef",
|
Field: "rankDef",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -121,7 +121,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "scoreDef",
|
Field: "scoreDef",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -142,7 +142,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "rankSup",
|
Field: "rankSup",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -163,7 +163,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "scoreSup",
|
Field: "scoreSup",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -184,7 +184,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "rankTotal",
|
Field: "rankTotal",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -205,7 +205,7 @@ func TestNewOpponentsDefeated(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "OpponentsDefeated",
|
Model: "OpponentsDefeated",
|
||||||
Field: "scoreTotal",
|
Field: "scoreTotal",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,7 +61,7 @@ func UnmarshalPlayerFromDatabase(
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
deletedAt time.Time,
|
deletedAt time.Time,
|
||||||
) (Player, error) {
|
) (Player, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return Player{}, ValidationError{
|
return Player{}, ValidationError{
|
||||||
Model: playerModelName,
|
Model: playerModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -200,6 +200,7 @@ func (p Player) ToCursor() (PlayerCursor, error) {
|
||||||
p.od.scoreSup,
|
p.od.scoreSup,
|
||||||
p.od.scoreTotal,
|
p.od.scoreTotal,
|
||||||
p.points,
|
p.points,
|
||||||
|
p.mostPoints,
|
||||||
p.deletedAt,
|
p.deletedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -326,7 +327,7 @@ const playerMetaModelName = "PlayerMeta"
|
||||||
// It should be used only for unmarshalling 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!
|
// 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) {
|
func UnmarshalPlayerMetaFromDatabase(id int, name string, rawProfileURL string) (PlayerMeta, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return PlayerMeta{}, ValidationError{
|
return PlayerMeta{}, ValidationError{
|
||||||
Model: playerMetaModelName,
|
Model: playerMetaModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -552,6 +553,8 @@ const (
|
||||||
PlayerSortODScoreTotalDESC
|
PlayerSortODScoreTotalDESC
|
||||||
PlayerSortPointsASC
|
PlayerSortPointsASC
|
||||||
PlayerSortPointsDESC
|
PlayerSortPointsDESC
|
||||||
|
PlayerSortMostPointsASC
|
||||||
|
PlayerSortMostPointsDESC
|
||||||
PlayerSortDeletedAtASC
|
PlayerSortDeletedAtASC
|
||||||
PlayerSortDeletedAtDESC
|
PlayerSortDeletedAtDESC
|
||||||
)
|
)
|
||||||
|
@ -592,6 +595,10 @@ func (s PlayerSort) String() string {
|
||||||
return "points:ASC"
|
return "points:ASC"
|
||||||
case PlayerSortPointsDESC:
|
case PlayerSortPointsDESC:
|
||||||
return "points:DESC"
|
return "points:DESC"
|
||||||
|
case PlayerSortMostPointsASC:
|
||||||
|
return "mostPoints:ASC"
|
||||||
|
case PlayerSortMostPointsDESC:
|
||||||
|
return "mostPoints:DESC"
|
||||||
case PlayerSortDeletedAtASC:
|
case PlayerSortDeletedAtASC:
|
||||||
return "deletedAt:ASC"
|
return "deletedAt:ASC"
|
||||||
case PlayerSortDeletedAtDESC:
|
case PlayerSortDeletedAtDESC:
|
||||||
|
@ -609,6 +616,7 @@ type PlayerCursor struct {
|
||||||
odScoreSup int
|
odScoreSup int
|
||||||
odScoreTotal int
|
odScoreTotal int
|
||||||
points int
|
points int
|
||||||
|
mostPoints int
|
||||||
deletedAt time.Time
|
deletedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,9 +630,10 @@ func NewPlayerCursor(
|
||||||
odScoreSup int,
|
odScoreSup int,
|
||||||
odScoreTotal int,
|
odScoreTotal int,
|
||||||
points int,
|
points int,
|
||||||
|
mostPoints int,
|
||||||
deletedAt time.Time,
|
deletedAt time.Time,
|
||||||
) (PlayerCursor, error) {
|
) (PlayerCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -640,7 +649,7 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreAtt, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreAtt, 0, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "odScoreAtt",
|
Field: "odScoreAtt",
|
||||||
|
@ -648,7 +657,7 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreDef, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreDef, 0, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "odScoreDef",
|
Field: "odScoreDef",
|
||||||
|
@ -656,7 +665,7 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreSup, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreSup, 0, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "odScoreSup",
|
Field: "odScoreSup",
|
||||||
|
@ -664,7 +673,7 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreTotal, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreTotal, 0, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "odScoreTotal",
|
Field: "odScoreTotal",
|
||||||
|
@ -672,7 +681,7 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return PlayerCursor{}, ValidationError{
|
return PlayerCursor{}, ValidationError{
|
||||||
Model: playerCursorModelName,
|
Model: playerCursorModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
@ -680,6 +689,14 @@ func NewPlayerCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateInRange(mostPoints, 0, math.MaxInt); err != nil {
|
||||||
|
return PlayerCursor{}, ValidationError{
|
||||||
|
Model: playerCursorModelName,
|
||||||
|
Field: "mostPoints",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PlayerCursor{
|
return PlayerCursor{
|
||||||
id: id,
|
id: id,
|
||||||
serverKey: serverKey,
|
serverKey: serverKey,
|
||||||
|
@ -688,6 +705,7 @@ func NewPlayerCursor(
|
||||||
odScoreSup: odScoreSup,
|
odScoreSup: odScoreSup,
|
||||||
odScoreTotal: odScoreTotal,
|
odScoreTotal: odScoreTotal,
|
||||||
points: points,
|
points: points,
|
||||||
|
mostPoints: mostPoints,
|
||||||
deletedAt: deletedAt,
|
deletedAt: deletedAt,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -734,6 +752,11 @@ func decodePlayerCursor(encoded string) (PlayerCursor, error) {
|
||||||
return PlayerCursor{}, ErrInvalidCursor
|
return PlayerCursor{}, ErrInvalidCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mostPoints, err := m.int("mostPoints")
|
||||||
|
if err != nil {
|
||||||
|
return PlayerCursor{}, ErrInvalidCursor
|
||||||
|
}
|
||||||
|
|
||||||
deletedAt, err := m.time("deletedAt")
|
deletedAt, err := m.time("deletedAt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return PlayerCursor{}, ErrInvalidCursor
|
return PlayerCursor{}, ErrInvalidCursor
|
||||||
|
@ -747,6 +770,7 @@ func decodePlayerCursor(encoded string) (PlayerCursor, error) {
|
||||||
odScoreSup,
|
odScoreSup,
|
||||||
odScoreTotal,
|
odScoreTotal,
|
||||||
points,
|
points,
|
||||||
|
mostPoints,
|
||||||
deletedAt,
|
deletedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -784,6 +808,10 @@ func (pc PlayerCursor) Points() int {
|
||||||
return pc.points
|
return pc.points
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pc PlayerCursor) MostPoints() int {
|
||||||
|
return pc.mostPoints
|
||||||
|
}
|
||||||
|
|
||||||
func (pc PlayerCursor) DeletedAt() time.Time {
|
func (pc PlayerCursor) DeletedAt() time.Time {
|
||||||
return pc.deletedAt
|
return pc.deletedAt
|
||||||
}
|
}
|
||||||
|
@ -805,6 +833,7 @@ func (pc PlayerCursor) Encode() string {
|
||||||
{"odScoreSup", pc.odScoreSup},
|
{"odScoreSup", pc.odScoreSup},
|
||||||
{"odScoreTotal", pc.odScoreTotal},
|
{"odScoreTotal", pc.odScoreTotal},
|
||||||
{"points", pc.points},
|
{"points", pc.points},
|
||||||
|
{"mostPoints", pc.mostPoints},
|
||||||
{"deletedAt", pc.deletedAt},
|
{"deletedAt", pc.deletedAt},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -842,7 +871,7 @@ func (params *ListPlayersParams) IDs() []int {
|
||||||
|
|
||||||
func (params *ListPlayersParams) SetIDs(ids []int) error {
|
func (params *ListPlayersParams) SetIDs(ids []int) error {
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listPlayersParamsModelName,
|
Model: listPlayersParamsModelName,
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
|
@ -939,7 +968,7 @@ func (params *ListPlayersParams) TribeIDs() []int {
|
||||||
|
|
||||||
func (params *ListPlayersParams) SetTribeIDs(tribeIDs []int) error {
|
func (params *ListPlayersParams) SetTribeIDs(tribeIDs []int) error {
|
||||||
for i, id := range tribeIDs {
|
for i, id := range tribeIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listPlayersParamsModelName,
|
Model: listPlayersParamsModelName,
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
|
@ -1062,7 +1091,7 @@ func (params *ListPlayersParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListPlayersParams) SetLimit(limit int) error {
|
func (params *ListPlayersParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, PlayerListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, PlayerListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listPlayersParamsModelName,
|
Model: listPlayersParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -39,7 +39,7 @@ func UnmarshalPlayerSnapshotFromDatabase(
|
||||||
date time.Time,
|
date time.Time,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (PlayerSnapshot, error) {
|
) (PlayerSnapshot, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return PlayerSnapshot{}, ValidationError{
|
return PlayerSnapshot{}, ValidationError{
|
||||||
Model: playerSnapshotModelName,
|
Model: playerSnapshotModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -47,7 +47,7 @@ func UnmarshalPlayerSnapshotFromDatabase(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(playerID, 1, math.MaxInt); err != nil {
|
if err := validateInRange(playerID, 1, math.MaxInt); err != nil {
|
||||||
return PlayerSnapshot{}, ValidationError{
|
return PlayerSnapshot{}, ValidationError{
|
||||||
Model: playerSnapshotModelName,
|
Model: playerSnapshotModelName,
|
||||||
Field: "playerID",
|
Field: "playerID",
|
||||||
|
@ -275,7 +275,7 @@ type PlayerSnapshotCursor struct {
|
||||||
const playerSnapshotCursorModelName = "PlayerSnapshotCursor"
|
const playerSnapshotCursorModelName = "PlayerSnapshotCursor"
|
||||||
|
|
||||||
func NewPlayerSnapshotCursor(id int, serverKey string, date time.Time) (PlayerSnapshotCursor, error) {
|
func NewPlayerSnapshotCursor(id int, serverKey string, date time.Time) (PlayerSnapshotCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return PlayerSnapshotCursor{}, ValidationError{
|
return PlayerSnapshotCursor{}, ValidationError{
|
||||||
Model: playerSnapshotCursorModelName,
|
Model: playerSnapshotCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -411,7 +411,7 @@ func (params *ListPlayerSnapshotsParams) PlayerIDs() []int {
|
||||||
|
|
||||||
func (params *ListPlayerSnapshotsParams) SetPlayerIDs(playerIDs []int) error {
|
func (params *ListPlayerSnapshotsParams) SetPlayerIDs(playerIDs []int) error {
|
||||||
for i, id := range playerIDs {
|
for i, id := range playerIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listPlayerSnapshotsParamsModelName,
|
Model: listPlayerSnapshotsParamsModelName,
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
|
@ -529,7 +529,7 @@ func (params *ListPlayerSnapshotsParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListPlayerSnapshotsParams) SetLimit(limit int) error {
|
func (params *ListPlayerSnapshotsParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, PlayerSnapshotListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, PlayerSnapshotListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listPlayerSnapshotsParamsModelName,
|
Model: listPlayerSnapshotsParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -147,7 +147,7 @@ func TestNewPlayerSnapshotCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerSnapshotCursor",
|
Model: "PlayerSnapshotCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -282,7 +282,7 @@ func TestListPlayerSnapshotsParams_SetPlayerIDs(t *testing.T) {
|
||||||
Model: "ListPlayerSnapshotsParams",
|
Model: "ListPlayerSnapshotsParams",
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -840,7 +840,7 @@ func TestListPlayerSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListPlayerSnapshotsParams",
|
Model: "ListPlayerSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -854,7 +854,7 @@ func TestListPlayerSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListPlayerSnapshotsParams",
|
Model: "ListPlayerSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerSnapshotListMaxLimit,
|
Max: domain.PlayerSnapshotListMaxLimit,
|
||||||
Current: domain.PlayerSnapshotListMaxLimit + 1,
|
Current: domain.PlayerSnapshotListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -303,6 +303,13 @@ func TestPlayerSort_IsInConflict(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectedRes: true,
|
expectedRes: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: mostPoints:ASC mostPoints:DESC",
|
||||||
|
args: args{
|
||||||
|
sorts: [2]domain.PlayerSort{domain.PlayerSortMostPointsASC, domain.PlayerSortMostPointsDESC},
|
||||||
|
},
|
||||||
|
expectedRes: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: deletedAt:ASC deletedAt:DESC",
|
name: "OK: deletedAt:ASC deletedAt:DESC",
|
||||||
args: args{
|
args: args{
|
||||||
|
@ -334,6 +341,7 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup int
|
odScoreSup int
|
||||||
odScoreTotal int
|
odScoreTotal int
|
||||||
points int
|
points int
|
||||||
|
mostPoints int
|
||||||
deletedAt time.Time
|
deletedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,6 +362,7 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
|
@ -368,12 +377,13 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -389,12 +399,13 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "odScoreAtt",
|
Field: "odScoreAtt",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -410,12 +421,13 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "odScoreDef",
|
Field: "odScoreDef",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -431,12 +443,13 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: -1,
|
odScoreSup: -1,
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "odScoreSup",
|
Field: "odScoreSup",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -452,12 +465,13 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: -1,
|
odScoreTotal: -1,
|
||||||
points: validPlayerCursor.Points(),
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "odScoreTotal",
|
Field: "odScoreTotal",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -473,12 +487,35 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
odScoreSup: validPlayerCursor.ODScoreSup(),
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
points: -1,
|
points: -1,
|
||||||
|
mostPoints: validPlayerCursor.MostPoints(),
|
||||||
deletedAt: validPlayerCursor.DeletedAt(),
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "PlayerCursor",
|
Model: "PlayerCursor",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
|
Min: 0,
|
||||||
|
Current: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: mostPoints < 0",
|
||||||
|
args: args{
|
||||||
|
id: validPlayerCursor.ID(),
|
||||||
|
serverKey: validPlayerCursor.ServerKey(),
|
||||||
|
odScoreAtt: validPlayerCursor.ODScoreAtt(),
|
||||||
|
odScoreDef: validPlayerCursor.ODScoreDef(),
|
||||||
|
odScoreSup: validPlayerCursor.ODScoreSup(),
|
||||||
|
odScoreTotal: validPlayerCursor.ODScoreTotal(),
|
||||||
|
points: validPlayerCursor.Points(),
|
||||||
|
mostPoints: -1,
|
||||||
|
deletedAt: validPlayerCursor.DeletedAt(),
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "PlayerCursor",
|
||||||
|
Field: "mostPoints",
|
||||||
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -518,6 +555,7 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
tt.args.odScoreSup,
|
tt.args.odScoreSup,
|
||||||
tt.args.odScoreTotal,
|
tt.args.odScoreTotal,
|
||||||
tt.args.points,
|
tt.args.points,
|
||||||
|
tt.args.mostPoints,
|
||||||
tt.args.deletedAt,
|
tt.args.deletedAt,
|
||||||
)
|
)
|
||||||
require.ErrorIs(t, err, tt.expectedErr)
|
require.ErrorIs(t, err, tt.expectedErr)
|
||||||
|
@ -531,6 +569,7 @@ func TestNewPlayerCursor(t *testing.T) {
|
||||||
assert.Equal(t, tt.args.odScoreSup, pc.ODScoreSup())
|
assert.Equal(t, tt.args.odScoreSup, pc.ODScoreSup())
|
||||||
assert.Equal(t, tt.args.odScoreTotal, pc.ODScoreTotal())
|
assert.Equal(t, tt.args.odScoreTotal, pc.ODScoreTotal())
|
||||||
assert.Equal(t, tt.args.points, pc.Points())
|
assert.Equal(t, tt.args.points, pc.Points())
|
||||||
|
assert.Equal(t, tt.args.mostPoints, pc.MostPoints())
|
||||||
assert.Equal(t, tt.args.deletedAt, pc.DeletedAt())
|
assert.Equal(t, tt.args.deletedAt, pc.DeletedAt())
|
||||||
assert.NotEmpty(t, pc.Encode())
|
assert.NotEmpty(t, pc.Encode())
|
||||||
})
|
})
|
||||||
|
@ -574,7 +613,7 @@ func TestListPlayersParams_SetIDs(t *testing.T) {
|
||||||
Model: "ListPlayersParams",
|
Model: "ListPlayersParams",
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -845,7 +884,7 @@ func TestListPlayersParams_SetTribeIDs(t *testing.T) {
|
||||||
Model: "ListPlayersParams",
|
Model: "ListPlayersParams",
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1490,7 +1529,7 @@ func TestListPlayersParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListPlayersParams",
|
Model: "ListPlayersParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1504,7 +1543,7 @@ func TestListPlayersParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListPlayersParams",
|
Model: "ListPlayersParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerListMaxLimit,
|
Max: domain.PlayerListMaxLimit,
|
||||||
Current: domain.PlayerListMaxLimit + 1,
|
Current: domain.PlayerListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -466,7 +466,7 @@ func (params *UpdateServerParams) NumTribes() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumTribes(num NullInt) error {
|
func (params *UpdateServerParams) SetNumTribes(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numTribes",
|
Field: "numTribes",
|
||||||
|
@ -486,7 +486,7 @@ func (params *UpdateServerParams) NumActiveTribes() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumActiveTribes(num NullInt) error {
|
func (params *UpdateServerParams) SetNumActiveTribes(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numActiveTribes",
|
Field: "numActiveTribes",
|
||||||
|
@ -506,7 +506,7 @@ func (params *UpdateServerParams) NumInactiveTribes() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumInactiveTribes(num NullInt) error {
|
func (params *UpdateServerParams) SetNumInactiveTribes(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numInactiveTribes",
|
Field: "numInactiveTribes",
|
||||||
|
@ -535,7 +535,7 @@ func (params *UpdateServerParams) NumPlayers() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumPlayers(num NullInt) error {
|
func (params *UpdateServerParams) SetNumPlayers(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numPlayers",
|
Field: "numPlayers",
|
||||||
|
@ -555,7 +555,7 @@ func (params *UpdateServerParams) NumActivePlayers() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumActivePlayers(num NullInt) error {
|
func (params *UpdateServerParams) SetNumActivePlayers(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numActivePlayers",
|
Field: "numActivePlayers",
|
||||||
|
@ -575,7 +575,7 @@ func (params *UpdateServerParams) NumInactivePlayers() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumInactivePlayers(num NullInt) error {
|
func (params *UpdateServerParams) SetNumInactivePlayers(num NullInt) error {
|
||||||
if num.Valid {
|
if num.Valid {
|
||||||
if err := validateIntInRange(num.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(num.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numInactivePlayers",
|
Field: "numInactivePlayers",
|
||||||
|
@ -604,7 +604,7 @@ func (params *UpdateServerParams) NumVillages() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumVillages(numVillages NullInt) error {
|
func (params *UpdateServerParams) SetNumVillages(numVillages NullInt) error {
|
||||||
if numVillages.Valid {
|
if numVillages.Valid {
|
||||||
if err := validateIntInRange(numVillages.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numVillages.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
|
@ -624,7 +624,7 @@ func (params *UpdateServerParams) NumPlayerVillages() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumPlayerVillages(numPlayerVillages NullInt) error {
|
func (params *UpdateServerParams) SetNumPlayerVillages(numPlayerVillages NullInt) error {
|
||||||
if numPlayerVillages.Valid {
|
if numPlayerVillages.Valid {
|
||||||
if err := validateIntInRange(numPlayerVillages.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numPlayerVillages.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numPlayerVillages",
|
Field: "numPlayerVillages",
|
||||||
|
@ -644,7 +644,7 @@ func (params *UpdateServerParams) NumBarbarianVillages() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumBarbarianVillages(numBarbarianVillages NullInt) error {
|
func (params *UpdateServerParams) SetNumBarbarianVillages(numBarbarianVillages NullInt) error {
|
||||||
if numBarbarianVillages.Valid {
|
if numBarbarianVillages.Valid {
|
||||||
if err := validateIntInRange(numBarbarianVillages.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numBarbarianVillages.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numBarbarianVillages",
|
Field: "numBarbarianVillages",
|
||||||
|
@ -664,7 +664,7 @@ func (params *UpdateServerParams) NumBonusVillages() NullInt {
|
||||||
|
|
||||||
func (params *UpdateServerParams) SetNumBonusVillages(numBonusVillages NullInt) error {
|
func (params *UpdateServerParams) SetNumBonusVillages(numBonusVillages NullInt) error {
|
||||||
if numBonusVillages.Valid {
|
if numBonusVillages.Valid {
|
||||||
if err := validateIntInRange(numBonusVillages.V, 0, math.MaxInt); err != nil {
|
if err := validateInRange(numBonusVillages.V, 0, math.MaxInt); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: updateServerParamsModelName,
|
Model: updateServerParamsModelName,
|
||||||
Field: "numBonusVillages",
|
Field: "numBonusVillages",
|
||||||
|
@ -1006,7 +1006,7 @@ func (params *ListServersParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListServersParams) SetLimit(limit int) error {
|
func (params *ListServersParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, ServerListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, ServerListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listServersParamsModelName,
|
Model: listServersParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
385
internal/domain/server_map.go
Normal file
385
internal/domain/server_map.go
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"golang.org/x/image/draw"
|
||||||
|
"golang.org/x/image/font"
|
||||||
|
"golang.org/x/image/font/basicfont"
|
||||||
|
"golang.org/x/image/math/fixed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerMapMarker struct {
|
||||||
|
village VillageMeta
|
||||||
|
color color.RGBA
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerMapMarker(village VillageMeta) ServerMapMarker {
|
||||||
|
return ServerMapMarker{
|
||||||
|
village: village,
|
||||||
|
color: color.RGBA{R: 255, G: 99, B: 71, A: 255},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMapMarker) Village() VillageMeta {
|
||||||
|
return m.village
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMapMarker) SetColor(c color.RGBA) error {
|
||||||
|
m.color = c
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMapMarker) Color() color.RGBA {
|
||||||
|
return m.color
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerMapLegendEntry struct {
|
||||||
|
color color.Color
|
||||||
|
names []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerMapLegendEntry(c color.Color, names ...string) ServerMapLegendEntry {
|
||||||
|
return ServerMapLegendEntry{color: c, names: names}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ServerMapLegendEntry) Color() color.Color {
|
||||||
|
return e.color
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ServerMapLegendEntry) Names() []string {
|
||||||
|
return e.names
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerMap struct {
|
||||||
|
server Server
|
||||||
|
size int
|
||||||
|
markersCh <-chan ServerMapMarker
|
||||||
|
backgroundColor color.RGBA
|
||||||
|
scale float32
|
||||||
|
centerX int
|
||||||
|
centerY int
|
||||||
|
continentGrid bool
|
||||||
|
gridLineColor color.RGBA
|
||||||
|
continentNumbers bool
|
||||||
|
continentNumberColor color.RGBA
|
||||||
|
legendEntries []ServerMapLegendEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverMapModelName = "ServerMap"
|
||||||
|
|
||||||
|
func NewServerMap(server Server, markersCh <-chan ServerMapMarker) ServerMap {
|
||||||
|
size := server.Config().Coord().MapSize
|
||||||
|
|
||||||
|
return ServerMap{
|
||||||
|
server: server,
|
||||||
|
size: size,
|
||||||
|
markersCh: markersCh,
|
||||||
|
backgroundColor: color.RGBA{
|
||||||
|
A: 255,
|
||||||
|
},
|
||||||
|
scale: 1,
|
||||||
|
centerX: size / 2,
|
||||||
|
centerY: size / 2,
|
||||||
|
continentGrid: true,
|
||||||
|
gridLineColor: color.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||||
|
continentNumbers: true,
|
||||||
|
continentNumberColor: color.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) Scale() float32 {
|
||||||
|
return m.scale
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
serverMapMinScale = 1
|
||||||
|
serverMapMaxScale = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *ServerMap) SetScale(scale float32) error {
|
||||||
|
if err := validateInRange(scale, serverMapMinScale, serverMapMaxScale); err != nil {
|
||||||
|
return ValidationError{
|
||||||
|
Model: serverMapModelName,
|
||||||
|
Field: "scale",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.scale = scale
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) BackgroundColor() color.RGBA {
|
||||||
|
return m.backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetBackgroundColor(backgroundColor color.RGBA) error {
|
||||||
|
m.backgroundColor = backgroundColor
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) CenterX() int {
|
||||||
|
return m.centerX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetCenterX(centerX int) error {
|
||||||
|
m.centerX = centerX
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) CenterY() int {
|
||||||
|
return m.centerY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetCenterY(centerY int) error {
|
||||||
|
m.centerY = centerY
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) ContinentGrid() bool {
|
||||||
|
return m.continentGrid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetContinentGrid(continentGrid bool) error {
|
||||||
|
m.continentGrid = continentGrid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) GridLineColor() color.RGBA {
|
||||||
|
return m.gridLineColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetGridLineColor(gridLineColor color.RGBA) error {
|
||||||
|
m.gridLineColor = gridLineColor
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) ContinentNumbers() bool {
|
||||||
|
return m.continentNumbers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetContinentNumbers(continentNumbers bool) error {
|
||||||
|
m.continentNumbers = continentNumbers
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) ContinentNumberColor() color.RGBA {
|
||||||
|
return m.continentNumberColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetContinentNumberColor(continentNumberColor color.RGBA) error {
|
||||||
|
m.continentNumberColor = continentNumberColor
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) LegendEntries() []ServerMapLegendEntry {
|
||||||
|
return m.legendEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) SetLegendEntries(legendEntries []ServerMapLegendEntry) error {
|
||||||
|
m.legendEntries = legendEntries
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) Generate(w io.Writer) error {
|
||||||
|
r := image.Rectangle{Max: image.Point{X: m.size, Y: m.size}}
|
||||||
|
imgHalfWidth := r.Dx() / 2
|
||||||
|
imgHalfHeight := r.Dy() / 2
|
||||||
|
|
||||||
|
img := image.NewRGBA(r)
|
||||||
|
|
||||||
|
draw.Draw(img, img.Bounds(), image.NewUniform(m.backgroundColor), image.Point{}, draw.Src)
|
||||||
|
m.drawContinentGrid(img)
|
||||||
|
m.drawMarkers(img)
|
||||||
|
m.drawContinentNumbers(img)
|
||||||
|
legend, err := m.generateLegend()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
scaledImg := m.scaleImg(img)
|
||||||
|
|
||||||
|
final := image.NewRGBA(image.Rect(0, 0, r.Dx()+legend.Rect.Dx(), r.Dy()))
|
||||||
|
draw.Draw(final, scaledImg.Rect, scaledImg, image.Point{
|
||||||
|
X: int(float32(m.centerX)*m.scale) - imgHalfWidth,
|
||||||
|
Y: int(float32(m.centerY)*m.scale) - imgHalfHeight,
|
||||||
|
}, draw.Src)
|
||||||
|
draw.Draw(final, image.Rect(r.Dx(), 0, final.Rect.Dx(), final.Rect.Dy()), legend, image.Point{}, draw.Src)
|
||||||
|
|
||||||
|
if err = png.Encode(w, final); err != nil {
|
||||||
|
return fmt.Errorf("couldn't encode image: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverMapContinentDx = 100
|
||||||
|
|
||||||
|
func (m *ServerMap) drawContinentGrid(img *image.RGBA) {
|
||||||
|
if !m.continentGrid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for y := serverMapContinentDx; y < m.size; y += serverMapContinentDx {
|
||||||
|
for x := range m.size {
|
||||||
|
img.Set(x, y, m.gridLineColor)
|
||||||
|
img.Set(y, x, m.gridLineColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverMapMarkerRectSideLength = 1
|
||||||
|
|
||||||
|
func (m *ServerMap) drawMarkers(img *image.RGBA) {
|
||||||
|
for marker := range m.markersCh {
|
||||||
|
village := marker.Village()
|
||||||
|
x := village.X()
|
||||||
|
y := village.Y()
|
||||||
|
rect := image.Rect(x, y, x+serverMapMarkerRectSideLength, y+serverMapMarkerRectSideLength)
|
||||||
|
draw.Draw(img, rect, &image.Uniform{C: marker.color}, image.Point{}, draw.Over)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) drawContinentNumbers(img *image.RGBA) {
|
||||||
|
if !m.continentNumbers {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
continent := 0
|
||||||
|
|
||||||
|
d := &font.Drawer{
|
||||||
|
Dst: img,
|
||||||
|
Src: image.NewUniform(m.continentNumberColor),
|
||||||
|
Face: basicfont.Face7x13,
|
||||||
|
}
|
||||||
|
|
||||||
|
for y := serverMapContinentDx; y <= m.size; y += serverMapContinentDx {
|
||||||
|
for x := serverMapContinentDx; x <= m.size; x += serverMapContinentDx {
|
||||||
|
continentStr := strconv.Itoa(continent)
|
||||||
|
|
||||||
|
d.Dot = fixed.Point26_6{
|
||||||
|
X: fixed.I(x) - d.MeasureString(continentStr),
|
||||||
|
Y: fixed.I(y - 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
d.DrawString(continentStr)
|
||||||
|
|
||||||
|
continent++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) scaleImg(img *image.RGBA) *image.RGBA {
|
||||||
|
if m.scale == 1 {
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
scaledSize := int(float32(m.size) * m.scale)
|
||||||
|
scaledImg := image.NewRGBA(image.Rect(0, 0, scaledSize, scaledSize))
|
||||||
|
draw.NearestNeighbor.Scale(scaledImg, scaledImg.Rect, img, img.Rect, draw.Over, nil)
|
||||||
|
|
||||||
|
return scaledImg
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
serverMapLegendWidth = 400
|
||||||
|
serverMapLegendPadding = 10
|
||||||
|
serverMapColorWidth = 40
|
||||||
|
serverMapSpaceColorText = 10
|
||||||
|
serverMapLegendStringSeparator = " + "
|
||||||
|
serverMapLegendStringOverflow = "..."
|
||||||
|
serverMapLegendMaxStringLength = 45
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrTooManyLegendEntries error = simpleError{
|
||||||
|
msg: "too many legend entries",
|
||||||
|
typ: ErrorTypeIncorrectInput,
|
||||||
|
code: "too-many-legend-entries",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServerMap) generateLegend() (*image.RGBA, error) {
|
||||||
|
if len(m.legendEntries) == 0 {
|
||||||
|
return image.NewRGBA(image.Rectangle{}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
img := image.NewRGBA(image.Rectangle{Max: image.Point{X: serverMapLegendWidth, Y: m.size}})
|
||||||
|
d := &font.Drawer{
|
||||||
|
Dst: img,
|
||||||
|
Src: image.NewUniform(m.continentNumberColor),
|
||||||
|
Face: basicfont.Face7x13,
|
||||||
|
}
|
||||||
|
lineHeight := basicfont.Face7x13.Metrics().Ascent.Ceil() + basicfont.Face7x13.Metrics().Descent.Ceil()
|
||||||
|
lineMaxWidth := img.Rect.Dx() - serverMapLegendPadding*2 - serverMapColorWidth - serverMapSpaceColorText
|
||||||
|
offset := serverMapLegendPadding
|
||||||
|
|
||||||
|
for _, e := range m.legendEntries {
|
||||||
|
namesLen := len(e.Names())
|
||||||
|
|
||||||
|
currentWidth := 0
|
||||||
|
line := ""
|
||||||
|
var lines []string
|
||||||
|
|
||||||
|
for i, name := range e.Names() {
|
||||||
|
if len(name) > serverMapLegendMaxStringLength {
|
||||||
|
name = name[:serverMapLegendMaxStringLength-len(serverMapLegendStringOverflow)] + "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
if i != namesLen-1 {
|
||||||
|
name += serverMapLegendStringSeparator
|
||||||
|
}
|
||||||
|
|
||||||
|
strWidth := d.MeasureString(name).Ceil()
|
||||||
|
|
||||||
|
if currentWidth+strWidth > lineMaxWidth {
|
||||||
|
lines = append(lines, line)
|
||||||
|
currentWidth = 0
|
||||||
|
line = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
line += name
|
||||||
|
currentWidth += strWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
if line != "" {
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
yMin := offset + (len(lines) * lineHeight / 2) - lineHeight/2
|
||||||
|
|
||||||
|
draw.Draw(
|
||||||
|
img,
|
||||||
|
image.Rect(
|
||||||
|
serverMapLegendPadding,
|
||||||
|
yMin,
|
||||||
|
serverMapColorWidth+serverMapLegendPadding,
|
||||||
|
yMin+lineHeight,
|
||||||
|
),
|
||||||
|
image.NewUniform(e.Color()),
|
||||||
|
image.Point{},
|
||||||
|
draw.Src,
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, l := range lines {
|
||||||
|
d.Dot = fixed.Point26_6{
|
||||||
|
X: fixed.I(serverMapColorWidth + serverMapLegendPadding + serverMapSpaceColorText),
|
||||||
|
Y: fixed.I(offset + (i+1)*lineHeight),
|
||||||
|
}
|
||||||
|
d.DrawString(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += (len(lines) * lineHeight) + serverMapLegendPadding
|
||||||
|
|
||||||
|
if offset > img.Bounds().Dy()-serverMapLegendPadding {
|
||||||
|
return nil, ErrTooManyLegendEntries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return img, nil
|
||||||
|
}
|
155
internal/domain/server_map_test.go
Normal file
155
internal/domain/server_map_test.go
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
package domain_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain/domaintest"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServerMap_SetScale(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
scale float32
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK",
|
||||||
|
args: args{
|
||||||
|
scale: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: scale < 1",
|
||||||
|
args: args{
|
||||||
|
scale: 0.99,
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ServerMap",
|
||||||
|
Field: "scale",
|
||||||
|
Err: domain.MinGreaterEqualError[float32]{
|
||||||
|
Min: 1,
|
||||||
|
Current: 0.99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: scale > 5",
|
||||||
|
args: args{
|
||||||
|
scale: 5.00001,
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ServerMap",
|
||||||
|
Field: "scale",
|
||||||
|
Err: domain.MaxLessEqualError[float32]{
|
||||||
|
Max: 5,
|
||||||
|
Current: 5.00001,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
params := domain.NewServerMap(domaintest.NewServer(t), make(chan domain.ServerMapMarker))
|
||||||
|
|
||||||
|
require.ErrorIs(t, params.SetScale(tt.args.scale), tt.expectedErr)
|
||||||
|
if tt.expectedErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.InDelta(t, tt.args.scale, params.Scale(), 0.001)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerMap_Generate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("OK: default", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ch := make(chan domain.ServerMapMarker)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
for i := range 500 {
|
||||||
|
ch <- domain.NewServerMapMarker(domaintest.NewVillage(t, func(cfg *domaintest.VillageConfig) {
|
||||||
|
cfg.X = i
|
||||||
|
cfg.Y = i
|
||||||
|
}).Meta())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
m := domain.NewServerMap(domaintest.NewServer(t), ch)
|
||||||
|
require.NoError(t, m.Generate(io.Discard))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: scale=2 legend", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ch := make(chan domain.ServerMapMarker)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
for i := range 500 {
|
||||||
|
ch <- domain.NewServerMapMarker(domaintest.NewVillage(t, func(cfg *domaintest.VillageConfig) {
|
||||||
|
cfg.X = i
|
||||||
|
cfg.Y = i
|
||||||
|
}).Meta())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
m := domain.NewServerMap(domaintest.NewServer(t), ch)
|
||||||
|
require.NoError(t, m.SetLegendEntries([]domain.ServerMapLegendEntry{
|
||||||
|
domain.NewServerMapLegendEntry(
|
||||||
|
color.RGBA{R: 255, G: 204, B: 229, A: 255},
|
||||||
|
"test22222^",
|
||||||
|
"test222",
|
||||||
|
),
|
||||||
|
domain.NewServerMapLegendEntry(
|
||||||
|
color.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||||
|
"test22222^",
|
||||||
|
"test2223",
|
||||||
|
"longstringlongstringlongstringlongstring",
|
||||||
|
"longstringlongstringlongstringlongstringlongstringlongstringlongstringlongstring",
|
||||||
|
"longstringlongstring2",
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
require.NoError(t, m.SetScale(2))
|
||||||
|
require.NoError(t, m.Generate(io.Discard))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: scale=2 centerX=250 centerY=250", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ch := make(chan domain.ServerMapMarker)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(ch)
|
||||||
|
for i := range 500 {
|
||||||
|
ch <- domain.NewServerMapMarker(domaintest.NewVillage(t, func(cfg *domaintest.VillageConfig) {
|
||||||
|
cfg.X = i
|
||||||
|
cfg.Y = i
|
||||||
|
}).Meta())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
m := domain.NewServerMap(domaintest.NewServer(t), ch)
|
||||||
|
require.NoError(t, m.SetCenterX(250))
|
||||||
|
require.NoError(t, m.SetCenterY(250))
|
||||||
|
require.NoError(t, m.SetScale(2))
|
||||||
|
require.NoError(t, m.Generate(io.Discard))
|
||||||
|
})
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ func UnmarshalServerSnapshotFromDatabase(
|
||||||
date time.Time,
|
date time.Time,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (ServerSnapshot, error) {
|
) (ServerSnapshot, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return ServerSnapshot{}, ValidationError{
|
return ServerSnapshot{}, ValidationError{
|
||||||
Model: serverSnapshotModelName,
|
Model: serverSnapshotModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -135,6 +135,13 @@ func (ss ServerSnapshot) CreatedAt() time.Time {
|
||||||
return ss.createdAt
|
return ss.createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss ServerSnapshot) WithRelations(server ServerMeta) ServerSnapshotWithRelations {
|
||||||
|
return ServerSnapshotWithRelations{
|
||||||
|
snapshot: ss,
|
||||||
|
server: server,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ss ServerSnapshot) ToCursor() (ServerSnapshotCursor, error) {
|
func (ss ServerSnapshot) ToCursor() (ServerSnapshotCursor, error) {
|
||||||
return NewServerSnapshotCursor(ss.id, ss.serverKey, ss.date)
|
return NewServerSnapshotCursor(ss.id, ss.serverKey, ss.date)
|
||||||
}
|
}
|
||||||
|
@ -145,6 +152,25 @@ func (ss ServerSnapshot) IsZero() bool {
|
||||||
|
|
||||||
type ServerSnapshots []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 {
|
type CreateServerSnapshotParams struct {
|
||||||
serverKey string
|
serverKey string
|
||||||
numPlayers int
|
numPlayers int
|
||||||
|
@ -176,7 +202,7 @@ func NewCreateServerSnapshotParams(server Server, date time.Time) (CreateServerS
|
||||||
numInactivePlayers: server.NumInactivePlayers(),
|
numInactivePlayers: server.NumInactivePlayers(),
|
||||||
numTribes: server.NumTribes(),
|
numTribes: server.NumTribes(),
|
||||||
numActiveTribes: server.NumActiveTribes(),
|
numActiveTribes: server.NumActiveTribes(),
|
||||||
numInactiveTribes: server.NumInactivePlayers(),
|
numInactiveTribes: server.NumInactiveTribes(),
|
||||||
numVillages: server.NumVillages(),
|
numVillages: server.NumVillages(),
|
||||||
numPlayerVillages: server.NumPlayerVillages(),
|
numPlayerVillages: server.NumPlayerVillages(),
|
||||||
numBarbarianVillages: server.NumBarbarianVillages(),
|
numBarbarianVillages: server.NumBarbarianVillages(),
|
||||||
|
@ -279,7 +305,7 @@ type ServerSnapshotCursor struct {
|
||||||
const serverSnapshotCursorModelName = "ServerSnapshotCursor"
|
const serverSnapshotCursorModelName = "ServerSnapshotCursor"
|
||||||
|
|
||||||
func NewServerSnapshotCursor(id int, serverKey string, date time.Time) (ServerSnapshotCursor, error) {
|
func NewServerSnapshotCursor(id int, serverKey string, date time.Time) (ServerSnapshotCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return ServerSnapshotCursor{}, ValidationError{
|
return ServerSnapshotCursor{}, ValidationError{
|
||||||
Model: serverSnapshotCursorModelName,
|
Model: serverSnapshotCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -510,7 +536,7 @@ func (params *ListServerSnapshotsParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListServerSnapshotsParams) SetLimit(limit int) error {
|
func (params *ListServerSnapshotsParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, ServerSnapshotListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, ServerSnapshotListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listServerSnapshotsParamsModelName,
|
Model: listServerSnapshotsParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
@ -576,3 +602,57 @@ func (res ListServerSnapshotsResult) Self() ServerSnapshotCursor {
|
||||||
func (res ListServerSnapshotsResult) Next() ServerSnapshotCursor {
|
func (res ListServerSnapshotsResult) Next() ServerSnapshotCursor {
|
||||||
return res.next
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ func TestNewServerSnapshotCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ServerSnapshotCursor",
|
Model: "ServerSnapshotCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -769,7 +769,7 @@ func TestListServerSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListServerSnapshotsParams",
|
Model: "ListServerSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -783,7 +783,7 @@ func TestListServerSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListServerSnapshotsParams",
|
Model: "ListServerSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.ServerSnapshotListMaxLimit,
|
Max: domain.ServerSnapshotListMaxLimit,
|
||||||
Current: domain.ServerSnapshotListMaxLimit + 1,
|
Current: domain.ServerSnapshotListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
@ -852,3 +852,50 @@ func TestNewListServerSnapshotsResult(t *testing.T) {
|
||||||
assert.True(t, res.Next().IsZero())
|
assert.True(t, res.Next().IsZero())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewListServerSnapshotsWithRelationsResult(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
snapshots := domain.ServerSnapshotsWithRelations{
|
||||||
|
domaintest.NewServerSnapshotWithRelations(t),
|
||||||
|
domaintest.NewServerSnapshotWithRelations(t),
|
||||||
|
domaintest.NewServerSnapshotWithRelations(t),
|
||||||
|
}
|
||||||
|
next := domaintest.NewServerSnapshotWithRelations(t)
|
||||||
|
|
||||||
|
t.Run("OK: with next", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListServerSnapshotsWithRelationsResult(snapshots, next)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, snapshots, res.ServerSnapshots())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().ID(), res.Self().ID())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().ServerKey(), res.Self().ServerKey())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().Date(), res.Self().Date())
|
||||||
|
assert.Equal(t, next.ServerSnapshot().ID(), res.Next().ID())
|
||||||
|
assert.Equal(t, next.ServerSnapshot().ServerKey(), res.Next().ServerKey())
|
||||||
|
assert.Equal(t, next.ServerSnapshot().Date(), res.Next().Date())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: without next", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListServerSnapshotsWithRelationsResult(snapshots, domain.ServerSnapshotWithRelations{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, snapshots, res.ServerSnapshots())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().ID(), res.Self().ID())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().ServerKey(), res.Self().ServerKey())
|
||||||
|
assert.Equal(t, snapshots[0].ServerSnapshot().Date(), res.Self().Date())
|
||||||
|
assert.True(t, res.Next().IsZero())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: 0 snapshots", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListServerSnapshotsWithRelationsResult(nil, domain.ServerSnapshotWithRelations{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Zero(t, res.ServerSnapshots())
|
||||||
|
assert.True(t, res.Self().IsZero())
|
||||||
|
assert.True(t, res.Next().IsZero())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ func TestUpdateServerParams_SetNumTribes(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numTribes",
|
Field: "numTribes",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -264,7 +264,7 @@ func TestUpdateServerParams_SetNumActiveTribes(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numActiveTribes",
|
Field: "numActiveTribes",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -327,7 +327,7 @@ func TestUpdateServerParams_SetNumInactiveTribes(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numInactiveTribes",
|
Field: "numInactiveTribes",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -390,7 +390,7 @@ func TestUpdateServerParams_SetNumPlayers(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numPlayers",
|
Field: "numPlayers",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -453,7 +453,7 @@ func TestUpdateServerParams_SetNumActivePlayers(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numActivePlayers",
|
Field: "numActivePlayers",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -516,7 +516,7 @@ func TestUpdateServerParams_SetNumInactivePlayers(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numInactivePlayers",
|
Field: "numInactivePlayers",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -579,7 +579,7 @@ func TestUpdateServerParams_SetNumVillages(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numVillages",
|
Field: "numVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -642,7 +642,7 @@ func TestUpdateServerParams_SetNumPlayerVillages(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numPlayerVillages",
|
Field: "numPlayerVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -705,7 +705,7 @@ func TestUpdateServerParams_SetNumBarbarianVillages(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numBarbarianVillages",
|
Field: "numBarbarianVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -768,7 +768,7 @@ func TestUpdateServerParams_SetNumBonusVillages(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "UpdateServerParams",
|
Model: "UpdateServerParams",
|
||||||
Field: "numBonusVillages",
|
Field: "numBonusVillages",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -1207,7 +1207,7 @@ func TestListServersParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListServersParams",
|
Model: "ListServersParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1221,7 +1221,7 @@ func TestListServersParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListServersParams",
|
Model: "ListServersParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.ServerListMaxLimit,
|
Max: domain.ServerListMaxLimit,
|
||||||
Current: domain.ServerListMaxLimit + 1,
|
Current: domain.ServerListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -67,7 +67,7 @@ func UnmarshalTribeFromDatabase(
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
deletedAt time.Time,
|
deletedAt time.Time,
|
||||||
) (Tribe, error) {
|
) (Tribe, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return Tribe{}, ValidationError{
|
return Tribe{}, ValidationError{
|
||||||
Model: tribeModelName,
|
Model: tribeModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -207,6 +207,7 @@ func (t Tribe) ToCursor() (TribeCursor, error) {
|
||||||
t.od.scoreDef,
|
t.od.scoreDef,
|
||||||
t.od.scoreTotal,
|
t.od.scoreTotal,
|
||||||
t.points,
|
t.points,
|
||||||
|
t.mostPoints,
|
||||||
t.dominance,
|
t.dominance,
|
||||||
t.deletedAt,
|
t.deletedAt,
|
||||||
)
|
)
|
||||||
|
@ -295,7 +296,7 @@ const tribeMetaModelName = "TribeMeta"
|
||||||
// It should be used only for unmarshalling from the database!
|
// It should be used only for unmarshalling from the database!
|
||||||
// You can't use UnmarshalTribeMetaFromDatabase as constructor - It may put domain into the invalid state!
|
// You can't use UnmarshalTribeMetaFromDatabase as constructor - It may put domain into the invalid state!
|
||||||
func UnmarshalTribeMetaFromDatabase(id int, name string, tag string, rawProfileURL string) (TribeMeta, error) {
|
func UnmarshalTribeMetaFromDatabase(id int, name string, tag string, rawProfileURL string) (TribeMeta, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeMeta{}, ValidationError{
|
return TribeMeta{}, ValidationError{
|
||||||
Model: tribeMetaModelName,
|
Model: tribeMetaModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -472,6 +473,8 @@ const (
|
||||||
TribeSortODScoreTotalDESC
|
TribeSortODScoreTotalDESC
|
||||||
TribeSortPointsASC
|
TribeSortPointsASC
|
||||||
TribeSortPointsDESC
|
TribeSortPointsDESC
|
||||||
|
TribeSortMostPointsASC
|
||||||
|
TribeSortMostPointsDESC
|
||||||
TribeSortDominanceASC
|
TribeSortDominanceASC
|
||||||
TribeSortDominanceDESC
|
TribeSortDominanceDESC
|
||||||
TribeSortDeletedAtASC
|
TribeSortDeletedAtASC
|
||||||
|
@ -510,6 +513,10 @@ func (s TribeSort) String() string {
|
||||||
return "points:ASC"
|
return "points:ASC"
|
||||||
case TribeSortPointsDESC:
|
case TribeSortPointsDESC:
|
||||||
return "points:DESC"
|
return "points:DESC"
|
||||||
|
case TribeSortMostPointsASC:
|
||||||
|
return "mostPoints:ASC"
|
||||||
|
case TribeSortMostPointsDESC:
|
||||||
|
return "mostPoints:DESC"
|
||||||
case TribeSortDominanceASC:
|
case TribeSortDominanceASC:
|
||||||
return "dominance:ASC"
|
return "dominance:ASC"
|
||||||
case TribeSortDominanceDESC:
|
case TribeSortDominanceDESC:
|
||||||
|
@ -530,6 +537,7 @@ type TribeCursor struct {
|
||||||
odScoreDef int
|
odScoreDef int
|
||||||
odScoreTotal int
|
odScoreTotal int
|
||||||
points int
|
points int
|
||||||
|
mostPoints int
|
||||||
dominance float64
|
dominance float64
|
||||||
deletedAt time.Time
|
deletedAt time.Time
|
||||||
}
|
}
|
||||||
|
@ -543,10 +551,11 @@ func NewTribeCursor(
|
||||||
odScoreDef int,
|
odScoreDef int,
|
||||||
odScoreTotal int,
|
odScoreTotal int,
|
||||||
points int,
|
points int,
|
||||||
|
mostPoints int,
|
||||||
dominance float64,
|
dominance float64,
|
||||||
deletedAt time.Time,
|
deletedAt time.Time,
|
||||||
) (TribeCursor, error) {
|
) (TribeCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeCursor{}, ValidationError{
|
return TribeCursor{}, ValidationError{
|
||||||
Model: tribeCursorModelName,
|
Model: tribeCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -562,7 +571,7 @@ func NewTribeCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreAtt, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreAtt, 0, math.MaxInt); err != nil {
|
||||||
return TribeCursor{}, ValidationError{
|
return TribeCursor{}, ValidationError{
|
||||||
Model: tribeCursorModelName,
|
Model: tribeCursorModelName,
|
||||||
Field: "odScoreAtt",
|
Field: "odScoreAtt",
|
||||||
|
@ -570,7 +579,7 @@ func NewTribeCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreDef, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreDef, 0, math.MaxInt); err != nil {
|
||||||
return TribeCursor{}, ValidationError{
|
return TribeCursor{}, ValidationError{
|
||||||
Model: tribeCursorModelName,
|
Model: tribeCursorModelName,
|
||||||
Field: "odScoreDef",
|
Field: "odScoreDef",
|
||||||
|
@ -578,7 +587,7 @@ func NewTribeCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(odScoreTotal, 0, math.MaxInt); err != nil {
|
if err := validateInRange(odScoreTotal, 0, math.MaxInt); err != nil {
|
||||||
return TribeCursor{}, ValidationError{
|
return TribeCursor{}, ValidationError{
|
||||||
Model: tribeCursorModelName,
|
Model: tribeCursorModelName,
|
||||||
Field: "odScoreTotal",
|
Field: "odScoreTotal",
|
||||||
|
@ -586,7 +595,7 @@ func NewTribeCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(points, 0, math.MaxInt); err != nil {
|
if err := validateInRange(points, 0, math.MaxInt); err != nil {
|
||||||
return TribeCursor{}, ValidationError{
|
return TribeCursor{}, ValidationError{
|
||||||
Model: tribeCursorModelName,
|
Model: tribeCursorModelName,
|
||||||
Field: "points",
|
Field: "points",
|
||||||
|
@ -594,6 +603,14 @@ func NewTribeCursor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateInRange(mostPoints, 0, math.MaxInt); err != nil {
|
||||||
|
return TribeCursor{}, ValidationError{
|
||||||
|
Model: tribeCursorModelName,
|
||||||
|
Field: "mostPoints",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TribeCursor{
|
return TribeCursor{
|
||||||
id: id,
|
id: id,
|
||||||
serverKey: serverKey,
|
serverKey: serverKey,
|
||||||
|
@ -601,6 +618,7 @@ func NewTribeCursor(
|
||||||
odScoreDef: odScoreDef,
|
odScoreDef: odScoreDef,
|
||||||
odScoreTotal: odScoreTotal,
|
odScoreTotal: odScoreTotal,
|
||||||
points: points,
|
points: points,
|
||||||
|
mostPoints: mostPoints,
|
||||||
dominance: dominance,
|
dominance: dominance,
|
||||||
deletedAt: deletedAt,
|
deletedAt: deletedAt,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -643,6 +661,11 @@ func decodeTribeCursor(encoded string) (TribeCursor, error) {
|
||||||
return TribeCursor{}, ErrInvalidCursor
|
return TribeCursor{}, ErrInvalidCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mostPoints, err := m.int("mostPoints")
|
||||||
|
if err != nil {
|
||||||
|
return TribeCursor{}, ErrInvalidCursor
|
||||||
|
}
|
||||||
|
|
||||||
dominance, err := m.float64("dominance")
|
dominance, err := m.float64("dominance")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return TribeCursor{}, ErrInvalidCursor
|
return TribeCursor{}, ErrInvalidCursor
|
||||||
|
@ -660,6 +683,7 @@ func decodeTribeCursor(encoded string) (TribeCursor, error) {
|
||||||
odScoreDef,
|
odScoreDef,
|
||||||
odScoreTotal,
|
odScoreTotal,
|
||||||
points,
|
points,
|
||||||
|
mostPoints,
|
||||||
dominance,
|
dominance,
|
||||||
deletedAt,
|
deletedAt,
|
||||||
)
|
)
|
||||||
|
@ -694,6 +718,10 @@ func (tc TribeCursor) Points() int {
|
||||||
return tc.points
|
return tc.points
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc TribeCursor) MostPoints() int {
|
||||||
|
return tc.mostPoints
|
||||||
|
}
|
||||||
|
|
||||||
func (tc TribeCursor) Dominance() float64 {
|
func (tc TribeCursor) Dominance() float64 {
|
||||||
return tc.dominance
|
return tc.dominance
|
||||||
}
|
}
|
||||||
|
@ -718,6 +746,7 @@ func (tc TribeCursor) Encode() string {
|
||||||
{"odScoreDef", tc.odScoreDef},
|
{"odScoreDef", tc.odScoreDef},
|
||||||
{"odScoreTotal", tc.odScoreTotal},
|
{"odScoreTotal", tc.odScoreTotal},
|
||||||
{"points", tc.points},
|
{"points", tc.points},
|
||||||
|
{"mostPoints", tc.mostPoints},
|
||||||
{"dominance", tc.dominance},
|
{"dominance", tc.dominance},
|
||||||
{"deletedAt", tc.deletedAt},
|
{"deletedAt", tc.deletedAt},
|
||||||
})
|
})
|
||||||
|
@ -754,7 +783,7 @@ func (params *ListTribesParams) IDs() []int {
|
||||||
|
|
||||||
func (params *ListTribesParams) SetIDs(ids []int) error {
|
func (params *ListTribesParams) SetIDs(ids []int) error {
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listTribesParamsModelName,
|
Model: listTribesParamsModelName,
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
|
@ -905,7 +934,7 @@ func (params *ListTribesParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListTribesParams) SetLimit(limit int) error {
|
func (params *ListTribesParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, TribeListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, TribeListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listTribesParamsModelName,
|
Model: listTribesParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -31,7 +31,7 @@ func UnmarshalTribeChangeFromDatabase(
|
||||||
newTribeID int,
|
newTribeID int,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (TribeChange, error) {
|
) (TribeChange, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeChange{}, ValidationError{
|
return TribeChange{}, ValidationError{
|
||||||
Model: tribeChangeModelName,
|
Model: tribeChangeModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -156,7 +156,7 @@ func NewCreateTribeChangeParams(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(playerID, 1, math.MaxInt); err != nil {
|
if err := validateInRange(playerID, 1, math.MaxInt); err != nil {
|
||||||
return CreateTribeChangeParams{}, ValidationError{
|
return CreateTribeChangeParams{}, ValidationError{
|
||||||
Model: createTribeChangeParamsModelName,
|
Model: createTribeChangeParamsModelName,
|
||||||
Field: "playerID",
|
Field: "playerID",
|
||||||
|
@ -164,7 +164,7 @@ func NewCreateTribeChangeParams(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(oldTribeID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(oldTribeID, 0, math.MaxInt); err != nil {
|
||||||
return CreateTribeChangeParams{}, ValidationError{
|
return CreateTribeChangeParams{}, ValidationError{
|
||||||
Model: createTribeChangeParamsModelName,
|
Model: createTribeChangeParamsModelName,
|
||||||
Field: "oldTribeID",
|
Field: "oldTribeID",
|
||||||
|
@ -172,7 +172,7 @@ func NewCreateTribeChangeParams(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(newTribeID, 0, math.MaxInt); err != nil {
|
if err := validateInRange(newTribeID, 0, math.MaxInt); err != nil {
|
||||||
return CreateTribeChangeParams{}, ValidationError{
|
return CreateTribeChangeParams{}, ValidationError{
|
||||||
Model: createTribeChangeParamsModelName,
|
Model: createTribeChangeParamsModelName,
|
||||||
Field: "newTribeID",
|
Field: "newTribeID",
|
||||||
|
@ -297,7 +297,7 @@ type TribeChangeCursor struct {
|
||||||
const tribeChangeCursorModelName = "TribeChangeCursor"
|
const tribeChangeCursorModelName = "TribeChangeCursor"
|
||||||
|
|
||||||
func NewTribeChangeCursor(id int, serverKey string, createdAt time.Time) (TribeChangeCursor, error) {
|
func NewTribeChangeCursor(id int, serverKey string, createdAt time.Time) (TribeChangeCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeChangeCursor{}, ValidationError{
|
return TribeChangeCursor{}, ValidationError{
|
||||||
Model: tribeChangeCursorModelName,
|
Model: tribeChangeCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -436,7 +436,7 @@ func (params *ListTribeChangesParams) PlayerIDs() []int {
|
||||||
|
|
||||||
func (params *ListTribeChangesParams) SetPlayerIDs(playerIDs []int) error {
|
func (params *ListTribeChangesParams) SetPlayerIDs(playerIDs []int) error {
|
||||||
for i, id := range playerIDs {
|
for i, id := range playerIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listTribeChangesParamsModelName,
|
Model: listTribeChangesParamsModelName,
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
|
@ -457,7 +457,7 @@ func (params *ListTribeChangesParams) TribeIDs() []int {
|
||||||
|
|
||||||
func (params *ListTribeChangesParams) SetTribeIDs(tribeIDs []int) error {
|
func (params *ListTribeChangesParams) SetTribeIDs(tribeIDs []int) error {
|
||||||
for i, id := range tribeIDs {
|
for i, id := range tribeIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listTribeChangesParamsModelName,
|
Model: listTribeChangesParamsModelName,
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
|
@ -542,7 +542,7 @@ func (params *ListTribeChangesParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListTribeChangesParams) SetLimit(limit int) error {
|
func (params *ListTribeChangesParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, TribeChangeListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, TribeChangeListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listTribeChangesParamsModelName,
|
Model: listTribeChangesParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -53,7 +53,7 @@ func TestNewCreateTribeChangeParams(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "CreateTribeChangeParams",
|
Model: "CreateTribeChangeParams",
|
||||||
Field: "playerID",
|
Field: "playerID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -70,7 +70,7 @@ func TestNewCreateTribeChangeParams(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "CreateTribeChangeParams",
|
Model: "CreateTribeChangeParams",
|
||||||
Field: "oldTribeID",
|
Field: "oldTribeID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -87,7 +87,7 @@ func TestNewCreateTribeChangeParams(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "CreateTribeChangeParams",
|
Model: "CreateTribeChangeParams",
|
||||||
Field: "newTribeID",
|
Field: "newTribeID",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -318,7 +318,7 @@ func TestNewTribeChangeCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeChangeCursor",
|
Model: "TribeChangeCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -453,7 +453,7 @@ func TestListTribeChangesParams_SetPlayerIDs(t *testing.T) {
|
||||||
Model: "ListTribeChangesParams",
|
Model: "ListTribeChangesParams",
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -513,7 +513,7 @@ func TestListTribeChangesParams_SetTribeIDs(t *testing.T) {
|
||||||
Model: "ListTribeChangesParams",
|
Model: "ListTribeChangesParams",
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1071,7 +1071,7 @@ func TestListTribeChangesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribeChangesParams",
|
Model: "ListTribeChangesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1085,7 +1085,7 @@ func TestListTribeChangesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribeChangesParams",
|
Model: "ListTribeChangesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeChangeListMaxLimit,
|
Max: domain.TribeChangeListMaxLimit,
|
||||||
Current: domain.TribeChangeListMaxLimit + 1,
|
Current: domain.TribeChangeListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,7 +43,7 @@ func UnmarshalTribeSnapshotFromDatabase(
|
||||||
date time.Time,
|
date time.Time,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (TribeSnapshot, error) {
|
) (TribeSnapshot, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeSnapshot{}, ValidationError{
|
return TribeSnapshot{}, ValidationError{
|
||||||
Model: tribeSnapshotModelName,
|
Model: tribeSnapshotModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -51,7 +51,7 @@ func UnmarshalTribeSnapshotFromDatabase(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateIntInRange(tribeID, 1, math.MaxInt); err != nil {
|
if err := validateInRange(tribeID, 1, math.MaxInt); err != nil {
|
||||||
return TribeSnapshot{}, ValidationError{
|
return TribeSnapshot{}, ValidationError{
|
||||||
Model: tribeSnapshotModelName,
|
Model: tribeSnapshotModelName,
|
||||||
Field: "tribeID",
|
Field: "tribeID",
|
||||||
|
@ -295,7 +295,7 @@ type TribeSnapshotCursor struct {
|
||||||
const tribeSnapshotCursorModelName = "TribeSnapshotCursor"
|
const tribeSnapshotCursorModelName = "TribeSnapshotCursor"
|
||||||
|
|
||||||
func NewTribeSnapshotCursor(id int, serverKey string, date time.Time) (TribeSnapshotCursor, error) {
|
func NewTribeSnapshotCursor(id int, serverKey string, date time.Time) (TribeSnapshotCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return TribeSnapshotCursor{}, ValidationError{
|
return TribeSnapshotCursor{}, ValidationError{
|
||||||
Model: tribeSnapshotCursorModelName,
|
Model: tribeSnapshotCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -430,7 +430,7 @@ func (params *ListTribeSnapshotsParams) TribeIDs() []int {
|
||||||
|
|
||||||
func (params *ListTribeSnapshotsParams) SetTribeIDs(tribeIDs []int) error {
|
func (params *ListTribeSnapshotsParams) SetTribeIDs(tribeIDs []int) error {
|
||||||
for i, id := range tribeIDs {
|
for i, id := range tribeIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listTribeSnapshotsParamsModelName,
|
Model: listTribeSnapshotsParamsModelName,
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
|
@ -548,7 +548,7 @@ func (params *ListTribeSnapshotsParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListTribeSnapshotsParams) SetLimit(limit int) error {
|
func (params *ListTribeSnapshotsParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, TribeSnapshotListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, TribeSnapshotListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listTribeSnapshotsParamsModelName,
|
Model: listTribeSnapshotsParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -149,7 +149,7 @@ func TestNewTribeSnapshotCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeSnapshotCursor",
|
Model: "TribeSnapshotCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -284,7 +284,7 @@ func TestListTribeSnapshotsParams_SetTribeIDs(t *testing.T) {
|
||||||
Model: "ListTribeSnapshotsParams",
|
Model: "ListTribeSnapshotsParams",
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -842,7 +842,7 @@ func TestListTribeSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribeSnapshotsParams",
|
Model: "ListTribeSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -856,7 +856,7 @@ func TestListTribeSnapshotsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribeSnapshotsParams",
|
Model: "ListTribeSnapshotsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeSnapshotListMaxLimit,
|
Max: domain.TribeSnapshotListMaxLimit,
|
||||||
Current: domain.TribeSnapshotListMaxLimit + 1,
|
Current: domain.TribeSnapshotListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -255,6 +255,13 @@ func TestTribeSort_IsInConflict(t *testing.T) {
|
||||||
},
|
},
|
||||||
expectedRes: true,
|
expectedRes: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: mostPoints:ASC mostPoints:DESC",
|
||||||
|
args: args{
|
||||||
|
sorts: [2]domain.TribeSort{domain.TribeSortMostPointsASC, domain.TribeSortMostPointsDESC},
|
||||||
|
},
|
||||||
|
expectedRes: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: dominance:ASC dominance:DESC",
|
name: "OK: dominance:ASC dominance:DESC",
|
||||||
args: args{
|
args: args{
|
||||||
|
@ -292,6 +299,7 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef int
|
odScoreDef int
|
||||||
odScoreTotal int
|
odScoreTotal int
|
||||||
points int
|
points int
|
||||||
|
mostPoints int
|
||||||
dominance float64
|
dominance float64
|
||||||
deletedAt time.Time
|
deletedAt time.Time
|
||||||
}
|
}
|
||||||
|
@ -312,6 +320,7 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
|
@ -326,13 +335,14 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeCursor",
|
Model: "TribeCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -347,13 +357,14 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeCursor",
|
Model: "TribeCursor",
|
||||||
Field: "odScoreAtt",
|
Field: "odScoreAtt",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -368,13 +379,14 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: -1,
|
odScoreDef: -1,
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeCursor",
|
Model: "TribeCursor",
|
||||||
Field: "odScoreDef",
|
Field: "odScoreDef",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -389,13 +401,14 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: -1,
|
odScoreTotal: -1,
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeCursor",
|
Model: "TribeCursor",
|
||||||
Field: "odScoreTotal",
|
Field: "odScoreTotal",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -410,13 +423,36 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: -1,
|
points: -1,
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "TribeCursor",
|
Model: "TribeCursor",
|
||||||
Field: "points",
|
Field: "points",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
|
Min: 0,
|
||||||
|
Current: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: points < 0",
|
||||||
|
args: args{
|
||||||
|
id: validTribeCursor.ID(),
|
||||||
|
serverKey: validTribeCursor.ServerKey(),
|
||||||
|
odScoreAtt: validTribeCursor.ODScoreAtt(),
|
||||||
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: -1,
|
||||||
|
dominance: validTribeCursor.Dominance(),
|
||||||
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "TribeCursor",
|
||||||
|
Field: "mostPoints",
|
||||||
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 0,
|
Min: 0,
|
||||||
Current: -1,
|
Current: -1,
|
||||||
},
|
},
|
||||||
|
@ -434,6 +470,7 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
odScoreDef: validTribeCursor.ODScoreDef(),
|
odScoreDef: validTribeCursor.ODScoreDef(),
|
||||||
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
odScoreTotal: validTribeCursor.ODScoreTotal(),
|
||||||
points: validTribeCursor.Points(),
|
points: validTribeCursor.Points(),
|
||||||
|
mostPoints: validTribeCursor.MostPoints(),
|
||||||
dominance: validTribeCursor.Dominance(),
|
dominance: validTribeCursor.Dominance(),
|
||||||
deletedAt: validTribeCursor.DeletedAt(),
|
deletedAt: validTribeCursor.DeletedAt(),
|
||||||
},
|
},
|
||||||
|
@ -456,6 +493,7 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
tt.args.odScoreDef,
|
tt.args.odScoreDef,
|
||||||
tt.args.odScoreTotal,
|
tt.args.odScoreTotal,
|
||||||
tt.args.points,
|
tt.args.points,
|
||||||
|
tt.args.mostPoints,
|
||||||
tt.args.dominance,
|
tt.args.dominance,
|
||||||
tt.args.deletedAt,
|
tt.args.deletedAt,
|
||||||
)
|
)
|
||||||
|
@ -469,6 +507,7 @@ func TestNewTribeCursor(t *testing.T) {
|
||||||
assert.Equal(t, tt.args.odScoreDef, tc.ODScoreDef())
|
assert.Equal(t, tt.args.odScoreDef, tc.ODScoreDef())
|
||||||
assert.Equal(t, tt.args.odScoreTotal, tc.ODScoreTotal())
|
assert.Equal(t, tt.args.odScoreTotal, tc.ODScoreTotal())
|
||||||
assert.Equal(t, tt.args.points, tc.Points())
|
assert.Equal(t, tt.args.points, tc.Points())
|
||||||
|
assert.Equal(t, tt.args.mostPoints, tc.MostPoints())
|
||||||
assert.InDelta(t, tt.args.dominance, tc.Dominance(), 0.001)
|
assert.InDelta(t, tt.args.dominance, tc.Dominance(), 0.001)
|
||||||
assert.Equal(t, tt.args.deletedAt, tc.DeletedAt())
|
assert.Equal(t, tt.args.deletedAt, tc.DeletedAt())
|
||||||
assert.NotEmpty(t, tc.Encode())
|
assert.NotEmpty(t, tc.Encode())
|
||||||
|
@ -513,7 +552,7 @@ func TestListTribesParams_SetIDs(t *testing.T) {
|
||||||
Model: "ListTribesParams",
|
Model: "ListTribesParams",
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1125,7 +1164,7 @@ func TestListTribesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribesParams",
|
Model: "ListTribesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -1139,7 +1178,7 @@ func TestListTribesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListTribesParams",
|
Model: "ListTribesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeListMaxLimit,
|
Max: domain.TribeListMaxLimit,
|
||||||
Current: domain.TribeListMaxLimit + 1,
|
Current: domain.TribeListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -122,56 +122,56 @@ func (e SliceElementValidationError) Unwrap() error {
|
||||||
return e.Err
|
return e.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
type MinGreaterEqualError struct {
|
type MinGreaterEqualError[T float32 | float64 | int] struct {
|
||||||
Min int
|
Min T
|
||||||
Current int
|
Current T
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ErrorWithParams = MinGreaterEqualError{}
|
var _ ErrorWithParams = MinGreaterEqualError[int]{}
|
||||||
|
|
||||||
func (e MinGreaterEqualError) Error() string {
|
func (e MinGreaterEqualError[T]) Error() string {
|
||||||
return fmt.Sprintf("must be no less than %d (current: %d)", e.Min, e.Current)
|
return fmt.Sprintf("must be no less than %v (current: %v)", e.Min, e.Current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MinGreaterEqualError) Type() ErrorType {
|
func (e MinGreaterEqualError[T]) Type() ErrorType {
|
||||||
return ErrorTypeIncorrectInput
|
return ErrorTypeIncorrectInput
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorCodeMinGreaterEqual = "min-greater-equal"
|
const errorCodeMinGreaterEqual = "min-greater-equal"
|
||||||
|
|
||||||
func (e MinGreaterEqualError) Code() string {
|
func (e MinGreaterEqualError[T]) Code() string {
|
||||||
return errorCodeMinGreaterEqual
|
return errorCodeMinGreaterEqual
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MinGreaterEqualError) Params() map[string]any {
|
func (e MinGreaterEqualError[T]) Params() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"Min": e.Min,
|
"Min": e.Min,
|
||||||
"Current": e.Current,
|
"Current": e.Current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MaxLessEqualError struct {
|
type MaxLessEqualError[T float32 | float64 | int] struct {
|
||||||
Max int
|
Max T
|
||||||
Current int
|
Current T
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ErrorWithParams = MaxLessEqualError{}
|
var _ ErrorWithParams = MaxLessEqualError[int]{}
|
||||||
|
|
||||||
func (e MaxLessEqualError) Error() string {
|
func (e MaxLessEqualError[T]) Error() string {
|
||||||
return fmt.Sprintf("must be no greater than %d (current: %d)", e.Max, e.Current)
|
return fmt.Sprintf("must be no greater than %v (current: %v)", e.Max, e.Current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MaxLessEqualError) Type() ErrorType {
|
func (e MaxLessEqualError[T]) Type() ErrorType {
|
||||||
return ErrorTypeIncorrectInput
|
return ErrorTypeIncorrectInput
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorCodeMaxLessEqual = "max-less-equal"
|
const errorCodeMaxLessEqual = "max-less-equal"
|
||||||
|
|
||||||
func (e MaxLessEqualError) Code() string {
|
func (e MaxLessEqualError[T]) Code() string {
|
||||||
return errorCodeMaxLessEqual
|
return errorCodeMaxLessEqual
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MaxLessEqualError) Params() map[string]any {
|
func (e MaxLessEqualError[T]) Params() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"Max": e.Max,
|
"Max": e.Max,
|
||||||
"Current": e.Current,
|
"Current": e.Current,
|
||||||
|
@ -356,16 +356,16 @@ func validateServerKey(key string) error {
|
||||||
return validateStringLen(key, serverKeyMinLength, serverKeyMaxLength)
|
return validateStringLen(key, serverKeyMinLength, serverKeyMaxLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateIntInRange(current, min, max int) error {
|
func validateInRange[T float32 | float64 | int](current, min, max T) error {
|
||||||
if current < min {
|
if current < min {
|
||||||
return MinGreaterEqualError{
|
return MinGreaterEqualError[T]{
|
||||||
Min: min,
|
Min: min,
|
||||||
Current: current,
|
Current: current,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if current > max {
|
if current > max {
|
||||||
return MaxLessEqualError{
|
return MaxLessEqualError[T]{
|
||||||
Max: max,
|
Max: max,
|
||||||
Current: current,
|
Current: current,
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ func (params *ListVersionsParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListVersionsParams) SetLimit(limit int) error {
|
func (params *ListVersionsParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, VersionListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, VersionListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listVersionsParamsModelName,
|
Model: listVersionsParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -324,7 +324,7 @@ func TestListVersionsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListVersionsParams",
|
Model: "ListVersionsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -338,7 +338,7 @@ func TestListVersionsParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListVersionsParams",
|
Model: "ListVersionsParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VersionListMaxLimit,
|
Max: domain.VersionListMaxLimit,
|
||||||
Current: domain.VersionListMaxLimit + 1,
|
Current: domain.VersionListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,7 @@ func UnmarshalVillageFromDatabase(
|
||||||
rawProfileURL string,
|
rawProfileURL string,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
) (Village, error) {
|
) (Village, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return Village{}, ValidationError{
|
return Village{}, ValidationError{
|
||||||
Model: villageModelName,
|
Model: villageModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -263,7 +263,7 @@ func UnmarshalVillageMetaFromDatabase(
|
||||||
continent string,
|
continent string,
|
||||||
rawProfileURL string,
|
rawProfileURL string,
|
||||||
) (VillageMeta, error) {
|
) (VillageMeta, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return VillageMeta{}, ValidationError{
|
return VillageMeta{}, ValidationError{
|
||||||
Model: villageMetaModelName,
|
Model: villageMetaModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -423,7 +423,7 @@ type VillageCursor struct {
|
||||||
const villageCursorModelName = "VillageCursor"
|
const villageCursorModelName = "VillageCursor"
|
||||||
|
|
||||||
func NewVillageCursor(id int, serverKey string) (VillageCursor, error) {
|
func NewVillageCursor(id int, serverKey string) (VillageCursor, error) {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return VillageCursor{}, ValidationError{
|
return VillageCursor{}, ValidationError{
|
||||||
Model: villageCursorModelName,
|
Model: villageCursorModelName,
|
||||||
Field: "id",
|
Field: "id",
|
||||||
|
@ -528,7 +528,7 @@ func (params *ListVillagesParams) IDs() []int {
|
||||||
|
|
||||||
func (params *ListVillagesParams) SetIDs(ids []int) error {
|
func (params *ListVillagesParams) SetIDs(ids []int) error {
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listVillagesParamsModelName,
|
Model: listVillagesParamsModelName,
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
|
@ -623,7 +623,7 @@ func (params *ListVillagesParams) PlayerIDs() []int {
|
||||||
|
|
||||||
func (params *ListVillagesParams) SetPlayerIDs(playerIDs []int) error {
|
func (params *ListVillagesParams) SetPlayerIDs(playerIDs []int) error {
|
||||||
for i, id := range playerIDs {
|
for i, id := range playerIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listVillagesParamsModelName,
|
Model: listVillagesParamsModelName,
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
|
@ -644,7 +644,7 @@ func (params *ListVillagesParams) TribeIDs() []int {
|
||||||
|
|
||||||
func (params *ListVillagesParams) SetTribeIDs(tribeIDs []int) error {
|
func (params *ListVillagesParams) SetTribeIDs(tribeIDs []int) error {
|
||||||
for i, id := range tribeIDs {
|
for i, id := range tribeIDs {
|
||||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
if err := validateInRange(id, 1, math.MaxInt); err != nil {
|
||||||
return SliceElementValidationError{
|
return SliceElementValidationError{
|
||||||
Model: listVillagesParamsModelName,
|
Model: listVillagesParamsModelName,
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
|
@ -711,7 +711,7 @@ func (params *ListVillagesParams) Limit() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *ListVillagesParams) SetLimit(limit int) error {
|
func (params *ListVillagesParams) SetLimit(limit int) error {
|
||||||
if err := validateIntInRange(limit, 1, VillageListMaxLimit); err != nil {
|
if err := validateInRange(limit, 1, VillageListMaxLimit); err != nil {
|
||||||
return ValidationError{
|
return ValidationError{
|
||||||
Model: listVillagesParamsModelName,
|
Model: listVillagesParamsModelName,
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
|
|
|
@ -181,7 +181,7 @@ func TestNewVillageCursor(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "VillageCursor",
|
Model: "VillageCursor",
|
||||||
Field: "id",
|
Field: "id",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -260,7 +260,7 @@ func TestListVillagesParams_SetIDs(t *testing.T) {
|
||||||
Model: "ListVillagesParams",
|
Model: "ListVillagesParams",
|
||||||
Field: "ids",
|
Field: "ids",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -545,7 +545,7 @@ func TestListVillagesParams_SetPlayerIDs(t *testing.T) {
|
||||||
Model: "ListVillagesParams",
|
Model: "ListVillagesParams",
|
||||||
Field: "playerIDs",
|
Field: "playerIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -605,7 +605,7 @@ func TestListVillagesParams_SetTribeIDs(t *testing.T) {
|
||||||
Model: "ListVillagesParams",
|
Model: "ListVillagesParams",
|
||||||
Field: "tribeIDs",
|
Field: "tribeIDs",
|
||||||
Index: 3,
|
Index: 3,
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -814,7 +814,7 @@ func TestListVillagesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListVillagesParams",
|
Model: "ListVillagesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MinGreaterEqualError{
|
Err: domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: 0,
|
Current: 0,
|
||||||
},
|
},
|
||||||
|
@ -828,7 +828,7 @@ func TestListVillagesParams_SetLimit(t *testing.T) {
|
||||||
expectedErr: domain.ValidationError{
|
expectedErr: domain.ValidationError{
|
||||||
Model: "ListVillagesParams",
|
Model: "ListVillagesParams",
|
||||||
Field: "limit",
|
Field: "limit",
|
||||||
Err: domain.MaxLessEqualError{
|
Err: domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VillageListMaxLimit,
|
Max: domain.VillageListMaxLimit,
|
||||||
Current: domain.VillageListMaxLimit + 1,
|
Current: domain.VillageListMaxLimit + 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,6 +20,7 @@ type apiHTTPHandler struct {
|
||||||
villageSvc *app.VillageService
|
villageSvc *app.VillageService
|
||||||
ennoblementSvc *app.EnnoblementService
|
ennoblementSvc *app.EnnoblementService
|
||||||
tribeChangeSvc *app.TribeChangeService
|
tribeChangeSvc *app.TribeChangeService
|
||||||
|
serverSnapshotSvc *app.ServerSnapshotService
|
||||||
tribeSnapshotSvc *app.TribeSnapshotService
|
tribeSnapshotSvc *app.TribeSnapshotService
|
||||||
playerSnapshotSvc *app.PlayerSnapshotService
|
playerSnapshotSvc *app.PlayerSnapshotService
|
||||||
errorRenderer apiErrorRenderer
|
errorRenderer apiErrorRenderer
|
||||||
|
@ -40,6 +41,7 @@ func NewAPIHTTPHandler(
|
||||||
villageSvc *app.VillageService,
|
villageSvc *app.VillageService,
|
||||||
ennoblementSvc *app.EnnoblementService,
|
ennoblementSvc *app.EnnoblementService,
|
||||||
tribeChangeSvc *app.TribeChangeService,
|
tribeChangeSvc *app.TribeChangeService,
|
||||||
|
serverSnapshotSvc *app.ServerSnapshotService,
|
||||||
tribeSnapshotSvc *app.TribeSnapshotService,
|
tribeSnapshotSvc *app.TribeSnapshotService,
|
||||||
playerSnapshotSvc *app.PlayerSnapshotService,
|
playerSnapshotSvc *app.PlayerSnapshotService,
|
||||||
opts ...APIHTTPHandlerOption,
|
opts ...APIHTTPHandlerOption,
|
||||||
|
@ -54,6 +56,7 @@ func NewAPIHTTPHandler(
|
||||||
villageSvc: villageSvc,
|
villageSvc: villageSvc,
|
||||||
ennoblementSvc: ennoblementSvc,
|
ennoblementSvc: ennoblementSvc,
|
||||||
tribeChangeSvc: tribeChangeSvc,
|
tribeChangeSvc: tribeChangeSvc,
|
||||||
|
serverSnapshotSvc: serverSnapshotSvc,
|
||||||
tribeSnapshotSvc: tribeSnapshotSvc,
|
tribeSnapshotSvc: tribeSnapshotSvc,
|
||||||
playerSnapshotSvc: playerSnapshotSvc,
|
playerSnapshotSvc: playerSnapshotSvc,
|
||||||
openAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
|
openAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
|
||||||
|
|
|
@ -258,7 +258,7 @@ func TestListEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ func TestListEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.EnnoblementListMaxLimit,
|
Max: domain.EnnoblementListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -866,7 +866,7 @@ func TestListPlayerEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -902,7 +902,7 @@ func TestListPlayerEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.EnnoblementListMaxLimit,
|
Max: domain.EnnoblementListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1532,7 +1532,7 @@ func TestListTribeEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1568,7 +1568,7 @@ func TestListTribeEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.EnnoblementListMaxLimit,
|
Max: domain.EnnoblementListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -2185,7 +2185,7 @@ func TestListVillageEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -2221,7 +2221,7 @@ func TestListVillageEnnoblements(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.EnnoblementListMaxLimit,
|
Max: domain.EnnoblementListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ var apiPlayerSortAllowedValues = []domain.PlayerSort{
|
||||||
domain.PlayerSortODScoreTotalDESC,
|
domain.PlayerSortODScoreTotalDESC,
|
||||||
domain.PlayerSortPointsASC,
|
domain.PlayerSortPointsASC,
|
||||||
domain.PlayerSortPointsDESC,
|
domain.PlayerSortPointsDESC,
|
||||||
|
domain.PlayerSortMostPointsASC,
|
||||||
|
domain.PlayerSortMostPointsDESC,
|
||||||
domain.PlayerSortDeletedAtASC,
|
domain.PlayerSortDeletedAtASC,
|
||||||
domain.PlayerSortDeletedAtDESC,
|
domain.PlayerSortDeletedAtDESC,
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ func TestListPlayerPlayerSnapshots(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ func TestListPlayerPlayerSnapshots(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerSnapshotListMaxLimit,
|
Max: domain.PlayerSnapshotListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,33 @@ func TestListVersionPlayers(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints:DESC]",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("sort", "mostPoints:DESC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListPlayersWithServersResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.PlayerWithServer) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.Server.Key, b.Server.Key),
|
||||||
|
cmp.Compare(a.MostPoints, b.MostPoints)*-1,
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: name",
|
name: "OK: name",
|
||||||
reqModifier: func(t *testing.T, req *http.Request) {
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
@ -343,7 +370,7 @@ func TestListVersionPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -379,7 +406,7 @@ func TestListVersionPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerListMaxLimit,
|
Max: domain.PlayerListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -653,7 +680,7 @@ func TestListVersionPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
id, err := strconv.Atoi(req.URL.Query().Get("id"))
|
id, err := strconv.Atoi(req.URL.Query().Get("id"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: id,
|
Current: id,
|
||||||
}
|
}
|
||||||
|
@ -1023,6 +1050,32 @@ func TestListServerPlayers(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints:DESC]",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("sort", "mostPoints:DESC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListPlayersWithServersResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.PlayerWithServer) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints, b.MostPoints)*-1,
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: name",
|
name: "OK: name",
|
||||||
reqModifier: func(t *testing.T, req *http.Request) {
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
@ -1185,7 +1238,7 @@ func TestListServerPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1274,7 @@ func TestListServerPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerListMaxLimit,
|
Max: domain.PlayerListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1495,7 +1548,7 @@ func TestListServerPlayers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
id, err := strconv.Atoi(req.URL.Query().Get("id"))
|
id, err := strconv.Atoi(req.URL.Query().Get("id"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: id,
|
Current: id,
|
||||||
}
|
}
|
||||||
|
@ -1863,6 +1916,32 @@ func TestListTribeMembers(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints:DESC]",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("sort", "mostPoints:DESC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListPlayersWithServersResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.PlayerWithServer) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints, b.MostPoints)*-1,
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ERR: limit is not an integer",
|
name: "ERR: limit is not an integer",
|
||||||
reqModifier: func(t *testing.T, req *http.Request) {
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
@ -1909,7 +1988,7 @@ func TestListTribeMembers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1945,7 +2024,7 @@ func TestListTribeMembers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.PlayerListMaxLimit,
|
Max: domain.PlayerListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -2339,7 +2418,7 @@ func TestGetPlayer(t *testing.T) {
|
||||||
require.Len(t, pathSegments, 8)
|
require.Len(t, pathSegments, 8)
|
||||||
id, err := strconv.Atoi(pathSegments[7])
|
id, err := strconv.Atoi(pathSegments[7])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: id,
|
Current: id,
|
||||||
}
|
}
|
||||||
|
|
96
internal/port/handler_http_api_server_snapshot.go
Normal file
96
internal/port/handler_http_api_server_snapshot.go
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package port
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/port/internal/apimodel"
|
||||||
|
)
|
||||||
|
|
||||||
|
const apiServerSnapshotSortMaxLength = 1
|
||||||
|
|
||||||
|
var apiServerSnapshotSortAllowedValues = []domain.ServerSnapshotSort{
|
||||||
|
domain.ServerSnapshotSortDateASC,
|
||||||
|
domain.ServerSnapshotSortDateDESC,
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gocyclo
|
||||||
|
func (h *apiHTTPHandler) ListServerServerSnapshots(
|
||||||
|
w http.ResponseWriter,
|
||||||
|
r *http.Request,
|
||||||
|
_ apimodel.VersionCodePathParam,
|
||||||
|
serverKey apimodel.ServerKeyPathParam,
|
||||||
|
params apimodel.ListServerServerSnapshotsParams,
|
||||||
|
) {
|
||||||
|
domainParams := domain.NewListServerSnapshotsParams()
|
||||||
|
|
||||||
|
if err := domainParams.SetSort([]domain.ServerSnapshotSort{domain.ServerSnapshotSortIDASC}); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Sort != nil {
|
||||||
|
if err := domainParams.PrependSortString(
|
||||||
|
*params.Sort,
|
||||||
|
apiServerSnapshotSortAllowedValues,
|
||||||
|
apiServerSnapshotSortMaxLength,
|
||||||
|
); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := domainParams.PrependSort([]domain.ServerSnapshotSort{domain.ServerSnapshotSortDateASC}); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Limit != nil {
|
||||||
|
if err := domainParams.SetLimit(*params.Limit); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Cursor != nil {
|
||||||
|
if err := domainParams.SetEncodedCursor(*params.Cursor); err != nil {
|
||||||
|
h.errorRenderer.withErrorPathFormatter(formatListServerSnapshotsErrorPath).render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := h.serverSnapshotSvc.ListWithRelations(r.Context(), domainParams)
|
||||||
|
if err != nil {
|
||||||
|
h.errorRenderer.render(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
renderJSON(w, r, http.StatusOK, apimodel.NewListServerSnapshotsResponse(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatListServerSnapshotsErrorPath(segments []domain.ErrorPathSegment) []string {
|
||||||
|
if segments[0].Model != "ListServerSnapshotsParams" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch segments[0].Field {
|
||||||
|
case "cursor":
|
||||||
|
return []string{"$query", "cursor"}
|
||||||
|
case "limit":
|
||||||
|
return []string{"$query", "limit"}
|
||||||
|
case "sort":
|
||||||
|
path := []string{"$query", "sort"}
|
||||||
|
if segments[0].Index >= 0 {
|
||||||
|
path = append(path, strconv.Itoa(segments[0].Index))
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
542
internal/port/handler_http_api_server_snapshot_test.go
Normal file
542
internal/port/handler_http_api_server_snapshot_test.go
Normal file
|
@ -0,0 +1,542 @@
|
||||||
|
package port_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain/domaintest"
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/port/internal/apimodel"
|
||||||
|
"github.com/brianvoe/gofakeit/v7"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
const endpointListServerServerSnapshots = "/v2/versions/%s/servers/%s/snapshots"
|
||||||
|
|
||||||
|
func TestListServerServerSnapshots(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
handler := newAPIHTTPHandler(t)
|
||||||
|
sss := getAllServerSnapshots(t, handler)
|
||||||
|
var server serverWithVersion
|
||||||
|
|
||||||
|
sssGroupedByServerKey := make(map[string][]serverSnapshotWithServer)
|
||||||
|
for _, ss := range sss {
|
||||||
|
key := ss.Server.Key
|
||||||
|
sssGroupedByServerKey[key] = append(sssGroupedByServerKey[key], ss)
|
||||||
|
}
|
||||||
|
currentMax := -1
|
||||||
|
for _, grouped := range sssGroupedByServerKey {
|
||||||
|
if l := len(grouped); l > currentMax && l > 0 {
|
||||||
|
currentMax = l
|
||||||
|
server = grouped[0].Server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
reqModifier func(t *testing.T, req *http.Request)
|
||||||
|
assertResp func(t *testing.T, req *http.Request, resp *http.Response)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK: without params",
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListServerSnapshotsResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.ServerSnapshot) int {
|
||||||
|
return cmp.Or(
|
||||||
|
a.Date.Compare(b.Date.Time),
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: limit=1",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("limit", "1")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListServerSnapshotsResponse](t, resp.Body)
|
||||||
|
assert.NotZero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, body.Data, limit)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: limit=1 cursor",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("limit", "1")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
resp := doCustomRequest(handler, req.Clone(req.Context()))
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body := decodeJSON[apimodel.ListServerSnapshotsResponse](t, resp.Body)
|
||||||
|
require.NotEmpty(t, body.Cursor.Next)
|
||||||
|
|
||||||
|
q.Set("cursor", body.Cursor.Next)
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListServerSnapshotsResponse](t, resp.Body)
|
||||||
|
assert.Equal(t, req.URL.Query().Get("cursor"), body.Cursor.Self)
|
||||||
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, body.Data, limit)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[date:DESC]",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("sort", "date:DESC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListServerSnapshotsResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.ServerSnapshot) int {
|
||||||
|
return cmp.Or(
|
||||||
|
a.Date.Compare(b.Date.Time)*-1,
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: limit is not an integer",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("limit", "asd")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: "invalid-param-format",
|
||||||
|
Message: fmt.Sprintf(
|
||||||
|
"error binding string parameter: strconv.ParseInt: parsing \"%s\": invalid syntax",
|
||||||
|
req.URL.Query().Get("limit"),
|
||||||
|
),
|
||||||
|
Path: []string{"$query", "limit"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: limit < 1",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("limit", "0")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
|
Min: 1,
|
||||||
|
Current: limit,
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"current": float64(domainErr.Current),
|
||||||
|
"min": float64(domainErr.Min),
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "limit"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fmt.Sprintf("ERR: limit > %d", domain.ServerSnapshotListMaxLimit),
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("limit", strconv.Itoa(domain.ServerSnapshotListMaxLimit+1))
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
|
Max: domain.ServerSnapshotListMaxLimit,
|
||||||
|
Current: limit,
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"current": float64(domainErr.Current),
|
||||||
|
"max": float64(domainErr.Max),
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "limit"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(cursor) < 1",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("cursor", "")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
domainErr := domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 1000,
|
||||||
|
Current: len(req.URL.Query().Get("cursor")),
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"current": float64(domainErr.Current),
|
||||||
|
"max": float64(domainErr.Max),
|
||||||
|
"min": float64(domainErr.Min),
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "cursor"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(cursor) > 1000",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("cursor", gofakeit.LetterN(1001))
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
domainErr := domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 1000,
|
||||||
|
Current: len(req.URL.Query().Get("cursor")),
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"current": float64(domainErr.Current),
|
||||||
|
"max": float64(domainErr.Max),
|
||||||
|
"min": float64(domainErr.Min),
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "cursor"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: invalid cursor",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("cursor", gofakeit.LetterN(100))
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
var domainErr domain.Error
|
||||||
|
require.ErrorAs(t, domain.ErrInvalidCursor, &domainErr)
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Path: []string{"$query", "cursor"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(sort) > 1",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Add("sort", "date:DESC")
|
||||||
|
q.Add("sort", "date:ASC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
domainErr := domain.LenOutOfRangeError{
|
||||||
|
Min: 0,
|
||||||
|
Max: 1,
|
||||||
|
Current: len(req.URL.Query()["sort"]),
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"current": float64(domainErr.Current),
|
||||||
|
"max": float64(domainErr.Max),
|
||||||
|
"min": float64(domainErr.Min),
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "sort"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: invalid sort",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Add("sort", "date:")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
domainErr := domain.UnsupportedSortStringError{
|
||||||
|
Sort: req.URL.Query()["sort"][0],
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"sort": domainErr.Sort,
|
||||||
|
},
|
||||||
|
Path: []string{"$query", "sort", "0"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: version not found",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
req.URL.Path = fmt.Sprintf(
|
||||||
|
endpointListServerServerSnapshots,
|
||||||
|
randInvalidVersionCode(t, handler),
|
||||||
|
server.Key,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
pathSegments := strings.Split(req.URL.Path, "/")
|
||||||
|
require.Len(t, pathSegments, 7)
|
||||||
|
domainErr := domain.VersionNotFoundError{
|
||||||
|
VersionCode: pathSegments[3],
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"code": domainErr.VersionCode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: server not found",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
req.URL.Path = fmt.Sprintf(
|
||||||
|
endpointListServerServerSnapshots,
|
||||||
|
server.Version.Code,
|
||||||
|
domaintest.RandServerKey(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
|
pathSegments := strings.Split(req.URL.Path, "/")
|
||||||
|
require.Len(t, pathSegments, 7)
|
||||||
|
domainErr := domain.ServerNotFoundError{
|
||||||
|
Key: pathSegments[5],
|
||||||
|
}
|
||||||
|
assert.Equal(t, apimodel.ErrorResponse{
|
||||||
|
Errors: []apimodel.Error{
|
||||||
|
{
|
||||||
|
Code: apimodel.ErrorCode(domainErr.Code()),
|
||||||
|
Message: domainErr.Error(),
|
||||||
|
Params: map[string]any{
|
||||||
|
"key": domainErr.Key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, body)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
req := httptest.NewRequest(
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf(endpointListServerServerSnapshots, server.Version.Code, server.Key),
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if tt.reqModifier != nil {
|
||||||
|
tt.reqModifier(t, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := doCustomRequest(handler, req)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
tt.assertResp(t, req, resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type serverSnapshotWithServer struct {
|
||||||
|
apimodel.ServerSnapshot
|
||||||
|
Server serverWithVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllServerSnapshots(tb testing.TB, h http.Handler) []serverSnapshotWithServer {
|
||||||
|
tb.Helper()
|
||||||
|
|
||||||
|
servers := getAllServers(tb, h)
|
||||||
|
|
||||||
|
var sss []serverSnapshotWithServer
|
||||||
|
|
||||||
|
for _, s := range servers {
|
||||||
|
resp := doRequest(h, http.MethodGet, fmt.Sprintf(
|
||||||
|
endpointListServerServerSnapshots,
|
||||||
|
s.Version.Code,
|
||||||
|
s.Key,
|
||||||
|
), nil)
|
||||||
|
require.Equal(tb, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
for _, ts := range decodeJSON[apimodel.ListServerSnapshotsResponse](tb, resp.Body).Data {
|
||||||
|
sss = append(sss, serverSnapshotWithServer{
|
||||||
|
ServerSnapshot: ts,
|
||||||
|
Server: s,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NotZero(tb, sss)
|
||||||
|
|
||||||
|
return sss
|
||||||
|
}
|
|
@ -198,7 +198,7 @@ func TestListServers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ func TestListServers(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.ServerListMaxLimit,
|
Max: domain.ServerListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ func newAPIHTTPHandler(tb testing.TB, opts ...func(cfg *apiHTTPHandlerConfig)) h
|
||||||
villageRepo := adapter.NewVillageBunRepository(bunDB)
|
villageRepo := adapter.NewVillageBunRepository(bunDB)
|
||||||
ennoblementRepo := adapter.NewEnnoblementBunRepository(bunDB)
|
ennoblementRepo := adapter.NewEnnoblementBunRepository(bunDB)
|
||||||
tribeChangeRepo := adapter.NewTribeChangeBunRepository(bunDB)
|
tribeChangeRepo := adapter.NewTribeChangeBunRepository(bunDB)
|
||||||
|
serverSnapshotRepo := adapter.NewServerSnapshotBunRepository(bunDB)
|
||||||
tribeSnapshotRepo := adapter.NewTribeSnapshotBunRepository(bunDB)
|
tribeSnapshotRepo := adapter.NewTribeSnapshotBunRepository(bunDB)
|
||||||
playerSnapshotRepo := adapter.NewPlayerSnapshotBunRepository(bunDB)
|
playerSnapshotRepo := adapter.NewPlayerSnapshotBunRepository(bunDB)
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ func newAPIHTTPHandler(tb testing.TB, opts ...func(cfg *apiHTTPHandlerConfig)) h
|
||||||
app.NewVillageService(villageRepo, nil, nil),
|
app.NewVillageService(villageRepo, nil, nil),
|
||||||
app.NewEnnoblementService(ennoblementRepo, nil, nil),
|
app.NewEnnoblementService(ennoblementRepo, nil, nil),
|
||||||
app.NewTribeChangeService(tribeChangeRepo),
|
app.NewTribeChangeService(tribeChangeRepo),
|
||||||
|
app.NewServerSnapshotService(serverSnapshotRepo, nil, nil),
|
||||||
app.NewTribeSnapshotService(tribeSnapshotRepo, nil, nil),
|
app.NewTribeSnapshotService(tribeSnapshotRepo, nil, nil),
|
||||||
app.NewPlayerSnapshotService(playerSnapshotRepo, nil, nil),
|
app.NewPlayerSnapshotService(playerSnapshotRepo, nil, nil),
|
||||||
cfg.options...,
|
cfg.options...,
|
||||||
|
|
|
@ -22,6 +22,8 @@ var apiTribeSortAllowedValues = []domain.TribeSort{
|
||||||
domain.TribeSortODScoreTotalDESC,
|
domain.TribeSortODScoreTotalDESC,
|
||||||
domain.TribeSortPointsASC,
|
domain.TribeSortPointsASC,
|
||||||
domain.TribeSortPointsDESC,
|
domain.TribeSortPointsDESC,
|
||||||
|
domain.TribeSortMostPointsASC,
|
||||||
|
domain.TribeSortMostPointsDESC,
|
||||||
domain.TribeSortDominanceASC,
|
domain.TribeSortDominanceASC,
|
||||||
domain.TribeSortDominanceDESC,
|
domain.TribeSortDominanceDESC,
|
||||||
domain.TribeSortDeletedAtASC,
|
domain.TribeSortDeletedAtASC,
|
||||||
|
|
|
@ -273,7 +273,7 @@ func TestListPlayerTribeChanges(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ func TestListPlayerTribeChanges(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeChangeListMaxLimit,
|
Max: domain.TribeChangeListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -965,7 +965,7 @@ func TestListTribeMemberChanges(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1001,7 @@ func TestListTribeMemberChanges(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeChangeListMaxLimit,
|
Max: domain.TribeChangeListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ func TestListTribeTribeSnapshots(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ func TestListTribeTribeSnapshots(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeSnapshotListMaxLimit,
|
Max: domain.TribeSnapshotListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,32 @@ func TestListTribes(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OK: sort=[mostPoints:DESC]",
|
||||||
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
t.Helper()
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Set("sort", "mostPoints:DESC")
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
},
|
||||||
|
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
// body
|
||||||
|
body := decodeJSON[apimodel.ListTribesResponse](t, resp.Body)
|
||||||
|
assert.Zero(t, body.Cursor.Next)
|
||||||
|
assert.NotZero(t, body.Cursor.Self)
|
||||||
|
assert.NotZero(t, body.Data)
|
||||||
|
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.Tribe) int {
|
||||||
|
return cmp.Or(
|
||||||
|
cmp.Compare(a.MostPoints, b.MostPoints)*-1,
|
||||||
|
cmp.Compare(a.Id, b.Id),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "OK: tag",
|
name: "OK: tag",
|
||||||
reqModifier: func(t *testing.T, req *http.Request) {
|
reqModifier: func(t *testing.T, req *http.Request) {
|
||||||
|
@ -301,7 +327,7 @@ func TestListTribes(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -337,7 +363,7 @@ func TestListTribes(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.TribeListMaxLimit,
|
Max: domain.TribeListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -763,7 +789,7 @@ func TestGetTribe(t *testing.T) {
|
||||||
require.Len(t, pathSegments, 8)
|
require.Len(t, pathSegments, 8)
|
||||||
id, err := strconv.Atoi(pathSegments[7])
|
id, err := strconv.Atoi(pathSegments[7])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: id,
|
Current: id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ func TestListVersions(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ func TestListVersions(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VersionListMaxLimit,
|
Max: domain.VersionListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ func TestListVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ func TestListVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VillageListMaxLimit,
|
Max: domain.VillageListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -629,7 +629,7 @@ func TestListPlayerVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -665,7 +665,7 @@ func TestListPlayerVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VillageListMaxLimit,
|
Max: domain.VillageListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1042,7 @@ func TestListTribeVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1078,7 @@ func TestListTribeVillages(t *testing.T) {
|
||||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MaxLessEqualError{
|
domainErr := domain.MaxLessEqualError[int]{
|
||||||
Max: domain.VillageListMaxLimit,
|
Max: domain.VillageListMaxLimit,
|
||||||
Current: limit,
|
Current: limit,
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1363,7 @@ func TestGetVillage(t *testing.T) {
|
||||||
require.Len(t, pathSegments, 8)
|
require.Len(t, pathSegments, 8)
|
||||||
id, err := strconv.Atoi(pathSegments[7])
|
id, err := strconv.Atoi(pathSegments[7])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
domainErr := domain.MinGreaterEqualError{
|
domainErr := domain.MinGreaterEqualError[int]{
|
||||||
Min: 1,
|
Min: 1,
|
||||||
Current: id,
|
Current: id,
|
||||||
}
|
}
|
||||||
|
|
43
internal/port/internal/apimodel/server_snapshot.go
Normal file
43
internal/port/internal/apimodel/server_snapshot.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package apimodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.dwysokinski.me/twhelp/core/internal/domain"
|
||||||
|
oapitypes "github.com/oapi-codegen/runtime/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServerSnapshot(withRelations domain.ServerSnapshotWithRelations) ServerSnapshot {
|
||||||
|
ss := withRelations.ServerSnapshot()
|
||||||
|
return ServerSnapshot{
|
||||||
|
Date: oapitypes.Date{Time: ss.Date()},
|
||||||
|
Id: ss.ID(),
|
||||||
|
NumActivePlayers: ss.NumActivePlayers(),
|
||||||
|
NumActiveTribes: ss.NumActiveTribes(),
|
||||||
|
NumBarbarianVillages: ss.NumBarbarianVillages(),
|
||||||
|
NumBonusVillages: ss.NumBonusVillages(),
|
||||||
|
NumInactivePlayers: ss.NumInactivePlayers(),
|
||||||
|
NumInactiveTribes: ss.NumInactiveTribes(),
|
||||||
|
NumPlayerVillages: ss.NumPlayerVillages(),
|
||||||
|
NumPlayers: ss.NumPlayers(),
|
||||||
|
NumTribes: ss.NumTribes(),
|
||||||
|
NumVillages: ss.NumVillages(),
|
||||||
|
Server: NewServerMeta(withRelations.Server()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListServerSnapshotsResponse(res domain.ListServerSnapshotsWithRelationsResult) ListServerSnapshotsResponse {
|
||||||
|
sss := res.ServerSnapshots()
|
||||||
|
|
||||||
|
resp := ListServerSnapshotsResponse{
|
||||||
|
Data: make([]ServerSnapshot, 0, len(sss)),
|
||||||
|
Cursor: Cursor{
|
||||||
|
Next: res.Next().Encode(),
|
||||||
|
Self: res.Self().Encode(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ss := range sss {
|
||||||
|
resp.Data = append(resp.Data, NewServerSnapshot(ss))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
1456
internal/port/testdata/api/fixture.yml
vendored
1456
internal/port/testdata/api/fixture.yml
vendored
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,12 @@
|
||||||
url: https://pl169.plemiona.pl
|
url: https://pl169.plemiona.pl
|
||||||
open: true
|
open: true
|
||||||
special: false
|
special: false
|
||||||
|
num_players: 10000
|
||||||
num_active_players: 2001
|
num_active_players: 2001
|
||||||
|
num_inactive_players: 7999
|
||||||
|
num_tribes: 500
|
||||||
num_active_tribes: 214
|
num_active_tribes: 214
|
||||||
|
num_inactive_tribes: 286
|
||||||
num_villages: 49074
|
num_villages: 49074
|
||||||
num_player_villages: 48500
|
num_player_villages: 48500
|
||||||
num_barbarian_villages: 1574
|
num_barbarian_villages: 1574
|
||||||
|
|
|
@ -39,8 +39,6 @@ spec:
|
||||||
key: rabbitmq-connection-string
|
key: rabbitmq-connection-string
|
||||||
- name: AUTO_MAX_PROCS
|
- name: AUTO_MAX_PROCS
|
||||||
value: "true"
|
value: "true"
|
||||||
- name: API_OPENAPI_SERVERS
|
|
||||||
value: https://twhelp.app,https://tribalwarshelp.com
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 20m
|
cpu: 20m
|
||||||
|
|
|
@ -29,3 +29,5 @@ spec:
|
||||||
key: rabbitmq-connection-string
|
key: rabbitmq-connection-string
|
||||||
- name: AUTO_MAX_PROCS
|
- name: AUTO_MAX_PROCS
|
||||||
value: "true"
|
value: "true"
|
||||||
|
- name: API_OPENAPI_SERVERS
|
||||||
|
value: https://twhelp.app,https://tribalwarshelp.com
|
||||||
|
|
Loading…
Reference in New Issue
Block a user