feat: api - GET /api/v2/versions/{versionCode}/servers/{serverKey}/tribes - add more sort options
This commit is contained in:
parent
e5d8ba5390
commit
bf3a7b11e5
|
@ -142,6 +142,7 @@ paths:
|
||||||
- $ref: "#/components/parameters/CursorQueryParam"
|
- $ref: "#/components/parameters/CursorQueryParam"
|
||||||
- $ref: "#/components/parameters/LimitQueryParam"
|
- $ref: "#/components/parameters/LimitQueryParam"
|
||||||
- $ref: "#/components/parameters/TribeDeletedQueryParam"
|
- $ref: "#/components/parameters/TribeDeletedQueryParam"
|
||||||
|
- $ref: "#/components/parameters/TribeSortQueryParam"
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: "#/components/responses/ListTribesResponse"
|
$ref: "#/components/responses/ListTribesResponse"
|
||||||
|
@ -949,6 +950,28 @@ components:
|
||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
required: false
|
required: false
|
||||||
|
TribeSortQueryParam:
|
||||||
|
name: sort
|
||||||
|
in: query
|
||||||
|
description: Order matters!
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- odScoreAtt:ASC
|
||||||
|
- odScoreAtt:DESC
|
||||||
|
- odScoreDef:ASC
|
||||||
|
- odScoreDef:DESC
|
||||||
|
- odScoreTotal:ASC
|
||||||
|
- odScoreTotal:DESC
|
||||||
|
- points:ASC
|
||||||
|
- points:DESC
|
||||||
|
- dominance:ASC
|
||||||
|
- dominance:DESC
|
||||||
|
- deletedAt:ASC
|
||||||
|
- deletedAt:DESC
|
||||||
|
maxItems: 2
|
||||||
VersionCodePathParam:
|
VersionCodePathParam:
|
||||||
in: path
|
in: path
|
||||||
name: versionCode
|
name: versionCode
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -380,6 +381,40 @@ const (
|
||||||
TribeSortDeletedAtDESC
|
TribeSortDeletedAtDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:gocyclo
|
||||||
|
func newTribeSortFromString(s string) (TribeSort, error) {
|
||||||
|
switch strings.ToLower(s) {
|
||||||
|
case "odscoreatt:asc":
|
||||||
|
return TribeSortODScoreAttASC, nil
|
||||||
|
case "odscoreatt:desc":
|
||||||
|
return TribeSortODScoreAttDESC, nil
|
||||||
|
case "odscoredef:asc":
|
||||||
|
return TribeSortODScoreDefASC, nil
|
||||||
|
case "odscoredef:desc":
|
||||||
|
return TribeSortODScoreDefDESC, nil
|
||||||
|
case "odscoretotal:asc":
|
||||||
|
return TribeSortODScoreTotalASC, nil
|
||||||
|
case "odscoretotal:desc":
|
||||||
|
return TribeSortODScoreTotalDESC, nil
|
||||||
|
case "points:asc":
|
||||||
|
return TribeSortPointsASC, nil
|
||||||
|
case "points:desc":
|
||||||
|
return TribeSortPointsDESC, nil
|
||||||
|
case "dominance:asc":
|
||||||
|
return TribeSortDominanceASC, nil
|
||||||
|
case "dominance:desc":
|
||||||
|
return TribeSortDominanceDESC, nil
|
||||||
|
case "deletedat:asc":
|
||||||
|
return TribeSortDeletedAtASC, nil
|
||||||
|
case "deletedat:desc":
|
||||||
|
return TribeSortDeletedAtDESC, nil
|
||||||
|
default:
|
||||||
|
return 0, UnsupportedSortStringError{
|
||||||
|
Sort: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TribeCursor struct {
|
type TribeCursor struct {
|
||||||
id int
|
id int
|
||||||
serverKey string
|
serverKey string
|
||||||
|
@ -666,6 +701,31 @@ func (params *ListTribesParams) SetSort(sort []TribeSort) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (params *ListTribesParams) PrependSortString(sort []string) error {
|
||||||
|
if err := validateSliceLen(sort, tribeSortMinLength, max(tribeSortMaxLength-len(params.sort), 0)); err != nil {
|
||||||
|
return ValidationError{
|
||||||
|
Model: listTribesParamsModelName,
|
||||||
|
Field: "sort",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(sort) - 1; i >= 0; i-- {
|
||||||
|
converted, err := newTribeSortFromString(sort[i])
|
||||||
|
if err != nil {
|
||||||
|
return SliceElementValidationError{
|
||||||
|
Model: listTribesParamsModelName,
|
||||||
|
Field: "sort",
|
||||||
|
Index: i,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.sort = append([]TribeSort{converted}, params.sort...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (params *ListTribesParams) Cursor() TribeCursor {
|
func (params *ListTribesParams) Cursor() TribeCursor {
|
||||||
return params.cursor
|
return params.cursor
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,6 +510,185 @@ func TestListTribesParams_SetSort(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListTribesParams_PrependSortString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
defaultNewParams := func(t *testing.T) domain.ListTribesParams {
|
||||||
|
t.Helper()
|
||||||
|
return domain.ListTribesParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
sort []string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
newParams func(t *testing.T) domain.ListTribesParams
|
||||||
|
args args
|
||||||
|
expectedSort []domain.TribeSort
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK: [odScoreAtt:ASC, odScoreDef:ASC, odScoreTotal:ASC]",
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"odScoreAtt:ASC",
|
||||||
|
"odScoreDef:ASC",
|
||||||
|
"odScoreTotal:ASC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSort: []domain.TribeSort{
|
||||||
|
domain.TribeSortODScoreAttASC,
|
||||||
|
domain.TribeSortODScoreDefASC,
|
||||||
|
domain.TribeSortODScoreTotalASC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: [odScoreAtt:DESC, odScoreDef:DESC, odScoreTotal:DESC]",
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"odScoreAtt:DESC",
|
||||||
|
"odScoreDef:DESC",
|
||||||
|
"odScoreTotal:DESC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSort: []domain.TribeSort{
|
||||||
|
domain.TribeSortODScoreAttDESC,
|
||||||
|
domain.TribeSortODScoreDefDESC,
|
||||||
|
domain.TribeSortODScoreTotalDESC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: [points:ASC, dominance:ASC, deletedAt:ASC]",
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"points:ASC",
|
||||||
|
"dominance:ASC",
|
||||||
|
"deletedAt:ASC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSort: []domain.TribeSort{
|
||||||
|
domain.TribeSortPointsASC,
|
||||||
|
domain.TribeSortDominanceASC,
|
||||||
|
domain.TribeSortDeletedAtASC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: [points:DESC, dominance:DESC, deletedAt:DESC]",
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"points:DESC",
|
||||||
|
"dominance:DESC",
|
||||||
|
"deletedAt:DESC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSort: []domain.TribeSort{
|
||||||
|
domain.TribeSortPointsDESC,
|
||||||
|
domain.TribeSortDominanceDESC,
|
||||||
|
domain.TribeSortDeletedAtDESC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(sort) < 1",
|
||||||
|
args: args{
|
||||||
|
sort: nil,
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListTribesParams",
|
||||||
|
Field: "sort",
|
||||||
|
Err: domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 3,
|
||||||
|
Current: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(sort) > 3",
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"odScoreAtt:ASC",
|
||||||
|
"odScoreDef:ASC",
|
||||||
|
"odScoreTotal:ASC",
|
||||||
|
"points:ASC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListTribesParams",
|
||||||
|
Field: "sort",
|
||||||
|
Err: domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 3,
|
||||||
|
Current: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: custom params + len(sort) > 2",
|
||||||
|
newParams: func(t *testing.T) domain.ListTribesParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListTribesParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.TribeSort{domain.TribeSortIDASC}))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"odScoreAtt:ASC",
|
||||||
|
"odScoreDef:ASC",
|
||||||
|
"odScoreTotal:ASC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListTribesParams",
|
||||||
|
Field: "sort",
|
||||||
|
Err: domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 2,
|
||||||
|
Current: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: unsupported sort string",
|
||||||
|
newParams: defaultNewParams,
|
||||||
|
args: args{
|
||||||
|
sort: []string{
|
||||||
|
"odScoreAtt:ASC",
|
||||||
|
"odScoreDef:ASC",
|
||||||
|
"odScoreTotal:",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: domain.SliceElementValidationError{
|
||||||
|
Model: "ListTribesParams",
|
||||||
|
Field: "sort",
|
||||||
|
Index: 2,
|
||||||
|
Err: domain.UnsupportedSortStringError{
|
||||||
|
Sort: "odScoreTotal:",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
newParams := defaultNewParams
|
||||||
|
if tt.newParams != nil {
|
||||||
|
newParams = tt.newParams
|
||||||
|
}
|
||||||
|
params := newParams(t)
|
||||||
|
|
||||||
|
require.ErrorIs(t, params.PrependSortString(tt.args.sort), tt.expectedErr)
|
||||||
|
if tt.expectedErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, tt.expectedSort, params.Sort())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestListTribesParams_SetEncodedCursor(t *testing.T) {
|
func TestListTribesParams_SetEncodedCursor(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,30 @@ func (e InvalidURLError) Params() map[string]any {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnsupportedSortStringError struct {
|
||||||
|
Sort string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ErrorWithParams = UnsupportedSortStringError{}
|
||||||
|
|
||||||
|
func (e UnsupportedSortStringError) Error() string {
|
||||||
|
return fmt.Sprintf("sort %s is unsupported", e.Sort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnsupportedSortStringError) Type() ErrorType {
|
||||||
|
return ErrorTypeIncorrectInput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnsupportedSortStringError) Code() string {
|
||||||
|
return "unsupported-sort-string"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnsupportedSortStringError) Params() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"Sort": e.Sort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ErrRequired error = simpleError{
|
var ErrRequired error = simpleError{
|
||||||
msg: "can't be blank",
|
msg: "can't be blank",
|
||||||
typ: ErrorTypeIncorrectInput,
|
typ: ErrorTypeIncorrectInput,
|
||||||
|
|
|
@ -2,11 +2,13 @@ package port
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:gocyclo
|
||||||
func (h *apiHTTPHandler) ListTribes(
|
func (h *apiHTTPHandler) ListTribes(
|
||||||
w http.ResponseWriter,
|
w http.ResponseWriter,
|
||||||
r *http.Request,
|
r *http.Request,
|
||||||
|
@ -21,6 +23,13 @@ func (h *apiHTTPHandler) ListTribes(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Sort != nil {
|
||||||
|
if err := domainParams.PrependSortString(*params.Sort); err != nil {
|
||||||
|
apiErrorRenderer{errors: []error{err}, formatErrorPath: formatListTribesParamsErrorPath}.render(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
|
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
|
||||||
apiErrorRenderer{errors: []error{err}, formatErrorPath: formatListTribesParamsErrorPath}.render(w, r)
|
apiErrorRenderer{errors: []error{err}, formatErrorPath: formatListTribesParamsErrorPath}.render(w, r)
|
||||||
return
|
return
|
||||||
|
@ -72,7 +81,11 @@ func formatListTribesParamsErrorPath(segments []errorPathSegment) []string {
|
||||||
case "deleted":
|
case "deleted":
|
||||||
return []string{"$query", "deleted"}
|
return []string{"$query", "deleted"}
|
||||||
case "sort":
|
case "sort":
|
||||||
return []string{"$query", "sort"}
|
path := []string{"$query", "sort"}
|
||||||
|
if segments[0].index >= 0 {
|
||||||
|
path = append(path, strconv.Itoa(segments[0].index))
|
||||||
|
}
|
||||||
|
return path
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user