commit
fff51c8a05
5
dailyplayerstats/constants.go
Normal file
5
dailyplayerstats/constants.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package dailyplayerstats
|
||||||
|
|
||||||
|
const (
|
||||||
|
PaginationLimit = 500
|
||||||
|
)
|
17
dailyplayerstats/repository.go
Normal file
17
dailyplayerstats/repository.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package dailyplayerstats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FetchConfig struct {
|
||||||
|
Server string
|
||||||
|
Filter *models.DailyPlayerStatsFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.DailyPlayerStats, int, error)
|
||||||
|
}
|
52
dailyplayerstats/repository/pg_repository.go
Normal file
52
dailyplayerstats/repository/pg_repository.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-pg/pg/v10"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tribalwarshelp/api/dailyplayerstats"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pgRepository struct {
|
||||||
|
*pg.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPGRepository(db *pg.DB) dailyplayerstats.Repository {
|
||||||
|
return &pgRepository{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg dailyplayerstats.FetchConfig) ([]*models.DailyPlayerStats, int, error) {
|
||||||
|
var err error
|
||||||
|
data := []*models.DailyPlayerStats{}
|
||||||
|
total := 0
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
|
if cfg.Filter != nil {
|
||||||
|
query = query.
|
||||||
|
WhereStruct(cfg.Filter).
|
||||||
|
Limit(cfg.Filter.Limit).
|
||||||
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
|
if cfg.Filter.Sort != "" {
|
||||||
|
query = query.Order(cfg.Filter.Sort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
|
if err != nil && err != pg.ErrNoRows {
|
||||||
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
|
}
|
||||||
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, total, nil
|
||||||
|
}
|
11
dailyplayerstats/usecase.go
Normal file
11
dailyplayerstats/usecase.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package dailyplayerstats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Usecase interface {
|
||||||
|
Fetch(ctx context.Context, server string, filter *models.DailyPlayerStatsFilter) ([]*models.DailyPlayerStats, int, error)
|
||||||
|
}
|
32
dailyplayerstats/usecase/dailyplayerstats_usecase.go
Normal file
32
dailyplayerstats/usecase/dailyplayerstats_usecase.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/dailyplayerstats"
|
||||||
|
"github.com/tribalwarshelp/api/utils"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type usecase struct {
|
||||||
|
repo dailyplayerstats.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo dailyplayerstats.Repository) dailyplayerstats.Usecase {
|
||||||
|
return &usecase{repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.DailyPlayerStatsFilter) ([]*models.DailyPlayerStats, int, error) {
|
||||||
|
if filter == nil {
|
||||||
|
filter = &models.DailyPlayerStatsFilter{}
|
||||||
|
}
|
||||||
|
if filter.Limit > dailyplayerstats.PaginationLimit || filter.Limit <= 0 {
|
||||||
|
filter.Limit = dailyplayerstats.PaginationLimit
|
||||||
|
}
|
||||||
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
|
return ucase.repo.Fetch(ctx, dailyplayerstats.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
|
}
|
5
dailytribestats/constants.go
Normal file
5
dailytribestats/constants.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package dailytribestats
|
||||||
|
|
||||||
|
const (
|
||||||
|
PaginationLimit = 500
|
||||||
|
)
|
17
dailytribestats/repository.go
Normal file
17
dailytribestats/repository.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package dailytribestats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FetchConfig struct {
|
||||||
|
Server string
|
||||||
|
Filter *models.DailyTribeStatsFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.DailyTribeStats, int, error)
|
||||||
|
}
|
52
dailytribestats/repository/pg_repository.go
Normal file
52
dailytribestats/repository/pg_repository.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-pg/pg/v10"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tribalwarshelp/api/dailytribestats"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pgRepository struct {
|
||||||
|
*pg.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPGRepository(db *pg.DB) dailytribestats.Repository {
|
||||||
|
return &pgRepository{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg dailytribestats.FetchConfig) ([]*models.DailyTribeStats, int, error) {
|
||||||
|
var err error
|
||||||
|
data := []*models.DailyTribeStats{}
|
||||||
|
total := 0
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
|
if cfg.Filter != nil {
|
||||||
|
query = query.
|
||||||
|
WhereStruct(cfg.Filter).
|
||||||
|
Limit(cfg.Filter.Limit).
|
||||||
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
|
if cfg.Filter.Sort != "" {
|
||||||
|
query = query.Order(cfg.Filter.Sort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
|
if err != nil && err != pg.ErrNoRows {
|
||||||
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
|
}
|
||||||
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, total, nil
|
||||||
|
}
|
11
dailytribestats/usecase.go
Normal file
11
dailytribestats/usecase.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package dailytribestats
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Usecase interface {
|
||||||
|
Fetch(ctx context.Context, server string, filter *models.DailyTribeStatsFilter) ([]*models.DailyTribeStats, int, error)
|
||||||
|
}
|
32
dailytribestats/usecase/dailytribestats_usecase.go
Normal file
32
dailytribestats/usecase/dailytribestats_usecase.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/dailytribestats"
|
||||||
|
"github.com/tribalwarshelp/api/utils"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type usecase struct {
|
||||||
|
repo dailytribestats.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo dailytribestats.Repository) dailytribestats.Usecase {
|
||||||
|
return &usecase{repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.DailyTribeStatsFilter) ([]*models.DailyTribeStats, int, error) {
|
||||||
|
if filter == nil {
|
||||||
|
filter = &models.DailyTribeStatsFilter{}
|
||||||
|
}
|
||||||
|
if filter.Limit > dailytribestats.PaginationLimit || filter.Limit <= 0 {
|
||||||
|
filter.Limit = dailytribestats.PaginationLimit
|
||||||
|
}
|
||||||
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
|
return ucase.repo.Fetch(ctx, dailytribestats.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,6 +6,12 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.EnnoblementFilter) ([]*models.Ennoblement, int, error)
|
Server string
|
||||||
|
Filter *models.EnnoblementFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Ennoblement, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,30 @@ func NewPGRepository(db *pg.DB) ennoblement.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.EnnoblementFilter) ([]*models.Ennoblement, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg ennoblement.FetchConfig) ([]*models.Ennoblement, int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
total := 0
|
||||||
data := []*models.Ennoblement{}
|
data := []*models.Ennoblement{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
|
|
@ -24,5 +24,9 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.E
|
||||||
filter.Limit = ennoblement.PaginationLimit
|
filter.Limit = ennoblement.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, ennoblement.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -14,7 +14,7 @@ require (
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/segmentio/encoding v0.1.14 // indirect
|
github.com/segmentio/encoding v0.1.14 // indirect
|
||||||
github.com/tribalwarshelp/map-generator v0.0.0-20200623143352-cc037d744be2
|
github.com/tribalwarshelp/map-generator v0.0.0-20200623143352-cc037d744be2
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200623144748-aa834a01dce6
|
github.com/tribalwarshelp/shared v0.0.0-20200625131045-74c5a9b3b4f0
|
||||||
github.com/vektah/gqlparser/v2 v2.0.1
|
github.com/vektah/gqlparser/v2 v2.0.1
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -175,16 +175,23 @@ github.com/tribalwarshelp/map-generator v0.0.0-20200623143352-cc037d744be2 h1:jk
|
||||||
github.com/tribalwarshelp/map-generator v0.0.0-20200623143352-cc037d744be2/go.mod h1:h3INS/arc4MelQjePKvXdrqWjHVVm2s4PKSrsMmkZx8=
|
github.com/tribalwarshelp/map-generator v0.0.0-20200623143352-cc037d744be2/go.mod h1:h3INS/arc4MelQjePKvXdrqWjHVVm2s4PKSrsMmkZx8=
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200622084436-3a768c8bf574 h1:y2EoH6zRK9Uc0AeswnJRYUUIQYcSLZB5VDFuxPCKxNM=
|
github.com/tribalwarshelp/shared v0.0.0-20200622084436-3a768c8bf574 h1:y2EoH6zRK9Uc0AeswnJRYUUIQYcSLZB5VDFuxPCKxNM=
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200622084436-3a768c8bf574/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
github.com/tribalwarshelp/shared v0.0.0-20200622084436-3a768c8bf574/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200623082627-128bf01a6570 h1:W2cBKRRvr1QLG2GzuJFuvtVe0dblHkkb+E2SlbdJBHo=
|
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200623082627-128bf01a6570/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200623144748-aa834a01dce6 h1:WZ1oxHysFtiPjHa2ADUqiGrzwcN3j0YpiVg/V2e/74o=
|
github.com/tribalwarshelp/shared v0.0.0-20200623144748-aa834a01dce6 h1:WZ1oxHysFtiPjHa2ADUqiGrzwcN3j0YpiVg/V2e/74o=
|
||||||
github.com/tribalwarshelp/shared v0.0.0-20200623144748-aa834a01dce6/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
github.com/tribalwarshelp/shared v0.0.0-20200623144748-aa834a01dce6/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200624131453-e04f1de1bf5c h1:sPu2tYRqZYAFwhJtZ4cDWLwanauQ4+4zlGEgdQNrVn4=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200624131453-e04f1de1bf5c/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200624134544-636239c5fd17 h1:DUMz3ROe2nYRszZuu97LVIgdPrt8QBWAVouFlrucL8c=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200624134544-636239c5fd17/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200625120510-6d18ee334662 h1:GBCpdHQsOrbz7xz+bTsZlFQJzKi1wsxgAeVFsNIZiH4=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200625120510-6d18ee334662/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200625131045-74c5a9b3b4f0 h1:k1j0Nh2OIr1fTrCrbznjPAH+eRVpB3HYXM1sHErrayg=
|
||||||
|
github.com/tribalwarshelp/shared v0.0.0-20200625131045-74c5a9b3b4f0/go.mod h1:tf+2yTHasV6jAF3V2deZ9slNoCyBzC0fMdTjI7clf6Y=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
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 v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||||
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
|
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
|
||||||
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
||||||
|
|
|
@ -12,8 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataLoaders struct {
|
type DataLoaders struct {
|
||||||
LangVersionByTag LangVersionLoader
|
LangVersionByTag LangVersionLoader
|
||||||
PlayerServersByID PlayerServersLoader
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -23,7 +22,7 @@ type Config struct {
|
||||||
LangVersionRepo langversion.Repository
|
LangVersionRepo langversion.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg Config) *DataLoaders {
|
func NewDataLoaders(cfg Config) *DataLoaders {
|
||||||
return &DataLoaders{
|
return &DataLoaders{
|
||||||
LangVersionByTag: LangVersionLoader{
|
LangVersionByTag: LangVersionLoader{
|
||||||
wait: 2 * time.Millisecond,
|
wait: 2 * time.Millisecond,
|
||||||
|
@ -33,8 +32,10 @@ func New(cfg Config) *DataLoaders {
|
||||||
for _, tag := range keys {
|
for _, tag := range keys {
|
||||||
tags = append(tags, models.LanguageTag(tag))
|
tags = append(tags, models.LanguageTag(tag))
|
||||||
}
|
}
|
||||||
langVersions, _, err := cfg.LangVersionRepo.Fetch(context.Background(), &models.LangVersionFilter{
|
langVersions, _, err := cfg.LangVersionRepo.Fetch(context.Background(), langversion.FetchConfig{
|
||||||
Tag: tags,
|
Filter: &models.LangVersionFilter{
|
||||||
|
Tag: tags,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{err}
|
return nil, []error{err}
|
||||||
|
@ -53,20 +54,5 @@ func New(cfg Config) *DataLoaders {
|
||||||
return inOrder, nil
|
return inOrder, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PlayerServersByID: PlayerServersLoader{
|
|
||||||
wait: 2 * time.Millisecond,
|
|
||||||
maxBatch: 0,
|
|
||||||
fetch: func(keys []int) ([][]string, []error) {
|
|
||||||
playerServersByID, err := cfg.PlayerRepo.FetchPlayerServers(context.Background(), keys...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, []error{err}
|
|
||||||
}
|
|
||||||
inOrder := make([][]string, len(keys))
|
|
||||||
for i, id := range keys {
|
|
||||||
inOrder[i] = playerServersByID[id]
|
|
||||||
}
|
|
||||||
return inOrder, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
graphql/dataloaders/lang_version_data_loaders.go
Normal file
48
graphql/dataloaders/lang_version_data_loaders.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package dataloaders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LangVersionDataLoaders struct {
|
||||||
|
PlayerServersByID PlayerServersLoader
|
||||||
|
PlayerNameChangesByID PlayerNameChangesLoader
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLangVersionDataLoaders(langTag models.LanguageTag, cfg Config) *LangVersionDataLoaders {
|
||||||
|
return &LangVersionDataLoaders{
|
||||||
|
PlayerServersByID: PlayerServersLoader{
|
||||||
|
wait: 2 * time.Millisecond,
|
||||||
|
maxBatch: 0,
|
||||||
|
fetch: func(keys []int) ([][]string, []error) {
|
||||||
|
playerServersByID, err := cfg.PlayerRepo.FetchPlayerServers(context.Background(), langTag, keys...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, []error{err}
|
||||||
|
}
|
||||||
|
inOrder := make([][]string, len(keys))
|
||||||
|
for i, id := range keys {
|
||||||
|
inOrder[i] = playerServersByID[id]
|
||||||
|
}
|
||||||
|
return inOrder, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PlayerNameChangesByID: PlayerNameChangesLoader{
|
||||||
|
wait: 2 * time.Millisecond,
|
||||||
|
maxBatch: 0,
|
||||||
|
fetch: func(keys []int) ([][]*models.PlayerNameChange, []error) {
|
||||||
|
playerNameChangesByID, err := cfg.PlayerRepo.FetchNameChanges(context.Background(), langTag, keys...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, []error{err}
|
||||||
|
}
|
||||||
|
inOrder := make([][]*models.PlayerNameChange, len(keys))
|
||||||
|
for i, id := range keys {
|
||||||
|
inOrder[i] = playerNameChangesByID[id]
|
||||||
|
}
|
||||||
|
return inOrder, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
225
graphql/dataloaders/playernamechangesloader_gen.go
Normal file
225
graphql/dataloaders/playernamechangesloader_gen.go
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
// Code generated by github.com/vektah/dataloaden, DO NOT EDIT.
|
||||||
|
|
||||||
|
package dataloaders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlayerNameChangesLoaderConfig captures the config to create a new PlayerNameChangesLoader
|
||||||
|
type PlayerNameChangesLoaderConfig struct {
|
||||||
|
// Fetch is a method that provides the data for the loader
|
||||||
|
Fetch func(keys []int) ([][]*models.PlayerNameChange, []error)
|
||||||
|
|
||||||
|
// Wait is how long wait before sending a batch
|
||||||
|
Wait time.Duration
|
||||||
|
|
||||||
|
// MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit
|
||||||
|
MaxBatch int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPlayerNameChangesLoader creates a new PlayerNameChangesLoader given a fetch, wait, and maxBatch
|
||||||
|
func NewPlayerNameChangesLoader(config PlayerNameChangesLoaderConfig) *PlayerNameChangesLoader {
|
||||||
|
return &PlayerNameChangesLoader{
|
||||||
|
fetch: config.Fetch,
|
||||||
|
wait: config.Wait,
|
||||||
|
maxBatch: config.MaxBatch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerNameChangesLoader batches and caches requests
|
||||||
|
type PlayerNameChangesLoader struct {
|
||||||
|
// this method provides the data for the loader
|
||||||
|
fetch func(keys []int) ([][]*models.PlayerNameChange, []error)
|
||||||
|
|
||||||
|
// how long to done before sending a batch
|
||||||
|
wait time.Duration
|
||||||
|
|
||||||
|
// this will limit the maximum number of keys to send in one batch, 0 = no limit
|
||||||
|
maxBatch int
|
||||||
|
|
||||||
|
// INTERNAL
|
||||||
|
|
||||||
|
// lazily created cache
|
||||||
|
cache map[int][]*models.PlayerNameChange
|
||||||
|
|
||||||
|
// the current batch. keys will continue to be collected until timeout is hit,
|
||||||
|
// then everything will be sent to the fetch method and out to the listeners
|
||||||
|
batch *playerNameChangesLoaderBatch
|
||||||
|
|
||||||
|
// mutex to prevent races
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type playerNameChangesLoaderBatch struct {
|
||||||
|
keys []int
|
||||||
|
data [][]*models.PlayerNameChange
|
||||||
|
error []error
|
||||||
|
closing bool
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a PlayerNameChange by key, batching and caching will be applied automatically
|
||||||
|
func (l *PlayerNameChangesLoader) Load(key int) ([]*models.PlayerNameChange, error) {
|
||||||
|
return l.LoadThunk(key)()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadThunk returns a function that when called will block waiting for a PlayerNameChange.
|
||||||
|
// This method should be used if you want one goroutine to make requests to many
|
||||||
|
// different data loaders without blocking until the thunk is called.
|
||||||
|
func (l *PlayerNameChangesLoader) LoadThunk(key int) func() ([]*models.PlayerNameChange, error) {
|
||||||
|
l.mu.Lock()
|
||||||
|
if it, ok := l.cache[key]; ok {
|
||||||
|
l.mu.Unlock()
|
||||||
|
return func() ([]*models.PlayerNameChange, error) {
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.batch == nil {
|
||||||
|
l.batch = &playerNameChangesLoaderBatch{done: make(chan struct{})}
|
||||||
|
}
|
||||||
|
batch := l.batch
|
||||||
|
pos := batch.keyIndex(l, key)
|
||||||
|
l.mu.Unlock()
|
||||||
|
|
||||||
|
return func() ([]*models.PlayerNameChange, error) {
|
||||||
|
<-batch.done
|
||||||
|
|
||||||
|
var data []*models.PlayerNameChange
|
||||||
|
if pos < len(batch.data) {
|
||||||
|
data = batch.data[pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
// its convenient to be able to return a single error for everything
|
||||||
|
if len(batch.error) == 1 {
|
||||||
|
err = batch.error[0]
|
||||||
|
} else if batch.error != nil {
|
||||||
|
err = batch.error[pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
l.mu.Lock()
|
||||||
|
l.unsafeSet(key, data)
|
||||||
|
l.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAll fetches many keys at once. It will be broken into appropriate sized
|
||||||
|
// sub batches depending on how the loader is configured
|
||||||
|
func (l *PlayerNameChangesLoader) LoadAll(keys []int) ([][]*models.PlayerNameChange, []error) {
|
||||||
|
results := make([]func() ([]*models.PlayerNameChange, error), len(keys))
|
||||||
|
|
||||||
|
for i, key := range keys {
|
||||||
|
results[i] = l.LoadThunk(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
playerNameChanges := make([][]*models.PlayerNameChange, len(keys))
|
||||||
|
errors := make([]error, len(keys))
|
||||||
|
for i, thunk := range results {
|
||||||
|
playerNameChanges[i], errors[i] = thunk()
|
||||||
|
}
|
||||||
|
return playerNameChanges, errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAllThunk returns a function that when called will block waiting for a PlayerNameChanges.
|
||||||
|
// This method should be used if you want one goroutine to make requests to many
|
||||||
|
// different data loaders without blocking until the thunk is called.
|
||||||
|
func (l *PlayerNameChangesLoader) LoadAllThunk(keys []int) func() ([][]*models.PlayerNameChange, []error) {
|
||||||
|
results := make([]func() ([]*models.PlayerNameChange, error), len(keys))
|
||||||
|
for i, key := range keys {
|
||||||
|
results[i] = l.LoadThunk(key)
|
||||||
|
}
|
||||||
|
return func() ([][]*models.PlayerNameChange, []error) {
|
||||||
|
playerNameChanges := make([][]*models.PlayerNameChange, len(keys))
|
||||||
|
errors := make([]error, len(keys))
|
||||||
|
for i, thunk := range results {
|
||||||
|
playerNameChanges[i], errors[i] = thunk()
|
||||||
|
}
|
||||||
|
return playerNameChanges, errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prime the cache with the provided key and value. If the key already exists, no change is made
|
||||||
|
// and false is returned.
|
||||||
|
// (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).)
|
||||||
|
func (l *PlayerNameChangesLoader) Prime(key int, value []*models.PlayerNameChange) bool {
|
||||||
|
l.mu.Lock()
|
||||||
|
var found bool
|
||||||
|
if _, found = l.cache[key]; !found {
|
||||||
|
// make a copy when writing to the cache, its easy to pass a pointer in from a loop var
|
||||||
|
// and end up with the whole cache pointing to the same value.
|
||||||
|
cpy := make([]*models.PlayerNameChange, len(value))
|
||||||
|
copy(cpy, value)
|
||||||
|
l.unsafeSet(key, cpy)
|
||||||
|
}
|
||||||
|
l.mu.Unlock()
|
||||||
|
return !found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the value at key from the cache, if it exists
|
||||||
|
func (l *PlayerNameChangesLoader) Clear(key int) {
|
||||||
|
l.mu.Lock()
|
||||||
|
delete(l.cache, key)
|
||||||
|
l.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *PlayerNameChangesLoader) unsafeSet(key int, value []*models.PlayerNameChange) {
|
||||||
|
if l.cache == nil {
|
||||||
|
l.cache = map[int][]*models.PlayerNameChange{}
|
||||||
|
}
|
||||||
|
l.cache[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyIndex will return the location of the key in the batch, if its not found
|
||||||
|
// it will add the key to the batch
|
||||||
|
func (b *playerNameChangesLoaderBatch) keyIndex(l *PlayerNameChangesLoader, key int) int {
|
||||||
|
for i, existingKey := range b.keys {
|
||||||
|
if key == existingKey {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := len(b.keys)
|
||||||
|
b.keys = append(b.keys, key)
|
||||||
|
if pos == 0 {
|
||||||
|
go b.startTimer(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.maxBatch != 0 && pos >= l.maxBatch-1 {
|
||||||
|
if !b.closing {
|
||||||
|
b.closing = true
|
||||||
|
l.batch = nil
|
||||||
|
go b.end(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *playerNameChangesLoaderBatch) startTimer(l *PlayerNameChangesLoader) {
|
||||||
|
time.Sleep(l.wait)
|
||||||
|
l.mu.Lock()
|
||||||
|
|
||||||
|
// we must have hit a batch limit and are already finalizing this batch
|
||||||
|
if b.closing {
|
||||||
|
l.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.batch = nil
|
||||||
|
l.mu.Unlock()
|
||||||
|
|
||||||
|
b.end(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *playerNameChangesLoaderBatch) end(l *PlayerNameChangesLoader) {
|
||||||
|
b.data, b.error = l.fetch(b.keys)
|
||||||
|
close(b.done)
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/player"
|
||||||
|
"github.com/tribalwarshelp/api/tribe"
|
||||||
"github.com/tribalwarshelp/api/village"
|
"github.com/tribalwarshelp/api/village"
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
@ -20,8 +22,11 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
|
||||||
wait: 2 * time.Millisecond,
|
wait: 2 * time.Millisecond,
|
||||||
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(), server, &models.PlayerFilter{
|
players, _, err := cfg.PlayerRepo.Fetch(context.Background(), player.FetchConfig{
|
||||||
ID: ids,
|
Filter: &models.PlayerFilter{
|
||||||
|
ID: ids,
|
||||||
|
},
|
||||||
|
Server: server,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{err}
|
return nil, []error{err}
|
||||||
|
@ -44,8 +49,11 @@ func NewServerDataLoaders(server string, cfg Config) *ServerDataLoaders {
|
||||||
wait: 2 * time.Millisecond,
|
wait: 2 * time.Millisecond,
|
||||||
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(), server, &models.TribeFilter{
|
tribes, _, err := cfg.TribeRepo.Fetch(context.Background(), tribe.FetchConfig{
|
||||||
ID: ids,
|
Server: server,
|
||||||
|
Filter: &models.TribeFilter{
|
||||||
|
ID: ids,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{err}
|
return nil, []error{err}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,6 +6,16 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DailyPlayerStats struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Items []*models.DailyPlayerStats `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DailyTribeStats struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Items []*models.DailyTribeStats `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
type EnnoblementsList struct {
|
type EnnoblementsList struct {
|
||||||
Items []*models.Ennoblement `json:"items"`
|
Items []*models.Ennoblement `json:"items"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
|
@ -36,6 +46,11 @@ type ServersList struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TribeChanges struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Items []*models.TribeChange `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
type TribeHistory struct {
|
type TribeHistory struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
Items []*models.TribeHistory `json:"items"`
|
Items []*models.TribeHistory `json:"items"`
|
||||||
|
|
|
@ -90,3 +90,17 @@ models:
|
||||||
model: github.com/tribalwarshelp/shared/models.ServerStats
|
model: github.com/tribalwarshelp/shared/models.ServerStats
|
||||||
ServerStatsFilter:
|
ServerStatsFilter:
|
||||||
model: github.com/tribalwarshelp/shared/models.ServerStatsFilter
|
model: github.com/tribalwarshelp/shared/models.ServerStatsFilter
|
||||||
|
TribeChangeRecord:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.TribeChange
|
||||||
|
TribeChangeFilter:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.TribeChangeFilter
|
||||||
|
DailyPlayerStatsRecord:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.DailyPlayerStats
|
||||||
|
DailyPlayerStatsFilter:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.DailyPlayerStatsFilter
|
||||||
|
DailyTribeStatsRecord:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.DailyTribeStats
|
||||||
|
DailyTribeStatsFilter:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.DailyTribeStatsFilter
|
||||||
|
PlayerNameChange:
|
||||||
|
model: github.com/tribalwarshelp/shared/models.PlayerNameChange
|
||||||
|
|
23
graphql/resolvers/daily_player_stats.go
Normal file
23
graphql/resolvers/daily_player_stats.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *dailyPlayerStatsRecordResolver) Player(ctx context.Context, obj *models.DailyPlayerStats) (*models.Player, error) {
|
||||||
|
if obj.Player != nil {
|
||||||
|
return obj.Player, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPlayer(ctx, obj.PlayerID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *queryResolver) DailyPlayerStats(ctx context.Context, server string, filter *models.DailyPlayerStatsFilter) (*generated.DailyPlayerStats, error) {
|
||||||
|
var err error
|
||||||
|
list := &generated.DailyPlayerStats{}
|
||||||
|
list.Items, list.Total, err = r.DailyPlayerStatsUcase.Fetch(ctx, server, filter)
|
||||||
|
return list, err
|
||||||
|
}
|
23
graphql/resolvers/daily_tribe_stats.go
Normal file
23
graphql/resolvers/daily_tribe_stats.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *dailyTribeStatsRecordResolver) Tribe(ctx context.Context, obj *models.DailyTribeStats) (*models.Tribe, error) {
|
||||||
|
if obj.Tribe != nil {
|
||||||
|
return obj.Tribe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTribe(ctx, obj.TribeID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *queryResolver) DailyTribeStats(ctx context.Context, server string, filter *models.DailyTribeStatsFilter) (*generated.DailyTribeStats, error) {
|
||||||
|
var err error
|
||||||
|
list := &generated.DailyTribeStats{}
|
||||||
|
list.Items, list.Total, err = r.DailyTribeStatsUcase.Fetch(ctx, server, filter)
|
||||||
|
return list, err
|
||||||
|
}
|
|
@ -2,9 +2,6 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
@ -50,12 +47,6 @@ func (r *ennoblementResolver) Village(ctx context.Context, obj *models.Ennobleme
|
||||||
return getVillage(ctx, obj.VillageID), nil
|
return getVillage(ctx, obj.VillageID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ennoblementResolver) EnnobledAt(ctx context.Context, obj *models.Ennoblement) (*time.Time, error) {
|
|
||||||
server, _ := getServer(ctx)
|
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.EnnobledAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *queryResolver) Ennoblements(ctx context.Context, server string, f *models.EnnoblementFilter) (*generated.EnnoblementsList, error) {
|
func (r *queryResolver) Ennoblements(ctx context.Context, server string, f *models.EnnoblementFilter) (*generated.EnnoblementsList, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.EnnoblementsList{}
|
list := &generated.EnnoblementsList{}
|
||||||
|
|
|
@ -2,11 +2,9 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
"github.com/tribalwarshelp/api/middleware"
|
"github.com/tribalwarshelp/api/middleware"
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,14 +66,3 @@ func getTribe(ctx context.Context, id int) *models.Tribe {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatDate(ctx context.Context, langTag models.LanguageTag, t time.Time) time.Time {
|
|
||||||
loaders := middleware.DataLoadersFromContext(ctx)
|
|
||||||
if loaders != nil {
|
|
||||||
lv, err := loaders.LangVersionByTag.Load(langTag.String())
|
|
||||||
if err == nil {
|
|
||||||
return t.In(utils.GetLocation(lv.Timezone))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/middleware"
|
"github.com/tribalwarshelp/api/middleware"
|
||||||
|
@ -19,20 +18,31 @@ func (r *playerResolver) Tribe(ctx context.Context, obj *models.Player) (*models
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *playerResolver) Servers(ctx context.Context, obj *models.Player) ([]string, error) {
|
func (r *playerResolver) Servers(ctx context.Context, obj *models.Player) ([]string, error) {
|
||||||
loaders := middleware.DataLoadersFromContext(ctx)
|
langVersionDataLoaders := middleware.LangVersionDataLoadersFromContext(ctx)
|
||||||
if loaders != nil {
|
if langVersionDataLoaders != nil {
|
||||||
servers, err := loaders.PlayerServersByID.Load(obj.ID)
|
serverKey, _ := getServer(ctx)
|
||||||
if err == nil {
|
if loaders, ok := langVersionDataLoaders[utils.LanguageTagFromServerKey(serverKey)]; ok {
|
||||||
return servers, nil
|
servers, err := loaders.PlayerServersByID.Load(obj.ID)
|
||||||
|
if err == nil {
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *playerResolver) JoinedAt(ctx context.Context, obj *models.Player) (*time.Time, error) {
|
func (r *playerResolver) NameChanges(ctx context.Context, obj *models.Player) ([]*models.PlayerNameChange, error) {
|
||||||
server, _ := getServer(ctx)
|
langVersionDataLoaders := middleware.LangVersionDataLoadersFromContext(ctx)
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.JoinedAt)
|
if langVersionDataLoaders != nil {
|
||||||
return &t, nil
|
serverKey, _ := getServer(ctx)
|
||||||
|
if loaders, ok := langVersionDataLoaders[utils.LanguageTagFromServerKey(serverKey)]; ok {
|
||||||
|
servers, err := loaders.PlayerNameChangesByID.Load(obj.ID)
|
||||||
|
if err == nil {
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []*models.PlayerNameChange{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Players(ctx context.Context, server string, filter *models.PlayerFilter) (*generated.PlayersList, error) {
|
func (r *queryResolver) Players(ctx context.Context, server string, filter *models.PlayerFilter) (*generated.PlayersList, error) {
|
||||||
|
|
|
@ -2,10 +2,8 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,12 +23,6 @@ func (r *playerHistoryRecordResolver) Tribe(ctx context.Context, obj *models.Pla
|
||||||
return getTribe(ctx, obj.TribeID), nil
|
return getTribe(ctx, obj.TribeID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *playerHistoryRecordResolver) CreatedAt(ctx context.Context, obj *models.PlayerHistory) (*time.Time, error) {
|
|
||||||
server, _ := getServer(ctx)
|
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.CreatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Resolver) PlayerHistory(ctx context.Context, server string, filter *models.PlayerHistoryFilter) (*generated.PlayerHistory, error) {
|
func (r *Resolver) PlayerHistory(ctx context.Context, server string, filter *models.PlayerHistoryFilter) (*generated.PlayerHistory, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.PlayerHistory{}
|
list := &generated.PlayerHistory{}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package resolvers
|
package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/tribalwarshelp/api/dailyplayerstats"
|
||||||
|
"github.com/tribalwarshelp/api/dailytribestats"
|
||||||
"github.com/tribalwarshelp/api/ennoblement"
|
"github.com/tribalwarshelp/api/ennoblement"
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/langversion"
|
"github.com/tribalwarshelp/api/langversion"
|
||||||
|
@ -10,42 +12,51 @@ import (
|
||||||
"github.com/tribalwarshelp/api/server"
|
"github.com/tribalwarshelp/api/server"
|
||||||
"github.com/tribalwarshelp/api/serverstats"
|
"github.com/tribalwarshelp/api/serverstats"
|
||||||
"github.com/tribalwarshelp/api/tribe"
|
"github.com/tribalwarshelp/api/tribe"
|
||||||
|
"github.com/tribalwarshelp/api/tribechange"
|
||||||
"github.com/tribalwarshelp/api/tribehistory"
|
"github.com/tribalwarshelp/api/tribehistory"
|
||||||
"github.com/tribalwarshelp/api/village"
|
"github.com/tribalwarshelp/api/village"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
LangVersionUcase langversion.Usecase
|
LangVersionUcase langversion.Usecase
|
||||||
ServerUcase server.Usecase
|
ServerUcase server.Usecase
|
||||||
PlayerUcase player.Usecase
|
PlayerUcase player.Usecase
|
||||||
TribeUcase tribe.Usecase
|
TribeUcase tribe.Usecase
|
||||||
VillageUcase village.Usecase
|
VillageUcase village.Usecase
|
||||||
LiveEnnoblementUcase liveennoblement.Usecase
|
LiveEnnoblementUcase liveennoblement.Usecase
|
||||||
EnnoblementUcase ennoblement.Usecase
|
EnnoblementUcase ennoblement.Usecase
|
||||||
PlayerHistoryUcase playerhistory.Usecase
|
PlayerHistoryUcase playerhistory.Usecase
|
||||||
TribeHistoryUcase tribehistory.Usecase
|
TribeHistoryUcase tribehistory.Usecase
|
||||||
ServerStatsUcase serverstats.Usecase
|
ServerStatsUcase serverstats.Usecase
|
||||||
|
TribeChangeUcase tribechange.Usecase
|
||||||
|
DailyTribeStatsUcase dailytribestats.Usecase
|
||||||
|
DailyPlayerStatsUcase dailyplayerstats.Usecase
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query returns generated.QueryResolver implementation.
|
// Query returns generated.QueryResolver implementation.
|
||||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||||
func (r *Resolver) Player() generated.PlayerResolver { return &playerResolver{r} }
|
func (r *Resolver) Player() generated.PlayerResolver { return &playerResolver{r} }
|
||||||
func (r *Resolver) Village() generated.VillageResolver { return &villageResolver{r} }
|
func (r *Resolver) Village() generated.VillageResolver { return &villageResolver{r} }
|
||||||
func (r *Resolver) Tribe() generated.TribeResolver { return &tribeResolver{r} }
|
|
||||||
func (r *Resolver) LiveEnnoblement() generated.LiveEnnoblementResolver {
|
func (r *Resolver) LiveEnnoblement() generated.LiveEnnoblementResolver {
|
||||||
return &liveEnnoblementResolver{r}
|
return &liveEnnoblementResolver{r}
|
||||||
}
|
}
|
||||||
func (r *Resolver) Ennoblement() generated.EnnoblementResolver { return &ennoblementResolver{r} }
|
func (r *Resolver) Ennoblement() generated.EnnoblementResolver { return &ennoblementResolver{r} }
|
||||||
func (r *Resolver) Server() generated.ServerResolver { return &serverResolver{r} }
|
func (r *Resolver) Server() generated.ServerResolver { return &serverResolver{r} }
|
||||||
func (r *Resolver) ServerStatsRecord() generated.ServerStatsRecordResolver {
|
|
||||||
return &serverStatsRecordResolver{r}
|
|
||||||
}
|
|
||||||
func (r *Resolver) PlayerHistoryRecord() generated.PlayerHistoryRecordResolver {
|
func (r *Resolver) PlayerHistoryRecord() generated.PlayerHistoryRecordResolver {
|
||||||
return &playerHistoryRecordResolver{r}
|
return &playerHistoryRecordResolver{r}
|
||||||
}
|
}
|
||||||
func (r *Resolver) TribeHistoryRecord() generated.TribeHistoryRecordResolver {
|
func (r *Resolver) TribeHistoryRecord() generated.TribeHistoryRecordResolver {
|
||||||
return &tribeHistoryRecordResolver{r}
|
return &tribeHistoryRecordResolver{r}
|
||||||
}
|
}
|
||||||
|
func (r *Resolver) TribeChangeRecord() generated.TribeChangeRecordResolver {
|
||||||
|
return &tribeChangeRecordResolver{r}
|
||||||
|
}
|
||||||
|
func (r *Resolver) DailyPlayerStatsRecord() generated.DailyPlayerStatsRecordResolver {
|
||||||
|
return &dailyPlayerStatsRecordResolver{r}
|
||||||
|
}
|
||||||
|
func (r *Resolver) DailyTribeStatsRecord() generated.DailyTribeStatsRecordResolver {
|
||||||
|
return &dailyTribeStatsRecordResolver{r}
|
||||||
|
}
|
||||||
|
|
||||||
type queryResolver struct{ *Resolver }
|
type queryResolver struct{ *Resolver }
|
||||||
type playerResolver struct{ *Resolver }
|
type playerResolver struct{ *Resolver }
|
||||||
|
@ -57,3 +68,6 @@ type serverResolver struct{ *Resolver }
|
||||||
type playerHistoryRecordResolver struct{ *Resolver }
|
type playerHistoryRecordResolver struct{ *Resolver }
|
||||||
type tribeHistoryRecordResolver struct{ *Resolver }
|
type tribeHistoryRecordResolver struct{ *Resolver }
|
||||||
type serverStatsRecordResolver struct{ *Resolver }
|
type serverStatsRecordResolver struct{ *Resolver }
|
||||||
|
type tribeChangeRecordResolver struct{ *Resolver }
|
||||||
|
type dailyPlayerStatsRecordResolver struct{ *Resolver }
|
||||||
|
type dailyTribeStatsRecordResolver struct{ *Resolver }
|
||||||
|
|
|
@ -2,7 +2,6 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/middleware"
|
"github.com/tribalwarshelp/api/middleware"
|
||||||
|
|
||||||
|
@ -19,21 +18,6 @@ func (r *serverResolver) LangVersion(ctx context.Context, obj *models.Server) (*
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *serverResolver) DataUpdatedAt(ctx context.Context, obj *models.Server) (*time.Time, error) {
|
|
||||||
t := formatDate(ctx, obj.LangVersionTag, obj.DataUpdatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *serverResolver) HistoryUpdatedAt(ctx context.Context, obj *models.Server) (*time.Time, error) {
|
|
||||||
t := formatDate(ctx, obj.LangVersionTag, obj.HistoryUpdatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *serverResolver) StatsUpdatedAt(ctx context.Context, obj *models.Server) (*time.Time, error) {
|
|
||||||
t := formatDate(ctx, obj.LangVersionTag, obj.StatsUpdatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *queryResolver) Servers(ctx context.Context, filter *models.ServerFilter) (*generated.ServersList, error) {
|
func (r *queryResolver) Servers(ctx context.Context, filter *models.ServerFilter) (*generated.ServersList, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.ServersList{}
|
list := &generated.ServersList{}
|
||||||
|
|
|
@ -2,19 +2,11 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *serverStatsRecordResolver) CreatedAt(ctx context.Context, obj *models.ServerStats) (*time.Time, error) {
|
|
||||||
server, _ := getServer(ctx)
|
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.CreatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Resolver) ServerStats(ctx context.Context, server string, filter *models.ServerStatsFilter) (*generated.ServerStats, error) {
|
func (r *Resolver) ServerStats(ctx context.Context, server string, filter *models.ServerStatsFilter) (*generated.ServerStats, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.ServerStats{}
|
list := &generated.ServerStats{}
|
||||||
|
|
|
@ -2,19 +2,11 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *tribeResolver) CreatedAt(ctx context.Context, obj *models.Tribe) (*time.Time, error) {
|
|
||||||
server, _ := getServer(ctx)
|
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.CreatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *queryResolver) Tribes(ctx context.Context, server string, filter *models.TribeFilter) (*generated.TribesList, error) {
|
func (r *queryResolver) Tribes(ctx context.Context, server string, filter *models.TribeFilter) (*generated.TribesList, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.TribesList{}
|
list := &generated.TribesList{}
|
||||||
|
|
39
graphql/resolvers/tribe_change.go
Normal file
39
graphql/resolvers/tribe_change.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *tribeChangeRecordResolver) Player(ctx context.Context, obj *models.TribeChange) (*models.Player, error) {
|
||||||
|
if obj.Player != nil {
|
||||||
|
return obj.Player, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPlayer(ctx, obj.PlayerID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tribeChangeRecordResolver) NewTribe(ctx context.Context, obj *models.TribeChange) (*models.Tribe, error) {
|
||||||
|
if obj.NewTribe != nil {
|
||||||
|
return obj.NewTribe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTribe(ctx, obj.NewTribeID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tribeChangeRecordResolver) OldTribe(ctx context.Context, obj *models.TribeChange) (*models.Tribe, error) {
|
||||||
|
if obj.OldTribe != nil {
|
||||||
|
return obj.OldTribe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTribe(ctx, obj.OldTribeID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) TribeChanges(ctx context.Context, server string, filter *models.TribeChangeFilter) (*generated.TribeChanges, error) {
|
||||||
|
var err error
|
||||||
|
list := &generated.TribeChanges{}
|
||||||
|
list.Items, list.Total, err = r.TribeChangeUcase.Fetch(ctx, server, filter)
|
||||||
|
return list, err
|
||||||
|
}
|
|
@ -2,10 +2,8 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/generated"
|
"github.com/tribalwarshelp/api/graphql/generated"
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,12 +15,6 @@ func (r *tribeHistoryRecordResolver) Tribe(ctx context.Context, obj *models.Trib
|
||||||
return getTribe(ctx, obj.TribeID), nil
|
return getTribe(ctx, obj.TribeID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *tribeHistoryRecordResolver) CreatedAt(ctx context.Context, obj *models.TribeHistory) (*time.Time, error) {
|
|
||||||
server, _ := getServer(ctx)
|
|
||||||
t := formatDate(ctx, utils.LanguageTagFromServerKey(server), obj.CreatedAt)
|
|
||||||
return &t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Resolver) TribeHistory(ctx context.Context, server string, filter *models.TribeHistoryFilter) (*generated.TribeHistory, error) {
|
func (r *Resolver) TribeHistory(ctx context.Context, server string, filter *models.TribeHistoryFilter) (*generated.TribeHistory, error) {
|
||||||
var err error
|
var err error
|
||||||
list := &generated.TribeHistory{}
|
list := &generated.TribeHistory{}
|
||||||
|
|
42
graphql/schema/daily_player_stats.graphql
Normal file
42
graphql/schema/daily_player_stats.graphql
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
type DailyPlayerStatsRecord {
|
||||||
|
player: Player @goField(forceResolver: true)
|
||||||
|
villages: Int!
|
||||||
|
points: Int!
|
||||||
|
rank: Int!
|
||||||
|
rankAtt: Int!
|
||||||
|
scoreAtt: Int!
|
||||||
|
rankDef: Int!
|
||||||
|
scoreDef: Int!
|
||||||
|
rankSup: Int!
|
||||||
|
scoreSup: Int!
|
||||||
|
rankTotal: Int!
|
||||||
|
scoreTotal: Int!
|
||||||
|
createdAt: Time!
|
||||||
|
}
|
||||||
|
|
||||||
|
type DailyPlayerStats {
|
||||||
|
total: Int!
|
||||||
|
items: [DailyPlayerStatsRecord!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input DailyPlayerStatsFilter {
|
||||||
|
playerID: [Int!]
|
||||||
|
playerIDNEQ: [Int!]
|
||||||
|
|
||||||
|
createdAt: Time
|
||||||
|
createdAtGT: Time
|
||||||
|
createdAtGTE: Time
|
||||||
|
createdAtLT: Time
|
||||||
|
createdAtLTE: Time
|
||||||
|
|
||||||
|
offset: Int
|
||||||
|
limit: Int
|
||||||
|
sort: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
dailyPlayerStats(
|
||||||
|
server: String!
|
||||||
|
filter: DailyPlayerStatsFilter
|
||||||
|
): DailyPlayerStats!
|
||||||
|
}
|
43
graphql/schema/daily_tribe_stats.graphql
Normal file
43
graphql/schema/daily_tribe_stats.graphql
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
type DailyTribeStatsRecord {
|
||||||
|
tribe: Tribe @goField(forceResolver: true)
|
||||||
|
members: Int!
|
||||||
|
villages: Int!
|
||||||
|
points: Int!
|
||||||
|
allPoints: Int!
|
||||||
|
rank: Int!
|
||||||
|
rankAtt: Int!
|
||||||
|
scoreAtt: Int!
|
||||||
|
rankDef: Int!
|
||||||
|
scoreDef: Int!
|
||||||
|
rankTotal: Int!
|
||||||
|
scoreTotal: Int!
|
||||||
|
dominance: Float!
|
||||||
|
createdAt: Time!
|
||||||
|
}
|
||||||
|
|
||||||
|
type DailyTribeStats {
|
||||||
|
total: Int!
|
||||||
|
items: [DailyTribeStatsRecord!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input DailyTribeStatsFilter {
|
||||||
|
tribeID: [Int!]
|
||||||
|
tribeIDNEQ: [Int!]
|
||||||
|
|
||||||
|
createdAt: Time
|
||||||
|
createdAtGT: Time
|
||||||
|
createdAtGTE: Time
|
||||||
|
createdAtLT: Time
|
||||||
|
createdAtLTE: Time
|
||||||
|
|
||||||
|
offset: Int
|
||||||
|
limit: Int
|
||||||
|
sort: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
dailyTribeStats(
|
||||||
|
server: String!
|
||||||
|
filter: DailyTribeStatsFilter
|
||||||
|
): DailyTribeStats!
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ type Ennoblement {
|
||||||
newOwnerTribe: Tribe @goField(forceResolver: true)
|
newOwnerTribe: Tribe @goField(forceResolver: true)
|
||||||
oldOwner: Player @goField(forceResolver: true)
|
oldOwner: Player @goField(forceResolver: true)
|
||||||
oldOwnerTribe: Tribe @goField(forceResolver: true)
|
oldOwnerTribe: Tribe @goField(forceResolver: true)
|
||||||
ennobledAt: Time! @goField(forceResolver: true)
|
ennobledAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnnoblementsList {
|
type EnnoblementsList {
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
|
type PlayerNameChange {
|
||||||
|
oldName: String!
|
||||||
|
newName: String!
|
||||||
|
changedOn: Time!
|
||||||
|
}
|
||||||
|
|
||||||
type Player {
|
type Player {
|
||||||
id: Int!
|
id: Int!
|
||||||
name: String!
|
name: String!
|
||||||
totalVillages: Int!
|
totalVillages: Int!
|
||||||
points: Int!
|
points: Int!
|
||||||
rank: Int!
|
rank: Int!
|
||||||
exist: Boolean!
|
exists: Boolean!
|
||||||
rankAtt: Int!
|
rankAtt: Int!
|
||||||
scoreAtt: Int!
|
scoreAtt: Int!
|
||||||
rankDef: Int!
|
rankDef: Int!
|
||||||
|
@ -14,9 +20,17 @@ type Player {
|
||||||
rankTotal: Int!
|
rankTotal: Int!
|
||||||
scoreTotal: Int!
|
scoreTotal: Int!
|
||||||
dailyGrowth: Int!
|
dailyGrowth: Int!
|
||||||
joinedAt: Time! @goField(forceResolver: true)
|
bestRank: Int!
|
||||||
|
bestRankAt: Time!
|
||||||
|
mostPoints: Int!
|
||||||
|
mostPointsAt: Time!
|
||||||
|
mostVillages: Int!
|
||||||
|
mostVillagesAt: Time!
|
||||||
|
joinedAt: Time!
|
||||||
|
deletedAt: Time
|
||||||
tribe: Tribe @goField(forceResolver: true)
|
tribe: Tribe @goField(forceResolver: true)
|
||||||
servers: [String!]! @goField(forceResolver: true)
|
servers: [String!]! @goField(forceResolver: true)
|
||||||
|
nameChanges: [PlayerNameChange!]! @goField(forceResolver: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayersList {
|
type PlayersList {
|
||||||
|
@ -28,7 +42,7 @@ input PlayerFilter {
|
||||||
id: [Int!]
|
id: [Int!]
|
||||||
idNEQ: [Int!]
|
idNEQ: [Int!]
|
||||||
|
|
||||||
exist: Boolean
|
exists: Boolean
|
||||||
|
|
||||||
name: [String!]
|
name: [String!]
|
||||||
nameNEQ: [String!]
|
nameNEQ: [String!]
|
||||||
|
@ -113,6 +127,12 @@ input PlayerFilter {
|
||||||
joinedAtLT: Time
|
joinedAtLT: Time
|
||||||
joinedAtLTE: Time
|
joinedAtLTE: Time
|
||||||
|
|
||||||
|
deletedAt: Time
|
||||||
|
deletedAtGT: Time
|
||||||
|
deletedAtGTE: Time
|
||||||
|
deletedAtLT: Time
|
||||||
|
deletedAtLTE: Time
|
||||||
|
|
||||||
tribeID: [Int!]
|
tribeID: [Int!]
|
||||||
tribeFilter: TribeFilter
|
tribeFilter: TribeFilter
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ type PlayerHistoryRecord {
|
||||||
rankTotal: Int!
|
rankTotal: Int!
|
||||||
scoreTotal: Int!
|
scoreTotal: Int!
|
||||||
tribe: Tribe @goField(forceResolver: true)
|
tribe: Tribe @goField(forceResolver: true)
|
||||||
createdAt: Time! @goField(forceResolver: true)
|
createdAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayerHistory {
|
type PlayerHistory {
|
||||||
|
|
|
@ -16,9 +16,9 @@ type Server {
|
||||||
unitConfig: UnitConfig!
|
unitConfig: UnitConfig!
|
||||||
buildingConfig: BuildingConfig!
|
buildingConfig: BuildingConfig!
|
||||||
|
|
||||||
dataUpdatedAt: Time! @goField(forceResolver: true)
|
dataUpdatedAt: Time!
|
||||||
historyUpdatedAt: Time! @goField(forceResolver: true)
|
historyUpdatedAt: Time!
|
||||||
statsUpdatedAt: Time! @goField(forceResolver: true)
|
statsUpdatedAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServersList {
|
type ServersList {
|
||||||
|
|
|
@ -9,7 +9,7 @@ type ServerStatsRecord {
|
||||||
barbarianVillages: Int!
|
barbarianVillages: Int!
|
||||||
playerVillages: Int!
|
playerVillages: Int!
|
||||||
villages: Int!
|
villages: Int!
|
||||||
createdAt: Time! @goField(forceResolver: true)
|
createdAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerStats {
|
type ServerStats {
|
||||||
|
|
|
@ -7,15 +7,22 @@ type Tribe {
|
||||||
points: Int!
|
points: Int!
|
||||||
allPoints: Int!
|
allPoints: Int!
|
||||||
rank: Int!
|
rank: Int!
|
||||||
exist: Boolean!
|
exists: Boolean!
|
||||||
rankAtt: Int!
|
rankAtt: Int!
|
||||||
scoreAtt: Int!
|
scoreAtt: Int!
|
||||||
rankDef: Int!
|
rankDef: Int!
|
||||||
scoreDef: Int!
|
scoreDef: Int!
|
||||||
rankTotal: Int!
|
rankTotal: Int!
|
||||||
dominance: Float!
|
|
||||||
createdAt: Time! @goField(forceResolver: true)
|
|
||||||
scoreTotal: Int!
|
scoreTotal: Int!
|
||||||
|
dominance: Float!
|
||||||
|
bestRank: Int!
|
||||||
|
bestRankAt: Time!
|
||||||
|
mostPoints: Int!
|
||||||
|
mostPointsAt: Time!
|
||||||
|
mostVillages: Int!
|
||||||
|
mostVillagesAt: Time!
|
||||||
|
createdAt: Time!
|
||||||
|
deletedAt: Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type TribesList {
|
type TribesList {
|
||||||
|
@ -27,7 +34,7 @@ input TribeFilter {
|
||||||
id: [Int!]
|
id: [Int!]
|
||||||
idNEQ: [Int!]
|
idNEQ: [Int!]
|
||||||
|
|
||||||
exist: Boolean
|
exists: Boolean
|
||||||
|
|
||||||
tag: [String!]
|
tag: [String!]
|
||||||
tagNEQ: [String!]
|
tagNEQ: [String!]
|
||||||
|
@ -117,6 +124,12 @@ input TribeFilter {
|
||||||
createdAtLT: Time
|
createdAtLT: Time
|
||||||
createdAtLTE: Time
|
createdAtLTE: Time
|
||||||
|
|
||||||
|
deletedAt: Time
|
||||||
|
deletedAtGT: Time
|
||||||
|
deletedAtGTE: Time
|
||||||
|
deletedAtLT: Time
|
||||||
|
deletedAtLTE: Time
|
||||||
|
|
||||||
offset: Int
|
offset: Int
|
||||||
limit: Int
|
limit: Int
|
||||||
sort: String
|
sort: String
|
||||||
|
|
36
graphql/schema/tribe_change.graphql
Normal file
36
graphql/schema/tribe_change.graphql
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
type TribeChangeRecord {
|
||||||
|
player: Player @goField(forceResolver: true)
|
||||||
|
oldTribe: Tribe @goField(forceResolver: true)
|
||||||
|
newTribe: Tribe @goField(forceResolver: true)
|
||||||
|
createdAt: Time!
|
||||||
|
}
|
||||||
|
|
||||||
|
type TribeChanges {
|
||||||
|
total: Int!
|
||||||
|
items: [TribeChangeRecord!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input TribeChangeFilter {
|
||||||
|
playerID: [Int!]
|
||||||
|
playerIDNEQ: [Int!]
|
||||||
|
|
||||||
|
oldTribeID: [Int!]
|
||||||
|
oldTribeIDNEQ: [Int!]
|
||||||
|
|
||||||
|
newTribeID: [Int!]
|
||||||
|
newTribeIDNEQ: [Int!]
|
||||||
|
|
||||||
|
createdAt: Time
|
||||||
|
createdAtGT: Time
|
||||||
|
createdAtGTE: Time
|
||||||
|
createdAtLT: Time
|
||||||
|
createdAtLTE: Time
|
||||||
|
|
||||||
|
offset: Int
|
||||||
|
limit: Int
|
||||||
|
sort: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
tribeChanges(server: String!, filter: TribeChangeFilter): TribeChanges!
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ type TribeHistoryRecord {
|
||||||
scoreDef: Int!
|
scoreDef: Int!
|
||||||
rankTotal: Int!
|
rankTotal: Int!
|
||||||
scoreTotal: Int!
|
scoreTotal: Int!
|
||||||
createdAt: Time! @goField(forceResolver: true)
|
createdAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type TribeHistory {
|
type TribeHistory {
|
||||||
|
|
|
@ -6,6 +6,11 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, filter *models.LangVersionFilter) ([]*models.LangVersion, int, error)
|
Filter *models.LangVersionFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.LangVersion, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,23 +23,28 @@ func NewPGRepository(db *pg.DB) (langversion.Repository, error) {
|
||||||
return &pgRepository{db}, nil
|
return &pgRepository{db}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, f *models.LangVersionFilter) ([]*models.LangVersion, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg langversion.FetchConfig) ([]*models.LangVersion, int, error) {
|
||||||
var err error
|
var err error
|
||||||
data := []*models.LangVersion{}
|
data := []*models.LangVersion{}
|
||||||
|
total := 0
|
||||||
query := repo.Model(&data).Context(ctx)
|
query := repo.Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,23 @@ func (ucase *usecase) Fetch(ctx context.Context, filter *models.LangVersionFilte
|
||||||
filter.Limit = langversion.PaginationLimit
|
filter.Limit = langversion.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, filter)
|
return ucase.repo.Fetch(ctx, langversion.FetchConfig{
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ucase *usecase) GetByTag(ctx context.Context, tag models.LanguageTag) (*models.LangVersion, error) {
|
func (ucase *usecase) GetByTag(ctx context.Context, tag models.LanguageTag) (*models.LangVersion, error) {
|
||||||
langversions, total, err := ucase.repo.Fetch(ctx, &models.LangVersionFilter{
|
langversions, _, err := ucase.repo.Fetch(ctx, langversion.FetchConfig{
|
||||||
Tag: []models.LanguageTag{tag},
|
Filter: &models.LangVersionFilter{
|
||||||
Limit: 1,
|
Tag: []models.LanguageTag{tag},
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if len(langversions) == 0 {
|
||||||
return nil, fmt.Errorf("There is no lang version with tag: %s.", tag)
|
return nil, fmt.Errorf("There is no lang version with tag: %s.", tag)
|
||||||
}
|
}
|
||||||
return langversions[0], nil
|
return langversions[0], nil
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/utils"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
@ -15,11 +13,8 @@ type lineParser struct {
|
||||||
location *time.Location
|
location *time.Location
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLineParser(timezone string) (*lineParser, error) {
|
func newLineParser() *lineParser {
|
||||||
return &lineParser{
|
return &lineParser{}
|
||||||
location: utils.GetLocation(timezone),
|
|
||||||
},
|
|
||||||
nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *lineParser) parse(line []string) (*models.LiveEnnoblement, error) {
|
func (parser *lineParser) parse(line []string) (*models.LiveEnnoblement, error) {
|
||||||
|
@ -36,7 +31,7 @@ func (parser *lineParser) parse(line []string) (*models.LiveEnnoblement, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "timestamp")
|
return nil, errors.Wrap(err, "timestamp")
|
||||||
}
|
}
|
||||||
e.EnnobledAt = time.Unix(int64(timestamp), 0).In(parser.location)
|
e.EnnobledAt = time.Unix(int64(timestamp), 0)
|
||||||
e.NewOwnerID, err = strconv.Atoi(line[2])
|
e.NewOwnerID, err = strconv.Atoi(line[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "*models.LiveEnnoblement.NewOwnerID")
|
return nil, errors.Wrap(err, "*models.LiveEnnoblement.NewOwnerID")
|
||||||
|
|
|
@ -55,10 +55,7 @@ func (repo *pgRepository) Fetch(ctx context.Context, server string) ([]*models.L
|
||||||
}
|
}
|
||||||
|
|
||||||
e := []*models.LiveEnnoblement{}
|
e := []*models.LiveEnnoblement{}
|
||||||
lineParser, err := newLineParser(s.LangVersion.Timezone)
|
lineParser := newLineParser()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
ennoblement, err := lineParser.parse(line)
|
ennoblement, err := lineParser.parse(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
41
main.go
41
main.go
|
@ -19,6 +19,10 @@ import (
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/dataloaders"
|
"github.com/tribalwarshelp/api/graphql/dataloaders"
|
||||||
|
|
||||||
|
dailyplayerstatsrepo "github.com/tribalwarshelp/api/dailyplayerstats/repository"
|
||||||
|
dailyplayerstatsucase "github.com/tribalwarshelp/api/dailyplayerstats/usecase"
|
||||||
|
dailytribestatsrepo "github.com/tribalwarshelp/api/dailytribestats/repository"
|
||||||
|
dailytribestatsucase "github.com/tribalwarshelp/api/dailytribestats/usecase"
|
||||||
ennoblementrepo "github.com/tribalwarshelp/api/ennoblement/repository"
|
ennoblementrepo "github.com/tribalwarshelp/api/ennoblement/repository"
|
||||||
ennoblementucase "github.com/tribalwarshelp/api/ennoblement/usecase"
|
ennoblementucase "github.com/tribalwarshelp/api/ennoblement/usecase"
|
||||||
langversionrepo "github.com/tribalwarshelp/api/langversion/repository"
|
langversionrepo "github.com/tribalwarshelp/api/langversion/repository"
|
||||||
|
@ -37,6 +41,8 @@ import (
|
||||||
serverstatsucase "github.com/tribalwarshelp/api/serverstats/usecase"
|
serverstatsucase "github.com/tribalwarshelp/api/serverstats/usecase"
|
||||||
triberepo "github.com/tribalwarshelp/api/tribe/repository"
|
triberepo "github.com/tribalwarshelp/api/tribe/repository"
|
||||||
tribeucase "github.com/tribalwarshelp/api/tribe/usecase"
|
tribeucase "github.com/tribalwarshelp/api/tribe/usecase"
|
||||||
|
tribechangerepo "github.com/tribalwarshelp/api/tribechange/repository"
|
||||||
|
tribechangeucase "github.com/tribalwarshelp/api/tribechange/usecase"
|
||||||
tribehistoryrepo "github.com/tribalwarshelp/api/tribehistory/repository"
|
tribehistoryrepo "github.com/tribalwarshelp/api/tribehistory/repository"
|
||||||
tribehistoryucase "github.com/tribalwarshelp/api/tribehistory/usecase"
|
tribehistoryucase "github.com/tribalwarshelp/api/tribehistory/usecase"
|
||||||
villagerepo "github.com/tribalwarshelp/api/village/repository"
|
villagerepo "github.com/tribalwarshelp/api/village/repository"
|
||||||
|
@ -68,15 +74,16 @@ func main() {
|
||||||
log.Fatal("Database disconnecting:", err)
|
log.Fatal("Database disconnecting:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
//single server redis
|
|
||||||
redisClient := redis.NewClient(&redis.Options{
|
redisClient := redis.NewClient(&redis.Options{
|
||||||
Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"),
|
Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"),
|
||||||
Password: os.Getenv("REDIS_PASSWORD"),
|
Password: os.Getenv("REDIS_PASSWORD"),
|
||||||
})
|
})
|
||||||
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
if err := redisClient.Ping(ctx).Err(); err != nil {
|
if err := redisClient.Ping(ctx).Err(); err != nil {
|
||||||
log.Fatal(errors.Wrap(err, "cannot establish a connection with Redis"))
|
log.Fatal(errors.Wrap(err, "cannot connect to redis"))
|
||||||
}
|
}
|
||||||
|
cancel()
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := redisClient.Close(); err != nil {
|
if err := redisClient.Close(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -98,6 +105,9 @@ func main() {
|
||||||
tribehistoryRepo := tribehistoryrepo.NewPGRepository(db)
|
tribehistoryRepo := tribehistoryrepo.NewPGRepository(db)
|
||||||
playerhistoryRepo := playerhistoryrepo.NewPGRepository(db)
|
playerhistoryRepo := playerhistoryrepo.NewPGRepository(db)
|
||||||
serverstatsRepo := serverstatsrepo.NewPGRepository(db)
|
serverstatsRepo := serverstatsrepo.NewPGRepository(db)
|
||||||
|
tribeChangeRepo := tribechangerepo.NewPGRepository(db)
|
||||||
|
dailyPlayerStatsRepo := dailyplayerstatsrepo.NewPGRepository(db)
|
||||||
|
dailyTribeStatsRepo := dailytribestatsrepo.NewPGRepository(db)
|
||||||
liveennoblementRepo := liveennoblementrepo.NewPGRepository(db, redisClient)
|
liveennoblementRepo := liveennoblementrepo.NewPGRepository(db, redisClient)
|
||||||
|
|
||||||
serverUcase := serverucase.New(serverRepo)
|
serverUcase := serverucase.New(serverRepo)
|
||||||
|
@ -119,16 +129,19 @@ func main() {
|
||||||
httpdelivery.Attach(httpdelivery.Config{
|
httpdelivery.Attach(httpdelivery.Config{
|
||||||
RouterGroup: graphql,
|
RouterGroup: graphql,
|
||||||
Resolver: &resolvers.Resolver{
|
Resolver: &resolvers.Resolver{
|
||||||
LangVersionUcase: langversionucase.New(langversionRepo),
|
LangVersionUcase: langversionucase.New(langversionRepo),
|
||||||
ServerUcase: serverUcase,
|
ServerUcase: serverUcase,
|
||||||
TribeUcase: tribeucase.New(tribeRepo),
|
TribeUcase: tribeucase.New(tribeRepo),
|
||||||
PlayerUcase: playerucase.New(playerRepo),
|
PlayerUcase: playerucase.New(playerRepo),
|
||||||
VillageUcase: villageucase.New(villageRepo),
|
VillageUcase: villageucase.New(villageRepo),
|
||||||
EnnoblementUcase: ennoblementucase.New(ennoblementRepo),
|
EnnoblementUcase: ennoblementucase.New(ennoblementRepo),
|
||||||
LiveEnnoblementUcase: liveennoblementucase.New(liveennoblementRepo),
|
LiveEnnoblementUcase: liveennoblementucase.New(liveennoblementRepo),
|
||||||
TribeHistoryUcase: tribehistoryucase.New(tribehistoryRepo),
|
TribeHistoryUcase: tribehistoryucase.New(tribehistoryRepo),
|
||||||
PlayerHistoryUcase: playerhistoryucase.New(playerhistoryRepo),
|
PlayerHistoryUcase: playerhistoryucase.New(playerhistoryRepo),
|
||||||
ServerStatsUcase: serverstatsucase.New(serverstatsRepo),
|
ServerStatsUcase: serverstatsucase.New(serverstatsRepo),
|
||||||
|
TribeChangeUcase: tribechangeucase.New(tribeChangeRepo),
|
||||||
|
DailyPlayerStatsUcase: dailyplayerstatsucase.New(dailyPlayerStatsRepo),
|
||||||
|
DailyTribeStatsUcase: dailytribestatsucase.New(dailyTribeStatsRepo),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -149,7 +162,7 @@ func main() {
|
||||||
<-quit
|
<-quit
|
||||||
log.Println("Shutdown Server ...")
|
log.Println("Shutdown Server ...")
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := srv.Shutdown(ctx); err != nil {
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
log.Fatal("Server Shutdown:", err)
|
log.Fatal("Server Shutdown:", err)
|
||||||
|
|
|
@ -8,18 +8,21 @@ import (
|
||||||
|
|
||||||
"github.com/tribalwarshelp/api/graphql/dataloaders"
|
"github.com/tribalwarshelp/api/graphql/dataloaders"
|
||||||
"github.com/tribalwarshelp/api/server"
|
"github.com/tribalwarshelp/api/server"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverDataLoadersContextKey ContextKey = "serverDataLoaders"
|
var serverDataLoadersContextKey ContextKey = "serverDataLoaders"
|
||||||
|
var langVersionLoadersContextKey ContextKey = "langVersionLoaders"
|
||||||
var dataloadersContextKey ContextKey = "dataloaders"
|
var dataloadersContextKey ContextKey = "dataloaders"
|
||||||
|
|
||||||
func DataLoadersToContext(serverRepo server.Repository, cfg dataloaders.Config) gin.HandlerFunc {
|
func DataLoadersToContext(serverRepo server.Repository, cfg dataloaders.Config) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
ctx := c.Request.Context()
|
ctx := c.Request.Context()
|
||||||
loaders := make(map[string]*dataloaders.ServerDataLoaders)
|
serverDataLoaders := make(map[string]*dataloaders.ServerDataLoaders)
|
||||||
servers, _, err := serverRepo.Fetch(c.Request.Context(), nil)
|
langVersionDataLoaders := make(map[models.LanguageTag]*dataloaders.LangVersionDataLoaders)
|
||||||
|
servers, _, err := serverRepo.Fetch(c.Request.Context(), server.FetchConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, &gqlerror.Error{
|
c.JSON(http.StatusOK, &gqlerror.Error{
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
|
@ -28,10 +31,14 @@ func DataLoadersToContext(serverRepo server.Repository, cfg dataloaders.Config)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
loaders[server.Key] = dataloaders.NewServerDataLoaders(server.Key, cfg)
|
serverDataLoaders[server.Key] = dataloaders.NewServerDataLoaders(server.Key, cfg)
|
||||||
|
if _, ok := langVersionDataLoaders[server.LangVersionTag]; !ok {
|
||||||
|
langVersionDataLoaders[server.LangVersionTag] = dataloaders.NewLangVersionDataLoaders(server.LangVersionTag, cfg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx = StoreServerDataLoadersInContext(ctx, loaders)
|
ctx = StoreServerDataLoadersInContext(ctx, serverDataLoaders)
|
||||||
ctx = StoreDataLoadersInContext(ctx, dataloaders.New(cfg))
|
ctx = StoreLangVersionDataLoadersInContext(ctx, langVersionDataLoaders)
|
||||||
|
ctx = StoreDataLoadersInContext(ctx, dataloaders.NewDataLoaders(cfg))
|
||||||
c.Request = c.Request.WithContext(ctx)
|
c.Request = c.Request.WithContext(ctx)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
@ -50,6 +57,19 @@ func ServerDataLoadersFromContext(ctx context.Context) map[string]*dataloaders.S
|
||||||
return dl.(map[string]*dataloaders.ServerDataLoaders)
|
return dl.(map[string]*dataloaders.ServerDataLoaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StoreLangVersionDataLoadersInContext(ctx context.Context, loaders map[models.LanguageTag]*dataloaders.LangVersionDataLoaders) context.Context {
|
||||||
|
return context.WithValue(ctx, langVersionLoadersContextKey, loaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LangVersionDataLoadersFromContext(ctx context.Context) map[models.LanguageTag]*dataloaders.LangVersionDataLoaders {
|
||||||
|
dl := ctx.Value(langVersionLoadersContextKey)
|
||||||
|
if dl == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return dl.(map[models.LanguageTag]*dataloaders.LangVersionDataLoaders)
|
||||||
|
}
|
||||||
|
|
||||||
func StoreDataLoadersInContext(ctx context.Context, loaders *dataloaders.DataLoaders) context.Context {
|
func StoreDataLoadersInContext(ctx context.Context, loaders *dataloaders.DataLoaders) context.Context {
|
||||||
return context.WithValue(ctx, dataloadersContextKey, loaders)
|
return context.WithValue(ctx, dataloadersContextKey, loaders)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,14 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.PlayerFilter) ([]*models.Player, int, error)
|
Server string
|
||||||
FetchPlayerServers(ctx context.Context, playerID ...int) (map[int][]string, error)
|
Filter *models.PlayerFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Player, int, error)
|
||||||
|
FetchNameChanges(ctx context.Context, langTag models.LanguageTag, playerID ...int) (map[int][]*models.PlayerNameChange, error)
|
||||||
|
FetchPlayerServers(ctx context.Context, langTag models.LanguageTag, playerID ...int) (map[int][]string, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,33 +19,38 @@ func NewPGRepository(db *pg.DB) player.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.PlayerFilter) ([]*models.Player, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg player.FetchConfig) ([]*models.Player, int, error) {
|
||||||
var err error
|
var err error
|
||||||
data := []*models.Player{}
|
data := []*models.Player{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
total := 0
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Exist != nil {
|
if cfg.Filter.Exists != nil {
|
||||||
query = query.Where("exist = ?", *f.Exist)
|
query = query.Where("exists = ?", *cfg.Filter.Exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.TribeFilter != nil {
|
if cfg.Filter.TribeFilter != nil {
|
||||||
query = query.Relation("Tribe._").WhereStruct(f.TribeFilter)
|
query = query.Relation("Tribe._").WhereStruct(cfg.Filter.TribeFilter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
@ -59,12 +64,31 @@ type fetchPlayerServersQueryResult struct {
|
||||||
Servers []string `pg:",array"`
|
Servers []string `pg:",array"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) FetchPlayerServers(ctx context.Context, playerID ...int) (map[int][]string, error) {
|
func (repo *pgRepository) FetchNameChanges(ctx context.Context, langTag models.LanguageTag, playerID ...int) (map[int][]*models.PlayerNameChange, error) {
|
||||||
|
data := []*models.PlayerNameChange{}
|
||||||
|
if err := repo.Model(&data).
|
||||||
|
Context(ctx).
|
||||||
|
Where("lang_version_tag = ?", langTag).
|
||||||
|
Where("player_id IN (?)", pg.In(playerID)).
|
||||||
|
Select(); err != nil && err != pg.ErrNoRows {
|
||||||
|
return nil, errors.Wrap(err, "Internal server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[int][]*models.PlayerNameChange)
|
||||||
|
for _, res := range data {
|
||||||
|
m[res.PlayerID] = append(m[res.PlayerID], res)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *pgRepository) FetchPlayerServers(ctx context.Context, langTag models.LanguageTag, playerID ...int) (map[int][]string, error) {
|
||||||
data := []*fetchPlayerServersQueryResult{}
|
data := []*fetchPlayerServersQueryResult{}
|
||||||
if err := repo.Model(&models.PlayerToServer{}).
|
if err := repo.Model(&models.PlayerToServer{}).
|
||||||
Context(ctx).
|
Context(ctx).
|
||||||
Column("player_id").
|
Column("player_id").
|
||||||
ColumnExpr("array_agg(server_key) as servers").
|
ColumnExpr("array_agg(server_key) as servers").
|
||||||
|
Relation("Server._").
|
||||||
|
Where("lang_version_tag = ?", langTag).
|
||||||
Where("player_id IN (?)", pg.In(playerID)).
|
Where("player_id IN (?)", pg.In(playerID)).
|
||||||
Group("player_id").
|
Group("player_id").
|
||||||
Select(&data); err != nil && err != pg.ErrNoRows {
|
Select(&data); err != nil && err != pg.ErrNoRows {
|
||||||
|
|
|
@ -25,18 +25,25 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.P
|
||||||
filter.Limit = player.PaginationLimit
|
filter.Limit = player.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, player.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*models.Player, error) {
|
func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*models.Player, error) {
|
||||||
players, total, err := ucase.repo.Fetch(ctx, server, &models.PlayerFilter{
|
players, _, err := ucase.repo.Fetch(ctx, player.FetchConfig{
|
||||||
ID: []int{id},
|
Server: server,
|
||||||
Limit: 1,
|
Filter: &models.PlayerFilter{
|
||||||
|
ID: []int{id},
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if len(players) == 0 {
|
||||||
return nil, fmt.Errorf("Player (ID: %d) not found.", id)
|
return nil, fmt.Errorf("Player (ID: %d) not found.", id)
|
||||||
}
|
}
|
||||||
return players[0], nil
|
return players[0], nil
|
||||||
|
|
|
@ -6,6 +6,12 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.PlayerHistoryFilter) ([]*models.PlayerHistory, int, error)
|
Server string
|
||||||
|
Filter *models.PlayerHistoryFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.PlayerHistory, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,30 @@ func NewPGRepository(db *pg.DB) playerhistory.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.PlayerHistoryFilter) ([]*models.PlayerHistory, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg playerhistory.FetchConfig) ([]*models.PlayerHistory, int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
total := 0
|
||||||
data := []*models.PlayerHistory{}
|
data := []*models.PlayerHistory{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
|
|
@ -24,5 +24,9 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.P
|
||||||
filter.Limit = playerhistory.PaginationLimit
|
filter.Limit = playerhistory.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, playerhistory.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, filter *models.ServerFilter) ([]*models.Server, int, error)
|
Filter *models.ServerFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Server, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,23 +23,28 @@ func NewPGRepository(db *pg.DB) (server.Repository, error) {
|
||||||
return &pgRepository{db}, nil
|
return &pgRepository{db}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, f *models.ServerFilter) ([]*models.Server, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg server.FetchConfig) ([]*models.Server, int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
total := 0
|
||||||
data := []*models.Server{}
|
data := []*models.Server{}
|
||||||
query := repo.Model(&data).Context(ctx)
|
query := repo.Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,23 @@ func (ucase *usecase) Fetch(ctx context.Context, filter *models.ServerFilter) ([
|
||||||
filter.Limit = server.PaginationLimit
|
filter.Limit = server.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, filter)
|
return ucase.repo.Fetch(ctx, server.FetchConfig{
|
||||||
|
Count: true,
|
||||||
|
Filter: filter,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ucase *usecase) GetByKey(ctx context.Context, key string) (*models.Server, error) {
|
func (ucase *usecase) GetByKey(ctx context.Context, key string) (*models.Server, error) {
|
||||||
servers, total, err := ucase.repo.Fetch(ctx, &models.ServerFilter{
|
servers, _, err := ucase.repo.Fetch(ctx, server.FetchConfig{
|
||||||
Key: []string{key},
|
Filter: &models.ServerFilter{
|
||||||
Limit: 1,
|
Key: []string{key},
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if len(servers) == 0 {
|
||||||
return nil, fmt.Errorf("Server (key: %s) not found.", key)
|
return nil, fmt.Errorf("Server (key: %s) not found.", key)
|
||||||
}
|
}
|
||||||
return servers[0], nil
|
return servers[0], nil
|
||||||
|
|
|
@ -6,6 +6,12 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.ServerStatsFilter) ([]*models.ServerStats, int, error)
|
Server string
|
||||||
|
Filter *models.ServerStatsFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.ServerStats, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,30 @@ func NewPGRepository(db *pg.DB) serverstats.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.ServerStatsFilter) ([]*models.ServerStats, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg serverstats.FetchConfig) ([]*models.ServerStats, int, error) {
|
||||||
var err error
|
var err error
|
||||||
data := []*models.ServerStats{}
|
data := []*models.ServerStats{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
total := 0
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
|
|
@ -24,5 +24,9 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.S
|
||||||
filter.Limit = serverstats.PaginationLimit
|
filter.Limit = serverstats.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, serverstats.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.TribeFilter) ([]*models.Tribe, int, error)
|
Server string
|
||||||
|
Filter *models.TribeFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Tribe, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,29 +19,34 @@ func NewPGRepository(db *pg.DB) tribe.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.TribeFilter) ([]*models.Tribe, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg tribe.FetchConfig) ([]*models.Tribe, int, error) {
|
||||||
var err error
|
var err error
|
||||||
data := []*models.Tribe{}
|
data := []*models.Tribe{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
total := 0
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Exist != nil {
|
if cfg.Filter.Exists != nil {
|
||||||
query = query.Where("exist = ?", *f.Exist)
|
query = query.Where("exist = ?", *cfg.Filter.Exists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
|
|
@ -25,18 +25,25 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.T
|
||||||
filter.Limit = tribe.PaginationLimit
|
filter.Limit = tribe.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, tribe.FetchConfig{
|
||||||
|
Filter: filter,
|
||||||
|
Server: server,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*models.Tribe, error) {
|
func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*models.Tribe, error) {
|
||||||
tribes, total, err := ucase.repo.Fetch(ctx, server, &models.TribeFilter{
|
tribes, _, err := ucase.repo.Fetch(ctx, tribe.FetchConfig{
|
||||||
ID: []int{id},
|
Filter: &models.TribeFilter{
|
||||||
Limit: 1,
|
ID: []int{id},
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
|
Server: server,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if total == 0 {
|
if len(tribes) == 0 {
|
||||||
return nil, fmt.Errorf("Tribe (ID: %s) not found.", id)
|
return nil, fmt.Errorf("Tribe (ID: %s) not found.", id)
|
||||||
}
|
}
|
||||||
return tribes[0], nil
|
return tribes[0], nil
|
||||||
|
|
5
tribechange/constants.go
Normal file
5
tribechange/constants.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package tribechange
|
||||||
|
|
||||||
|
const (
|
||||||
|
PaginationLimit = 100
|
||||||
|
)
|
17
tribechange/repository.go
Normal file
17
tribechange/repository.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package tribechange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FetchConfig struct {
|
||||||
|
Server string
|
||||||
|
Filter *models.TribeChangeFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.TribeChange, int, error)
|
||||||
|
}
|
52
tribechange/repository/pg_repository.go
Normal file
52
tribechange/repository/pg_repository.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-pg/pg/v10"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tribalwarshelp/api/tribechange"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pgRepository struct {
|
||||||
|
*pg.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPGRepository(db *pg.DB) tribechange.Repository {
|
||||||
|
return &pgRepository{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg tribechange.FetchConfig) ([]*models.TribeChange, int, error) {
|
||||||
|
var err error
|
||||||
|
total := 0
|
||||||
|
data := []*models.TribeChange{}
|
||||||
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
|
if cfg.Filter != nil {
|
||||||
|
query = query.
|
||||||
|
WhereStruct(cfg.Filter).
|
||||||
|
Limit(cfg.Filter.Limit).
|
||||||
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
|
if cfg.Filter.Sort != "" {
|
||||||
|
query = query.Order(cfg.Filter.Sort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
|
if err != nil && err != pg.ErrNoRows {
|
||||||
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
|
}
|
||||||
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, total, nil
|
||||||
|
}
|
11
tribechange/usecase.go
Normal file
11
tribechange/usecase.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package tribechange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Usecase interface {
|
||||||
|
Fetch(ctx context.Context, server string, filter *models.TribeChangeFilter) ([]*models.TribeChange, int, error)
|
||||||
|
}
|
32
tribechange/usecase/tribechange_usecase.go
Normal file
32
tribechange/usecase/tribechange_usecase.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/api/tribechange"
|
||||||
|
"github.com/tribalwarshelp/api/utils"
|
||||||
|
"github.com/tribalwarshelp/shared/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type usecase struct {
|
||||||
|
repo tribechange.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo tribechange.Repository) tribechange.Usecase {
|
||||||
|
return &usecase{repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.TribeChangeFilter) ([]*models.TribeChange, int, error) {
|
||||||
|
if filter == nil {
|
||||||
|
filter = &models.TribeChangeFilter{}
|
||||||
|
}
|
||||||
|
if filter.Limit > tribechange.PaginationLimit || filter.Limit <= 0 {
|
||||||
|
filter.Limit = tribechange.PaginationLimit
|
||||||
|
}
|
||||||
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
|
return ucase.repo.Fetch(ctx, tribechange.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,6 +6,12 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/models"
|
"github.com/tribalwarshelp/shared/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type FetchConfig struct {
|
||||||
Fetch(ctx context.Context, server string, filter *models.TribeHistoryFilter) ([]*models.TribeHistory, int, error)
|
Server string
|
||||||
|
Filter *models.TribeHistoryFilter
|
||||||
|
Count bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.TribeHistory, int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,30 @@ func NewPGRepository(db *pg.DB) tribehistory.Repository {
|
||||||
return &pgRepository{db}
|
return &pgRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *pgRepository) Fetch(ctx context.Context, server string, f *models.TribeHistoryFilter) ([]*models.TribeHistory, int, error) {
|
func (repo *pgRepository) Fetch(ctx context.Context, cfg tribehistory.FetchConfig) ([]*models.TribeHistory, int, error) {
|
||||||
var err error
|
var err error
|
||||||
|
total := 0
|
||||||
data := []*models.TribeHistory{}
|
data := []*models.TribeHistory{}
|
||||||
query := repo.WithParam("SERVER", pg.Safe(server)).Model(&data).Context(ctx)
|
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
|
||||||
|
|
||||||
if f != nil {
|
if cfg.Filter != nil {
|
||||||
query = query.
|
query = query.
|
||||||
WhereStruct(f).
|
WhereStruct(cfg.Filter).
|
||||||
Limit(f.Limit).
|
Limit(cfg.Filter.Limit).
|
||||||
Offset(f.Offset)
|
Offset(cfg.Filter.Offset)
|
||||||
|
|
||||||
if f.Sort != "" {
|
if cfg.Filter.Sort != "" {
|
||||||
query = query.Order(f.Sort)
|
query = query.Order(cfg.Filter.Sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := query.SelectAndCount()
|
if cfg.Count {
|
||||||
|
total, err = query.SelectAndCount()
|
||||||
|
} else {
|
||||||
|
err = query.Select()
|
||||||
|
}
|
||||||
if err != nil && err != pg.ErrNoRows {
|
if err != nil && err != pg.ErrNoRows {
|
||||||
if strings.Contains(err.Error(), `relation "`+server) {
|
if strings.Contains(err.Error(), `relation "`+cfg.Server) {
|
||||||
return nil, 0, fmt.Errorf("Server not found")
|
return nil, 0, fmt.Errorf("Server not found")
|
||||||
}
|
}
|
||||||
return nil, 0, errors.Wrap(err, "Internal server error")
|
return nil, 0, errors.Wrap(err, "Internal server error")
|
||||||
|
|
|
@ -24,5 +24,9 @@ func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.T
|
||||||
filter.Limit = tribehistory.PaginationLimit
|
filter.Limit = tribehistory.PaginationLimit
|
||||||
}
|
}
|
||||||
filter.Sort = utils.SanitizeSort(filter.Sort)
|
filter.Sort = utils.SanitizeSort(filter.Sort)
|
||||||
return ucase.repo.Fetch(ctx, server, filter)
|
return ucase.repo.Fetch(ctx, tribehistory.FetchConfig{
|
||||||
|
Server: server,
|
||||||
|
Filter: filter,
|
||||||
|
Count: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func GetLocation(timezone string) *time.Location {
|
func GetLocation(timezone string) *time.Location {
|
||||||
loc, err := time.LoadLocation(timezone)
|
loc, err := time.LoadLocation(timezone)
|
||||||
|
|
Reference in New Issue
Block a user