Merge pull request #11 from tribalwarshelp/repositories-select-option

Repositories - add 'select' option to FetchConfigs
This commit is contained in:
Dawid Wysokiński 2021-03-21 13:27:28 +01:00 committed by GitHub
commit 9659e2c01c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 201 additions and 126 deletions

View File

@ -1,78 +1,83 @@
# TWHelp API # TWHelp API
A GraphQL API for Tribal Wars data. All versions are available. A GraphQL API for Tribal Wars data.
## API Limits ## API Limits
You can fetch in one HTTP request: You can fetch in one GraphQL query:
1. 1000 daily player/tribe stats 1. 1000 daily player/tribe stats records
2. 100 ennoblements 2. 200 ennoblements
3. 100 versions 3. 30 versions
4. 100 players/tribes 4. 200 players/tribes
5. 1000 villages 5. 1000 villages
6. 100 player/tribe history records 6. 100 player/tribe history records
7. 100 servers 7. 100 servers
8. 60 server stats 8. 60 server stats records
9. 100 tribe changes 9. 100 tribe changes
## Sample queries ## Sample queries
You can check how to make requests from JavaScript [here](https://github.com/tribalwarshelp/scripts). You can check how to make requests from JavaScript [here](https://github.com/tribalwarshelp/scripts).
1. All barbarian villages with 10% more population 1. All bonus villages with 10% more population
```graphql ```graphql
query { query {
villages(server: "en115", filter: { playerID: [0], bonus: 4 }) { villages(server: "en115", filter: { playerID: [0], bonus: 4 }) {
total total
items { items {
id id
name name
x x
y y
points points
}
} }
}
} }
``` ```
2. Top 30 players without a tribe, ordered by points. 2. Top 30 players without a tribe, ordered by points.
```graphql ```graphql
query { query {
players( players(
server: "pl148" server: "pl148"
filter: { tribeID: [0], sort: "points DESC", limit: 30 } filter: { tribeID: [0] }
) { sort: ["points DESC"]
total limit: 30
items { ) {
id total
name items {
rank id
points name
totalVillages rank
rankAtt points
rankDef totalVillages
rankTotal rankAtt
rankSup rankDef
rankTotal
rankSup
}
} }
}
} }
``` ```
3. Search a player by a nickname fragment. 3. Search a player by a nickname fragment.
```graphql ```graphql
query { query {
players(server: "pl148", filter: { nameIEQ: "%pablo%" }) { players(server: "pl148", filter: { nameIEQ: "%pablo%" }) {
total total
items { items {
id id
name name
}
} }
}
} }
``` ```
## Map service ## Map service
@ -112,8 +117,6 @@ DB_NAME=your_pgdb_name
DB_PORT=your_pgdb_port DB_PORT=your_pgdb_port
DB_HOST=your_pgdb_host DB_HOST=your_pgdb_host
DB_PASSWORD=your_pgdb_password DB_PASSWORD=your_pgdb_password
REDIS_HOST=your_redis_host
REDIS_PORT=your_redis_port
LIMIT_WHITELIST=127.0.0.1,::1 LIMIT_WHITELIST=127.0.0.1,::1
LOG_DB_QUERIES=[true|false] LOG_DB_QUERIES=[true|false]
``` ```

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.DailyPlayerStatsFilter Filter *models.DailyPlayerStatsFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg dailyplayerstats.FetchC
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -21,7 +21,6 @@ func (ucase *usecase) Fetch(ctx context.Context, cfg dailyplayerstats.FetchConfi
if cfg.Filter == nil { if cfg.Filter == nil {
cfg.Filter = &models.DailyPlayerStatsFilter{} cfg.Filter = &models.DailyPlayerStatsFilter{}
} }
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > dailyplayerstats.FetchLimit || cfg.Limit <= 0) { if !middleware.CanExceedLimit(ctx) && (cfg.Limit > dailyplayerstats.FetchLimit || cfg.Limit <= 0) {
cfg.Limit = dailyplayerstats.FetchLimit cfg.Limit = dailyplayerstats.FetchLimit
} }

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.DailyTribeStatsFilter Filter *models.DailyTribeStatsFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg dailytribestats.FetchCo
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.EnnoblementFilter Filter *models.EnnoblementFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg ennoblement.FetchConfig
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

2
go.sum
View File

@ -160,8 +160,6 @@ github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GH
github.com/tribalwarshelp/map-generator v0.0.0-20210106163923-fa048a59f5f2 h1:yYSQuWN6YvY0cL77Ha7Y350Xm2/J+6suHubv5F/ZluY= github.com/tribalwarshelp/map-generator v0.0.0-20210106163923-fa048a59f5f2 h1:yYSQuWN6YvY0cL77Ha7Y350Xm2/J+6suHubv5F/ZluY=
github.com/tribalwarshelp/map-generator v0.0.0-20210106163923-fa048a59f5f2/go.mod h1:ywyp0CZ3JsJ+0GAbUJVWo3dipHcAohD7KkV2TNbiTHU= github.com/tribalwarshelp/map-generator v0.0.0-20210106163923-fa048a59f5f2/go.mod h1:ywyp0CZ3JsJ+0GAbUJVWo3dipHcAohD7KkV2TNbiTHU=
github.com/tribalwarshelp/shared v0.0.0-20210106162314-d3488036ca2f/go.mod h1:vtDs7EjEysk4dpFPfu3c4lkICXZYIRV0BrT7rsqG0dw= github.com/tribalwarshelp/shared v0.0.0-20210106162314-d3488036ca2f/go.mod h1:vtDs7EjEysk4dpFPfu3c4lkICXZYIRV0BrT7rsqG0dw=
github.com/tribalwarshelp/shared v0.0.0-20210115163415-972e2df3f7db h1:RzMEF4BP3YJ7jJOyYO00TdeB6DY7g0Dp/8cQ8t6WKzw=
github.com/tribalwarshelp/shared v0.0.0-20210115163415-972e2df3f7db/go.mod h1:vtDs7EjEysk4dpFPfu3c4lkICXZYIRV0BrT7rsqG0dw=
github.com/tribalwarshelp/shared v0.0.0-20210321105345-7a8582fd0b91 h1:YxUIaDrLe3nE+8MHWxcGn1f/Ic0AfC/iS8/tnHAm2iE= github.com/tribalwarshelp/shared v0.0.0-20210321105345-7a8582fd0b91 h1:YxUIaDrLe3nE+8MHWxcGn1f/Ic0AfC/iS8/tnHAm2iE=
github.com/tribalwarshelp/shared v0.0.0-20210321105345-7a8582fd0b91/go.mod h1:EnTN6KBL5jZZnan7cVOWIsAO3q+a1XNPpa9m6Pv3MeM= github.com/tribalwarshelp/shared v0.0.0-20210321105345-7a8582fd0b91/go.mod h1:EnTN6KBL5jZZnan7cVOWIsAO3q+a1XNPpa9m6Pv3MeM=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=

View File

@ -11,6 +11,10 @@ import (
"github.com/tribalwarshelp/shared/models" "github.com/tribalwarshelp/shared/models"
) )
const (
wait = 4 * time.Millisecond
)
type DataLoaders struct { type DataLoaders struct {
VersionByCode *VersionLoader VersionByCode *VersionLoader
} }
@ -25,7 +29,7 @@ type Config struct {
func NewDataLoaders(cfg Config) *DataLoaders { func NewDataLoaders(cfg Config) *DataLoaders {
return &DataLoaders{ return &DataLoaders{
VersionByCode: &VersionLoader{ VersionByCode: &VersionLoader{
wait: 4 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(keys []string) ([]*models.Version, []error) { fetch: func(keys []string) ([]*models.Version, []error) {
codes := []models.VersionCode{} codes := []models.VersionCode{}
@ -36,6 +40,7 @@ func NewDataLoaders(cfg Config) *DataLoaders {
Filter: &models.VersionFilter{ Filter: &models.VersionFilter{
Code: codes, Code: codes,
}, },
Select: true,
}) })
if err != nil { if err != nil {
return nil, []error{err} return nil, []error{err}

View File

@ -2,8 +2,6 @@ package dataloaders
import ( import (
"context" "context"
"time"
"github.com/tribalwarshelp/api/player" "github.com/tribalwarshelp/api/player"
"github.com/tribalwarshelp/api/tribe" "github.com/tribalwarshelp/api/tribe"
"github.com/tribalwarshelp/api/village" "github.com/tribalwarshelp/api/village"
@ -19,13 +17,14 @@ type ServerDataLoaders struct {
func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders { func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
return &ServerDataLoaders{ return &ServerDataLoaders{
PlayerByID: &PlayerLoader{ PlayerByID: &PlayerLoader{
wait: 2 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(ids []int) ([]*models.Player, []error) { fetch: func(ids []int) ([]*models.Player, []error) {
players, _, err := cfg.PlayerRepo.Fetch(context.Background(), player.FetchConfig{ players, _, err := cfg.PlayerRepo.Fetch(context.Background(), player.FetchConfig{
Filter: &models.PlayerFilter{ Filter: &models.PlayerFilter{
ID: ids, ID: ids,
}, },
Select: true,
Server: server, Server: server,
}) })
if err != nil { if err != nil {
@ -46,7 +45,7 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
}, },
}, },
TribeByID: &TribeLoader{ TribeByID: &TribeLoader{
wait: 2 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(ids []int) ([]*models.Tribe, []error) { fetch: func(ids []int) ([]*models.Tribe, []error) {
tribes, _, err := cfg.TribeRepo.Fetch(context.Background(), tribe.FetchConfig{ tribes, _, err := cfg.TribeRepo.Fetch(context.Background(), tribe.FetchConfig{
@ -54,6 +53,7 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
Filter: &models.TribeFilter{ Filter: &models.TribeFilter{
ID: ids, ID: ids,
}, },
Select: true,
}) })
if err != nil { if err != nil {
return nil, []error{err} return nil, []error{err}
@ -73,7 +73,7 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
}, },
}, },
VillageByID: &VillageLoader{ VillageByID: &VillageLoader{
wait: 2 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(ids []int) ([]*models.Village, []error) { fetch: func(ids []int) ([]*models.Village, []error) {
villages, _, err := cfg.VillageRepo.Fetch(context.Background(), village.FetchConfig{ villages, _, err := cfg.VillageRepo.Fetch(context.Background(), village.FetchConfig{
@ -82,6 +82,7 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
Filter: &models.VillageFilter{ Filter: &models.VillageFilter{
ID: ids, ID: ids,
}, },
Select: true,
}) })
if err != nil { if err != nil {
return nil, []error{err} return nil, []error{err}

View File

@ -2,8 +2,6 @@ package dataloaders
import ( import (
"context" "context"
"time"
"github.com/tribalwarshelp/shared/models" "github.com/tribalwarshelp/shared/models"
) )
@ -15,7 +13,7 @@ type VersionDataLoaders struct {
func NewVersionDataLoaders(versionCode models.VersionCode, cfg Config) *VersionDataLoaders { func NewVersionDataLoaders(versionCode models.VersionCode, cfg Config) *VersionDataLoaders {
return &VersionDataLoaders{ return &VersionDataLoaders{
PlayerServersByID: &PlayerServersLoader{ PlayerServersByID: &PlayerServersLoader{
wait: 2 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(keys []int) ([][]string, []error) { fetch: func(keys []int) ([][]string, []error) {
playerServersByID, err := cfg.PlayerRepo.FetchPlayerServers(context.Background(), versionCode, keys...) playerServersByID, err := cfg.PlayerRepo.FetchPlayerServers(context.Background(), versionCode, keys...)
@ -30,7 +28,7 @@ func NewVersionDataLoaders(versionCode models.VersionCode, cfg Config) *VersionD
}, },
}, },
PlayerNameChangesByID: &PlayerNameChangesLoader{ PlayerNameChangesByID: &PlayerNameChangesLoader{
wait: 2 * time.Millisecond, wait: wait,
maxBatch: 0, maxBatch: 0,
fetch: func(keys []int) ([][]*models.PlayerNameChange, []error) { fetch: func(keys []int) ([][]*models.PlayerNameChange, []error) {
playerNameChangesByID, err := cfg.PlayerRepo.FetchNameChanges(context.Background(), versionCode, keys...) playerNameChangesByID, err := cfg.PlayerRepo.FetchNameChanges(context.Background(), versionCode, keys...)

View File

@ -31,6 +31,7 @@ func (r *queryResolver) DailyPlayerStats(ctx context.Context,
Sort: sort, Sort: sort,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Select: shouldSelectItems(ctx),
Count: shouldCount(ctx), Count: shouldCount(ctx),
}) })
return list, err return list, err

View File

@ -31,6 +31,7 @@ func (r *queryResolver) DailyTribeStats(ctx context.Context,
Sort: sort, Sort: sort,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Select: shouldSelectItems(ctx),
Count: shouldCount(ctx), Count: shouldCount(ctx),
}) })
return list, err return list, err

View File

@ -63,6 +63,7 @@ func (r *queryResolver) Ennoblements(ctx context.Context, server string,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -67,11 +67,19 @@ func getTribe(ctx context.Context, id int) *models.Tribe {
return nil return nil
} }
func shouldCount(ctx context.Context) bool { func findField(ctx context.Context, name string) bool {
for _, field := range graphql.CollectFieldsCtx(ctx, nil) { for _, field := range graphql.CollectFieldsCtx(ctx, nil) {
if field.Name == countField { if field.Name == name {
return true return true
} }
} }
return false return false
} }
func shouldCount(ctx context.Context) bool {
return findField(ctx, countField)
}
func shouldSelectItems(ctx context.Context) bool {
return findField(ctx, itemsField)
}

View File

@ -62,6 +62,7 @@ func (r *queryResolver) Players(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -40,6 +40,7 @@ func (r *Resolver) PlayerHistory(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -18,6 +18,7 @@ import (
const ( const (
countField = "total" countField = "total"
itemsField = "items"
) )
type Resolver struct { type Resolver struct {

View File

@ -33,6 +33,7 @@ func (r *queryResolver) Servers(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -24,6 +24,7 @@ func (r *Resolver) ServerStats(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -24,6 +24,7 @@ func (r *queryResolver) Tribes(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
}) })
return list, err return list, err
} }

View File

@ -47,6 +47,7 @@ func (r *Resolver) TribeChanges(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
Server: server, Server: server,
}) })
return list, err return list, err

View File

@ -31,6 +31,7 @@ func (r *Resolver) TribeHistory(ctx context.Context,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Select: shouldSelectItems(ctx),
Server: server, Server: server,
}) })
return list, err return list, err

View File

@ -21,6 +21,7 @@ func (r *queryResolver) Versions(ctx context.Context,
Sort: sort, Sort: sort,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Select: shouldSelectItems(ctx),
Count: shouldCount(ctx), Count: shouldCount(ctx),
}) })
return list, err return list, err

View File

@ -30,6 +30,7 @@ func (r *queryResolver) Villages(ctx context.Context,
Sort: sort, Sort: sort,
Limit: utils.SafeIntPointer(limit, 0), Limit: utils.SafeIntPointer(limit, 0),
Offset: utils.SafeIntPointer(offset, 0), Offset: utils.SafeIntPointer(offset, 0),
Select: shouldSelectItems(ctx),
Count: shouldCount(ctx), Count: shouldCount(ctx),
Server: server, Server: server,
}) })

View File

@ -29,6 +29,7 @@ func DataLoadersToContext(dltcc DataLoadersToContextConfig, cfg dataloaders.Conf
versionDataLoaders := make(map[models.VersionCode]*dataloaders.VersionDataLoaders) versionDataLoaders := make(map[models.VersionCode]*dataloaders.VersionDataLoaders)
servers, _, err := dltcc.ServerRepo.Fetch(c.Request.Context(), server.FetchConfig{ servers, _, err := dltcc.ServerRepo.Fetch(c.Request.Context(), server.FetchConfig{
Columns: []string{utils.Underscore("versionCode"), "key"}, Columns: []string{utils.Underscore("versionCode"), "key"},
Select: true,
}) })
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, &gqlerror.Error{ c.JSON(http.StatusInternalServerError, &gqlerror.Error{

View File

@ -16,13 +16,13 @@ type NetworksAndIps struct {
} }
func (networksAndIps NetworksAndIps) Contains(ip net.IP) bool { func (networksAndIps NetworksAndIps) Contains(ip net.IP) bool {
for _, expectedIP := range networksAndIps.Ips { for _, whitelistedIP := range networksAndIps.Ips {
if expectedIP.Equal(ip) { if whitelistedIP.Equal(ip) {
return true return true
} }
} }
for _, subnetwork := range networksAndIps.Networks { for _, network := range networksAndIps.Networks {
if subnetwork.Contains(ip) { if network.Contains(ip) {
return true return true
} }
} }
@ -43,7 +43,10 @@ func (cfg LimitWhitelistConfig) GetNetworksAndIps() NetworksAndIps {
continue continue
} }
ips = append(ips, net.ParseIP(ip)) parsed := net.ParseIP(ip)
if parsed != nil {
ips = append(ips, parsed)
}
} }
return NetworksAndIps{ return NetworksAndIps{
Networks: networks, Networks: networks,

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.PlayerFilter Filter *models.PlayerFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -39,10 +39,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg player.FetchConfig) ([]
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -37,8 +37,9 @@ func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*mode
Filter: &models.PlayerFilter{ Filter: &models.PlayerFilter{
ID: []int{id}, ID: []int{id},
}, },
Limit: 1, Limit: 1,
Count: false, Count: false,
Select: true,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -10,6 +10,7 @@ type FetchConfig struct {
Server string Server string
Filter *models.PlayerHistoryFilter Filter *models.PlayerHistoryFilter
Count bool Count bool
Select bool
Sort []string Sort []string
Limit int Limit int
Offset int Offset int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg playerhistory.FetchConf
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Filter *models.ServerFilter Filter *models.ServerFilter
Columns []string Columns []string
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -41,10 +41,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg server.FetchConfig) ([]
query = query.Column(cfg.Columns...) query = query.Column(cfg.Columns...)
} }
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
return nil, 0, fmt.Errorf("Internal server error") return nil, 0, fmt.Errorf("Internal server error")

View File

@ -34,8 +34,9 @@ func (ucase *usecase) GetByKey(ctx context.Context, key string) (*models.Server,
Filter: &models.ServerFilter{ Filter: &models.ServerFilter{
Key: []string{key}, Key: []string{key},
}, },
Limit: 1, Limit: 1,
Count: false, Count: false,
Select: true,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -32,38 +32,14 @@ func New(villageRepo village.Repository) servermap.Usecase {
func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersConfig) ([]*generator.Marker, error) { func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersConfig) ([]*generator.Marker, error) {
g := new(errgroup.Group) g := new(errgroup.Group)
tribes := make(map[string][]int) tribes, tribeIDs, err := toMarkers(cfg.Tribes)
tribeIDs := []int{} if err != nil {
cache := make(map[int]bool) return nil, err
for _, data := range cfg.Tribes {
//id,#color
id, color, err := parseMarker(data)
if err != nil {
return nil, errors.Wrapf(err, "tribe=%s", data)
}
if ok := cache[id]; ok || color == "" {
continue
}
tribeIDs = append(tribeIDs, id)
cache[id] = true
tribes[color] = append(tribes[color], id)
} }
players := make(map[string][]int) players, playerIDs, err := toMarkers(cfg.Players)
playerIDs := []int{} if err != nil {
cache = make(map[int]bool) return nil, err
for _, data := range cfg.Players {
//id,#color
id, color, err := parseMarker(data)
if err != nil {
return nil, errors.Wrapf(err, "player=%s", data)
}
if ok := cache[id]; ok || color == "" {
continue
}
playerIDs = append(playerIDs, id)
cache[id] = true
players[color] = append(players[color], id)
} }
otherMarkers := []*generator.Marker{} otherMarkers := []*generator.Marker{}
@ -82,6 +58,7 @@ func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersCo
TribeIDNEQ: tribeIDs, TribeIDNEQ: tribeIDs,
}, },
}, },
Select: true,
Columns: []string{"x", "y"}, Columns: []string{"x", "y"},
Count: false, Count: false,
}) })
@ -108,6 +85,7 @@ func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersCo
Filter: &models.VillageFilter{ Filter: &models.VillageFilter{
PlayerID: []int{0}, PlayerID: []int{0},
}, },
Select: true,
Columns: []string{"x", "y"}, Columns: []string{"x", "y"},
Count: false, Count: false,
}) })
@ -138,6 +116,7 @@ func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersCo
TribeID: ids, TribeID: ids,
}, },
}, },
Select: true,
Columns: []string{"x", "y"}, Columns: []string{"x", "y"},
Count: false, Count: false,
}) })
@ -166,6 +145,7 @@ func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersCo
Filter: &models.VillageFilter{ Filter: &models.VillageFilter{
PlayerID: ids, PlayerID: ids,
}, },
Select: true,
Columns: []string{"x", "y"}, Columns: []string{"x", "y"},
Count: false, Count: false,
}) })
@ -183,14 +163,17 @@ func (ucase *usecase) GetMarkers(ctx context.Context, cfg servermap.GetMarkersCo
}) })
} }
err := g.Wait() err = g.Wait()
if err != nil {
return nil, err
}
sort.SliceStable(playerMarkers, func(i, j int) bool { sort.SliceStable(playerMarkers, func(i, j int) bool {
return len(playerMarkers[i].Villages) < len(playerMarkers[j].Villages) return len(playerMarkers[i].Villages) < len(playerMarkers[j].Villages)
}) })
sort.SliceStable(tribeMarkers, func(i, j int) bool { sort.SliceStable(tribeMarkers, func(i, j int) bool {
return len(tribeMarkers[i].Villages) < len(tribeMarkers[j].Villages) return len(tribeMarkers[i].Villages) < len(tribeMarkers[j].Villages)
}) })
return concatMarkers(otherMarkers, tribeMarkers, playerMarkers), err return concatMarkers(otherMarkers, tribeMarkers, playerMarkers), nil
} }
func concatMarkers(slices ...[]*generator.Marker) []*generator.Marker { func concatMarkers(slices ...[]*generator.Marker) []*generator.Marker {
@ -206,14 +189,14 @@ func concatMarkers(slices ...[]*generator.Marker) []*generator.Marker {
return tmp return tmp
} }
func parseMarker(str string) (int, string, error) { func toMarker(param string) (int, string, error) {
splitted := strings.Split(str, ",") splitted := strings.Split(param, ",")
if len(splitted) != 2 { if len(splitted) != 2 {
return 0, "", fmt.Errorf("%s: Invalid marker format (should be id,#hexcolor)", str) return 0, "", fmt.Errorf("%s: Invalid marker format (should be id,#hexcolor)", param)
} }
id, err := strconv.Atoi(splitted[0]) id, err := strconv.Atoi(splitted[0])
if err != nil { if err != nil {
return 0, "", errors.Wrapf(err, "%s: Invalid marker format (should be id,#hexcolor)", str) return 0, "", errors.Wrapf(err, "%s: Invalid marker format (should be id,#hexcolor)", param)
} }
if id <= 0 { if id <= 0 {
return 0, "", fmt.Errorf("ID should be greater than 0") return 0, "", fmt.Errorf("ID should be greater than 0")
@ -221,3 +204,23 @@ func parseMarker(str string) (int, string, error) {
return id, splitted[1], nil return id, splitted[1], nil
} }
func toMarkers(params []string) (map[string][]int, []int, error) {
idsByColor := make(map[string][]int)
ids := []int{}
cache := make(map[int]bool)
for _, param := range params {
//id,#color
id, color, err := toMarker(param)
if err != nil {
return nil, nil, errors.Wrapf(err, "invalid param %s", param)
}
if ok := cache[id]; ok || color == "" {
continue
}
ids = append(ids, id)
cache[id] = true
idsByColor[color] = append(idsByColor[color], id)
}
return idsByColor, ids, nil
}

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.ServerStatsFilter Filter *models.ServerStatsFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -33,10 +33,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg serverstats.FetchConfig
query = query.Apply(cfg.Filter.Where) query = query.Apply(cfg.Filter.Where)
} }
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -10,6 +10,7 @@ type FetchConfig struct {
Server string Server string
Filter *models.TribeFilter Filter *models.TribeFilter
Count bool Count bool
Select bool
Sort []string Sort []string
Limit int Limit int
Offset int Offset int

View File

@ -34,10 +34,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg tribe.FetchConfig) ([]*
query = query.Apply(cfg.Filter.Where) query = query.Apply(cfg.Filter.Where)
} }
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -39,6 +39,7 @@ func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*mode
Limit: 1, Limit: 1,
Server: server, Server: server,
Count: false, Count: false,
Select: true,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -10,6 +10,7 @@ type FetchConfig struct {
Server string Server string
Filter *models.TribeChangeFilter Filter *models.TribeChangeFilter
Count bool Count bool
Select bool
Sort []string Sort []string
Limit int Limit int
Offset int Offset int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg tribechange.FetchConfig
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -9,6 +9,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Server string Server string
Filter *models.TribeHistoryFilter Filter *models.TribeHistoryFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg tribehistory.FetchConfi
} }
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -8,6 +8,7 @@ import (
type FetchConfig struct { type FetchConfig struct {
Filter *models.VersionFilter Filter *models.VersionFilter
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -38,10 +38,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg version.FetchConfig) ([
query = query.Apply(cfg.Filter.Where) query = query.Apply(cfg.Filter.Where)
} }
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
return nil, 0, fmt.Errorf("Internal server error") return nil, 0, fmt.Errorf("Internal server error")

View File

@ -38,7 +38,9 @@ func (ucase *usecase) GetByCode(ctx context.Context, code models.VersionCode) (*
Filter: &models.VersionFilter{ Filter: &models.VersionFilter{
Code: []models.VersionCode{code}, Code: []models.VersionCode{code},
}, },
Limit: 1, Limit: 1,
Select: true,
Count: false,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -10,6 +10,7 @@ type FetchConfig struct {
Server string Server string
Filter *models.VillageFilter Filter *models.VillageFilter
Columns []string Columns []string
Select bool
Count bool Count bool
Sort []string Sort []string
Limit int Limit int

View File

@ -41,10 +41,12 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg village.FetchConfig) ([
query = query.Apply(relationshipAndSortAppender.Append) query = query.Apply(relationshipAndSortAppender.Append)
total := 0 total := 0
if cfg.Count { if cfg.Count && cfg.Select {
total, err = query.SelectAndCount() total, err = query.SelectAndCount()
} else { } else if cfg.Select {
err = query.Select() err = query.Select()
} else if cfg.Count {
total, err = query.Count()
} }
if err != nil && err != pg.ErrNoRows { if err != nil && err != pg.ErrNoRows {
if strings.Contains(err.Error(), `relation "`+cfg.Server) { if strings.Contains(err.Error(), `relation "`+cfg.Server) {

View File

@ -37,6 +37,8 @@ func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*mode
}, },
Limit: 1, Limit: 1,
Server: server, Server: server,
Select: true,
Count: false,
}) })
if err != nil { if err != nil {
return nil, err return nil, err