add 2 new queries - SearchTribe and SearchPlayer + bump github.com/tribalwarshelp/shared

This commit is contained in:
Dawid Wysokiński 2020-12-25 12:07:54 +01:00
parent 5aae1ca92f
commit 4bccaab85d
19 changed files with 1724 additions and 1 deletions

2
go.mod
View File

@ -16,7 +16,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/segmentio/encoding v0.1.14 // indirect
github.com/tribalwarshelp/map-generator v0.0.0-20200801113621-fb8892ceb243
github.com/tribalwarshelp/shared v0.0.0-20201107073846-5e8e2d44d75c
github.com/tribalwarshelp/shared v0.0.0-20201225102309-31dd9dda110c
github.com/vektah/gqlparser/v2 v2.1.0
go.opentelemetry.io/otel v0.9.0 // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208

2
go.sum
View File

@ -204,6 +204,8 @@ github.com/tribalwarshelp/shared v0.0.0-20201106181031-7c5891c02013 h1:6KWK3MWsT
github.com/tribalwarshelp/shared v0.0.0-20201106181031-7c5891c02013/go.mod h1:Lxk6zaQhPTPrgz9ksMgg51m8XgflrCo/kRBx2cM3yfk=
github.com/tribalwarshelp/shared v0.0.0-20201107073846-5e8e2d44d75c h1:Lgqaf1a5zBpCGlA3O0k/jTChI0nvYlXj882iQK2fFT4=
github.com/tribalwarshelp/shared v0.0.0-20201107073846-5e8e2d44d75c/go.mod h1:Lxk6zaQhPTPrgz9ksMgg51m8XgflrCo/kRBx2cM3yfk=
github.com/tribalwarshelp/shared v0.0.0-20201225102309-31dd9dda110c h1:ArwHE/mF3yaOhM/XMYnlh8bCOcsQeOwOfA3SJWOIlhM=
github.com/tribalwarshelp/shared v0.0.0-20201225102309-31dd9dda110c/go.mod h1:Lxk6zaQhPTPrgz9ksMgg51m8XgflrCo/kRBx2cM3yfk=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,16 @@ type EnnoblementList struct {
Total int `json:"total"`
}
type FoundPlayerList struct {
Items []*models.FoundPlayer `json:"items"`
Total int `json:"total"`
}
type FoundTribeList struct {
Items []*models.FoundTribe `json:"items"`
Total int `json:"total"`
}
type PlayerHistory struct {
Total int `json:"total"`
Items []*models.PlayerHistory `json:"items"`

View File

@ -67,10 +67,14 @@ models:
model: github.com/tribalwarshelp/shared/models.Player
PlayerFilter:
model: github.com/tribalwarshelp/shared/models.PlayerFilter
FoundPlayer:
model: github.com/tribalwarshelp/shared/models.FoundPlayer
Tribe:
model: github.com/tribalwarshelp/shared/models.Tribe
TribeFilter:
model: github.com/tribalwarshelp/shared/models.TribeFilter
FoundTribe:
model: github.com/tribalwarshelp/shared/models.FoundTribe
Village:
model: github.com/tribalwarshelp/shared/models.Village
VillageFilter:

View File

@ -66,3 +66,28 @@ func getTribe(ctx context.Context, id int) *models.Tribe {
}
return nil
}
func shouldCount(ctx context.Context) bool {
count := false
for _, field := range graphql.CollectFieldsCtx(ctx, nil) {
if field.Name == countField {
count = true
break
}
}
return count
}
func safeStrPointer(s *string, def string) string {
if s == nil {
return def
}
return *s
}
func safeIntPointer(s *int, def int) int {
if s == nil {
return def
}
return *s
}

View File

@ -77,3 +77,24 @@ func (r *queryResolver) Players(ctx context.Context,
func (r *queryResolver) Player(ctx context.Context, server string, id int) (*models.Player, error) {
return r.PlayerUcase.GetByID(ctx, server, id)
}
func (r *queryResolver) SearchPlayer(ctx context.Context,
version string,
name *string,
id *int,
limit *int,
offset *int,
sort []string) (*generated.FoundPlayerList, error) {
var err error
list := &generated.FoundPlayerList{}
list.Items, list.Total, err = r.PlayerUcase.SearchPlayer(ctx, player.SearchPlayerConfig{
Sort: sort,
Limit: safeIntPointer(limit, 0),
Offset: safeIntPointer(offset, 0),
Version: version,
Name: safeStrPointer(name, ""),
ID: safeIntPointer(id, 0),
Count: shouldCount(ctx),
})
return list, err
}

View File

@ -17,6 +17,10 @@ import (
"github.com/tribalwarshelp/api/village"
)
const (
countField = "total"
)
type Resolver struct {
VersionUcase version.Usecase
ServerUcase server.Usecase

View File

@ -39,3 +39,22 @@ func (r *queryResolver) Tribes(ctx context.Context,
func (r *queryResolver) Tribe(ctx context.Context, server string, id int) (*models.Tribe, error) {
return r.TribeUcase.GetByID(ctx, server, id)
}
func (r *queryResolver) SearchTribe(ctx context.Context,
version string,
query string,
limit *int,
offset *int,
sort []string) (*generated.FoundTribeList, error) {
var err error
list := &generated.FoundTribeList{}
list.Items, list.Total, err = r.TribeUcase.SearchTribe(ctx, tribe.SearchTribeConfig{
Sort: sort,
Limit: safeIntPointer(limit, 0),
Offset: safeIntPointer(offset, 0),
Version: version,
Query: query,
Count: shouldCount(ctx),
})
return list, err
}

View File

@ -150,6 +150,22 @@ input PlayerFilter {
)
}
type FoundPlayer {
server: String!
id: Int!
name: String!
bestRank: Int!
mostPoints: Int!
mostVillages: Int!
tribeID: Int!
tribeTag: String!
}
type FoundPlayerList {
items: [FoundPlayer!]
total: Int!
}
extend type Query {
players(
server: String!
@ -159,4 +175,12 @@ extend type Query {
sort: [String!]
): PlayerList!
player(server: String!, id: Int!): Player
searchPlayer(
version: String!
name: String
id: Int
limit: Int
offset: Int
sort: [String!]
): FoundPlayerList!
}

View File

@ -144,6 +144,21 @@ input TribeFilter {
)
}
type FoundTribe {
server: String!
id: Int!
tag: String!
name: String!
bestRank: Int!
mostPoints: Int!
mostVillages: Int!
}
type FoundTribeList {
items: [FoundTribe!]
total: Int!
}
extend type Query {
tribes(
server: String!
@ -153,4 +168,11 @@ extend type Query {
sort: [String!]
): TribeList!
tribe(server: String!, id: Int!): Tribe
searchTribe(
version: String!
query: String!
limit: Int
offset: Int
sort: [String!]
): FoundTribeList!
}

View File

@ -15,8 +15,19 @@ type FetchConfig struct {
Offset int
}
type SearchPlayerConfig struct {
Version string
Name string
ID int
Count bool
Sort []string
Limit int
Offset int
}
type Repository interface {
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Player, int, error)
FetchNameChanges(ctx context.Context, code models.VersionCode, playerID ...int) (map[int][]*models.PlayerNameChange, error)
FetchPlayerServers(ctx context.Context, code models.VersionCode, playerID ...int) (map[int][]string, error)
SearchPlayer(ctx context.Context, cfg SearchPlayerConfig) ([]*models.FoundPlayer, int, error)
}

View File

@ -6,6 +6,7 @@ import (
"strings"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
"github.com/tribalwarshelp/api/player"
"github.com/tribalwarshelp/api/utils"
@ -107,3 +108,63 @@ func (repo *pgRepository) FetchPlayerServers(ctx context.Context, code models.Ve
}
return m, nil
}
func (repo *pgRepository) SearchPlayer(ctx context.Context, cfg player.SearchPlayerConfig) ([]*models.FoundPlayer, int, error) {
servers := []*models.Server{}
if err := repo.
Model(&servers).
Context(ctx).
Column("key").
Where("version_code = ?", cfg.Version).
Select(); err != nil {
return nil, 0, errors.Wrap(err, "Internal server error")
}
var query *orm.Query
res := []*models.FoundPlayer{}
whereClause := "player.id = ?1 OR player.name ILIKE ?0"
if cfg.ID <= 0 {
whereClause = "player.name ILIKE ?0"
} else if cfg.Name == "" {
whereClause = "player.id = ?1"
}
for _, server := range servers {
safeKey := pg.Safe(server.Key)
otherQuery := repo.
Model().
Context(ctx).
ColumnExpr("? AS server", server.Key).
ColumnExpr("tribe.tag as tribe_tag").
Column("player.id", "player.name", "player.most_points", "player.best_rank", "player.most_villages", "player.tribe_id").
TableExpr("?0.players as player", safeKey).
Join("LEFT JOIN ?0.tribes as tribe ON player.tribe_id = tribe.id", safeKey).
Where(whereClause, cfg.Name, cfg.ID)
if query == nil {
query = otherQuery
} else {
query = query.UnionAll(otherQuery)
}
}
var err error
count := 0
if query != nil {
base := repo.
Model().
With("union_q", query).
Table("union_q").
Limit(cfg.Limit).
Offset(cfg.Offset).
Order(cfg.Sort...)
if cfg.Count {
count, err = base.SelectAndCount(&res)
} else {
err = base.Select(&res)
}
if err != nil && err != pg.ErrNoRows {
return nil, 0, errors.Wrap(err, "Internal server error")
}
}
return res, count, nil
}

View File

@ -9,4 +9,5 @@ import (
type Usecase interface {
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Player, int, error)
GetByID(ctx context.Context, server string, id int) (*models.Player, error)
SearchPlayer(ctx context.Context, cfg SearchPlayerConfig) ([]*models.FoundPlayer, int, error)
}

View File

@ -3,6 +3,7 @@ package usecase
import (
"context"
"fmt"
"strings"
"github.com/tribalwarshelp/api/middleware"
"github.com/tribalwarshelp/api/player"
@ -59,3 +60,17 @@ func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*mode
}
return players[0], nil
}
func (ucase *usecase) SearchPlayer(ctx context.Context, cfg player.SearchPlayerConfig) ([]*models.FoundPlayer, int, error) {
if "" == strings.TrimSpace(cfg.Version) {
return nil, 0, fmt.Errorf("Version is required.")
}
if "" == strings.TrimSpace(cfg.Name) && cfg.ID <= 0 {
return nil, 0, fmt.Errorf("Your search is ambiguous. You must specify the variable 'name' or 'id'.")
}
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > player.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = player.PaginationLimit
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.SearchPlayer(ctx, cfg)
}

View File

@ -15,6 +15,16 @@ type FetchConfig struct {
Offset int
}
type SearchTribeConfig struct {
Version string
Query string
Count bool
Sort []string
Limit int
Offset int
}
type Repository interface {
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Tribe, int, error)
SearchTribe(ctx context.Context, cfg SearchTribeConfig) ([]*models.FoundTribe, int, error)
}

View File

@ -6,6 +6,7 @@ import (
"strings"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
"github.com/tribalwarshelp/api/tribe"
"github.com/tribalwarshelp/shared/models"
@ -53,3 +54,55 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg tribe.FetchConfig) ([]*
return data, total, nil
}
func (repo *pgRepository) SearchTribe(ctx context.Context, cfg tribe.SearchTribeConfig) ([]*models.FoundTribe, int, error) {
servers := []*models.Server{}
if err := repo.
Model(&servers).
Context(ctx).
Column("key").
Where("version_code = ?", cfg.Version).
Select(); err != nil {
return nil, 0, errors.Wrap(err, "Internal server error")
}
var query *orm.Query
res := []*models.FoundTribe{}
for _, server := range servers {
safeKey := pg.Safe(server.Key)
otherQuery := repo.
Model().
Context(ctx).
ColumnExpr("? AS server", server.Key).
Column("tribe.id", "tribe.name", "tribe.most_points", "tribe.best_rank", "tribe.most_villages").
TableExpr("?0.tribes as tribe", safeKey).
Where("tribe.tag ILIKE ?0 OR tribe.name ILIKE ?0", cfg.Query)
if query == nil {
query = otherQuery
} else {
query = query.UnionAll(otherQuery)
}
}
var err error
count := 0
if query != nil {
base := repo.
Model().
With("union_q", query).
Table("union_q").
Limit(cfg.Limit).
Offset(cfg.Offset).
Order(cfg.Sort...)
if cfg.Count {
count, err = base.SelectAndCount(&res)
} else {
err = base.Select(&res)
}
if err != nil && err != pg.ErrNoRows {
return nil, 0, errors.Wrap(err, "Internal server error")
}
}
return res, count, nil
}

View File

@ -9,4 +9,5 @@ import (
type Usecase interface {
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Tribe, int, error)
GetByID(ctx context.Context, server string, id int) (*models.Tribe, error)
SearchTribe(ctx context.Context, cfg SearchTribeConfig) ([]*models.FoundTribe, int, error)
}

View File

@ -3,6 +3,7 @@ package usecase
import (
"context"
"fmt"
"strings"
"github.com/tribalwarshelp/api/middleware"
"github.com/tribalwarshelp/api/tribe"
@ -55,3 +56,17 @@ func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*mode
}
return tribes[0], nil
}
func (ucase *usecase) SearchTribe(ctx context.Context, cfg tribe.SearchTribeConfig) ([]*models.FoundTribe, int, error) {
if "" == strings.TrimSpace(cfg.Version) {
return nil, 0, fmt.Errorf("Version is required.")
}
if "" == strings.TrimSpace(cfg.Query) {
return nil, 0, fmt.Errorf("Your search is ambiguous. You must specify the variable 'query'.")
}
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > tribe.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = tribe.PaginationLimit
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.SearchTribe(ctx, cfg)
}