[WIP] - refactor limit, sort, offset

- update the Server/PlayerHistory repository and usecase
This commit is contained in:
Dawid Wysokiński 2020-11-21 10:50:52 +01:00
parent a854a4b80a
commit 05efc69b31
14 changed files with 254 additions and 68 deletions

View File

@ -223,11 +223,11 @@ type ComplexityRoot struct {
LangVersions func(childComplexity int, filter *models.VersionFilter) int
LiveEnnoblements func(childComplexity int, server string) int
Player func(childComplexity int, server string, id int) int
PlayerHistory func(childComplexity int, server string, filter *models.PlayerHistoryFilter) int
PlayerHistory func(childComplexity int, server string, filter *models.PlayerHistoryFilter, limit *int, offset *int, sort []string) int
Players func(childComplexity int, server string, filter *models.PlayerFilter, limit *int, offset *int, sort []string) int
Server func(childComplexity int, key string) int
ServerStats func(childComplexity int, server string, filter *models.ServerStatsFilter) int
Servers func(childComplexity int, filter *models.ServerFilter) int
Servers func(childComplexity int, filter *models.ServerFilter, limit *int, offset *int, sort []string) int
Tribe func(childComplexity int, server string, id int) int
TribeChanges func(childComplexity int, server string, filter *models.TribeChangeFilter) int
TribeHistory func(childComplexity int, server string, filter *models.TribeHistoryFilter) int
@ -585,8 +585,8 @@ type QueryResolver interface {
LiveEnnoblements(ctx context.Context, server string) ([]*models.LiveEnnoblement, error)
Players(ctx context.Context, server string, filter *models.PlayerFilter, limit *int, offset *int, sort []string) (*PlayerList, error)
Player(ctx context.Context, server string, id int) (*models.Player, error)
PlayerHistory(ctx context.Context, server string, filter *models.PlayerHistoryFilter) (*PlayerHistory, error)
Servers(ctx context.Context, filter *models.ServerFilter) (*ServerList, error)
PlayerHistory(ctx context.Context, server string, filter *models.PlayerHistoryFilter, limit *int, offset *int, sort []string) (*PlayerHistory, error)
Servers(ctx context.Context, filter *models.ServerFilter, limit *int, offset *int, sort []string) (*ServerList, error)
Server(ctx context.Context, key string) (*models.Server, error)
ServerStats(ctx context.Context, server string, filter *models.ServerStatsFilter) (*ServerStats, error)
Tribes(ctx context.Context, server string, filter *models.TribeFilter) (*TribeList, error)
@ -1561,7 +1561,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.PlayerHistory(childComplexity, args["server"].(string), args["filter"].(*models.PlayerHistoryFilter)), true
return e.complexity.Query.PlayerHistory(childComplexity, args["server"].(string), args["filter"].(*models.PlayerHistoryFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string)), true
case "Query.players":
if e.complexity.Query.Players == nil {
@ -1609,7 +1609,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.Servers(childComplexity, args["filter"].(*models.ServerFilter)), true
return e.complexity.Query.Servers(childComplexity, args["filter"].(*models.ServerFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string)), true
case "Query.tribe":
if e.complexity.Query.Tribe == nil {
@ -3712,12 +3712,27 @@ input PlayerHistoryFilter {
createDateLTE: Time
offset: Int
@deprecated(
reason: "Use a new variable added to the query playerHistory - ` + "`" + `offset` + "`" + `."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query playerHistory - ` + "`" + `limit` + "`" + `."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query playerHistory - ` + "`" + `sort` + "`" + `."
)
}
extend type Query {
playerHistory(server: String!, filter: PlayerHistoryFilter): PlayerHistory!
playerHistory(
server: String!
filter: PlayerHistoryFilter
limit: Int
offset: Int
sort: [String!]
): PlayerHistory!
}
`, BuiltIn: false},
{Name: "schema/scalars.graphql", Input: `scalar Time
@ -3734,7 +3749,9 @@ type Server {
numberOfTribes: Int!
numberOfVillages: Int!
langVersion: Version @goField(forceResolver: true) @deprecated(reason: "Use ` + "`" + `version` + "`" + `.")
langVersion: Version
@goField(forceResolver: true)
@deprecated(reason: "Use ` + "`" + `version` + "`" + `.")
version: Version @goField(forceResolver: true)
config: ServerConfig!
@ -3766,12 +3783,26 @@ input ServerFilter {
versionCodeNEQ: [VersionCode!]
offset: Int
@deprecated(
reason: "Use a new variable added to the query players - ` + "`" + `offset` + "`" + `."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query players - ` + "`" + `limit` + "`" + `."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query players - ` + "`" + `sort` + "`" + `."
)
}
extend type Query {
servers(filter: ServerFilter): ServerList!
servers(
filter: ServerFilter
limit: Int
offset: Int
sort: [String!]
): ServerList!
server(key: String!): Server
}
`, BuiltIn: false},
@ -4571,6 +4602,33 @@ func (ec *executionContext) field_Query_playerHistory_args(ctx context.Context,
}
}
args["filter"] = arg1
var arg2 *int
if tmp, ok := rawArgs["limit"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit"))
arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["limit"] = arg2
var arg3 *int
if tmp, ok := rawArgs["offset"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset"))
arg3, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["offset"] = arg3
var arg4 []string
if tmp, ok := rawArgs["sort"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort"))
arg4, err = ec.unmarshalOString2ᚕstringᚄ(ctx, tmp)
if err != nil {
return nil, err
}
}
args["sort"] = arg4
return args, nil
}
@ -4700,6 +4758,33 @@ func (ec *executionContext) field_Query_servers_args(ctx context.Context, rawArg
}
}
args["filter"] = arg0
var arg1 *int
if tmp, ok := rawArgs["limit"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit"))
arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["limit"] = arg1
var arg2 *int
if tmp, ok := rawArgs["offset"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset"))
arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["offset"] = arg2
var arg3 []string
if tmp, ok := rawArgs["sort"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort"))
arg3, err = ec.unmarshalOString2ᚕstringᚄ(ctx, tmp)
if err != nil {
return nil, err
}
}
args["sort"] = arg3
return args, nil
}
@ -9294,7 +9379,7 @@ func (ec *executionContext) _Query_playerHistory(ctx context.Context, field grap
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().PlayerHistory(rctx, args["server"].(string), args["filter"].(*models.PlayerHistoryFilter))
return ec.resolvers.Query().PlayerHistory(rctx, args["server"].(string), args["filter"].(*models.PlayerHistoryFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string))
})
if err != nil {
ec.Error(ctx, err)
@ -9336,7 +9421,7 @@ func (ec *executionContext) _Query_servers(ctx context.Context, field graphql.Co
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().Servers(rctx, args["filter"].(*models.ServerFilter))
return ec.resolvers.Query().Servers(rctx, args["filter"].(*models.ServerFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string))
})
if err != nil {
ec.Error(ctx, err)

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/tribalwarshelp/api/graphql/generated"
"github.com/tribalwarshelp/api/playerhistory"
"github.com/tribalwarshelp/shared/models"
)
@ -23,9 +24,29 @@ func (r *playerHistoryRecordResolver) Tribe(ctx context.Context, obj *models.Pla
return getTribe(ctx, obj.TribeID), 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,
f *models.PlayerHistoryFilter, limit *int,
offset *int,
sort []string) (*generated.PlayerHistory, error) {
defLimit := 0
defOffset := 0
if limit == nil {
limit = &defLimit
}
if offset == nil {
offset = &defOffset
}
var err error
list := &generated.PlayerHistory{}
list.Items, list.Total, err = r.PlayerHistoryUcase.Fetch(ctx, server, filter)
list.Items, list.Total, err = r.PlayerHistoryUcase.Fetch(ctx, playerhistory.FetchConfig{
Server: server,
Filter: f,
Sort: sort,
Limit: *limit,
Offset: *offset,
Count: true,
})
return list, err
}

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/tribalwarshelp/api/middleware"
"github.com/tribalwarshelp/api/server"
"github.com/tribalwarshelp/api/graphql/generated"
"github.com/tribalwarshelp/shared/models"
@ -22,10 +23,28 @@ func (r *serverResolver) LangVersion(ctx context.Context, obj *models.Server) (*
return r.Version(ctx, obj)
}
func (r *queryResolver) Servers(ctx context.Context, filter *models.ServerFilter) (*generated.ServerList, error) {
func (r *queryResolver) Servers(ctx context.Context,
f *models.ServerFilter, limit *int,
offset *int,
sort []string) (*generated.ServerList, error) {
defLimit := 0
defOffset := 0
if limit == nil {
limit = &defLimit
}
if offset == nil {
offset = &defOffset
}
var err error
list := &generated.ServerList{}
list.Items, list.Total, err = r.ServerUcase.Fetch(ctx, filter)
list.Items, list.Total, err = r.ServerUcase.Fetch(ctx, server.FetchConfig{
Filter: f,
Sort: sort,
Limit: *limit,
Offset: *offset,
Count: true,
})
return list, err
}

View File

@ -31,10 +31,25 @@ input PlayerHistoryFilter {
createDateLTE: Time
offset: Int
@deprecated(
reason: "Use a new variable added to the query playerHistory - `offset`."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query playerHistory - `limit`."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query playerHistory - `sort`."
)
}
extend type Query {
playerHistory(server: String!, filter: PlayerHistoryFilter): PlayerHistory!
playerHistory(
server: String!
filter: PlayerHistoryFilter
limit: Int
offset: Int
sort: [String!]
): PlayerHistory!
}

View File

@ -10,7 +10,9 @@ type Server {
numberOfTribes: Int!
numberOfVillages: Int!
langVersion: Version @goField(forceResolver: true) @deprecated(reason: "Use `version`.")
langVersion: Version
@goField(forceResolver: true)
@deprecated(reason: "Use `version`.")
version: Version @goField(forceResolver: true)
config: ServerConfig!
@ -42,11 +44,25 @@ input ServerFilter {
versionCodeNEQ: [VersionCode!]
offset: Int
@deprecated(
reason: "Use a new variable added to the query players - `offset`."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query players - `limit`."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query players - `sort`."
)
}
extend type Query {
servers(filter: ServerFilter): ServerList!
servers(
filter: ServerFilter
limit: Int
offset: Int
sort: [String!]
): ServerList!
server(key: String!): Server
}

View File

@ -31,6 +31,9 @@ func (ucase *usecase) Fetch(ctx context.Context, cfg player.FetchConfig) ([]*mod
if cfg.Filter.Sort != "" {
cfg.Sort = append(cfg.Sort, cfg.Filter.Sort)
}
if cfg.Filter.TribeFilter != nil && cfg.Filter.TribeFilter.Sort != "" {
cfg.Sort = append(cfg.Sort, "tribe."+cfg.Filter.TribeFilter.Sort)
}
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > player.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = player.PaginationLimit

View File

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

View File

@ -8,6 +8,7 @@ import (
"github.com/go-pg/pg/v10"
"github.com/pkg/errors"
"github.com/tribalwarshelp/api/playerhistory"
"github.com/tribalwarshelp/api/utils"
"github.com/tribalwarshelp/shared/models"
)
@ -23,17 +24,20 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg playerhistory.FetchConf
var err error
total := 0
data := []*models.PlayerHistory{}
query := repo.WithParam("SERVER", pg.Safe(cfg.Server)).Model(&data).Context(ctx)
query := repo.
WithParam("SERVER", pg.Safe(cfg.Server)).
Model(&data).
Context(ctx).
Order(cfg.Sort...).
Limit(cfg.Limit).
Offset(cfg.Offset)
playerRequired := utils.FindStringWithPrefix(cfg.Sort, "player.") != ""
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)
}
WhereStruct(cfg.Filter)
}
if playerRequired {
query = query.Relation("Player._")
}
if cfg.Count {

View File

@ -7,5 +7,5 @@ import (
)
type Usecase interface {
Fetch(ctx context.Context, server string, filter *models.PlayerHistoryFilter) ([]*models.PlayerHistory, int, error)
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.PlayerHistory, int, error)
}

View File

@ -17,17 +17,23 @@ func New(repo playerhistory.Repository) playerhistory.Usecase {
return &usecase{repo}
}
func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.PlayerHistoryFilter) ([]*models.PlayerHistory, int, error) {
if filter == nil {
filter = &models.PlayerHistoryFilter{}
func (ucase *usecase) Fetch(ctx context.Context, cfg playerhistory.FetchConfig) ([]*models.PlayerHistory, int, error) {
if cfg.Filter == nil {
cfg.Filter = &models.PlayerHistoryFilter{}
}
if !middleware.CanExceedLimit(ctx) && (filter.Limit > playerhistory.PaginationLimit || filter.Limit <= 0) {
filter.Limit = playerhistory.PaginationLimit
if cfg.Filter.Limit > 0 {
cfg.Limit = cfg.Filter.Limit
}
filter.Sort = utils.SanitizeSortExpression(filter.Sort)
return ucase.repo.Fetch(ctx, playerhistory.FetchConfig{
Server: server,
Filter: filter,
Count: true,
})
if cfg.Filter.Offset > 0 {
cfg.Offset = cfg.Filter.Offset
}
if cfg.Filter.Sort != "" {
cfg.Sort = append(cfg.Sort, cfg.Filter.Sort)
}
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > playerhistory.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = playerhistory.PaginationLimit
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.Fetch(ctx, cfg)
}

View File

@ -7,9 +7,12 @@ import (
)
type FetchConfig struct {
Filter *models.ServerFilter
Filter *models.ServerFilter
Columns []string
Count bool
Count bool
Sort []string
Limit int
Offset int
}
type Repository interface {

View File

@ -7,6 +7,7 @@ import (
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
"github.com/tribalwarshelp/api/server"
"github.com/tribalwarshelp/api/utils"
"github.com/tribalwarshelp/shared/models"
)
@ -27,19 +28,20 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg server.FetchConfig) ([]
var err error
total := 0
data := []*models.Server{}
query := repo.Model(&data).Context(ctx)
query := repo.
Model(&data).
Context(ctx).
Order(cfg.Sort...).
Limit(cfg.Limit).
Offset(cfg.Offset)
versionRequired := utils.FindStringWithPrefix(cfg.Sort, "version.") != ""
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)
}
WhereStruct(cfg.Filter)
}
if versionRequired {
query = query.Relation("Version._")
}
if len(cfg.Columns) > 0 {
query = query.Column(cfg.Columns...)
}

View File

@ -7,6 +7,6 @@ import (
)
type Usecase interface {
Fetch(ctx context.Context, filter *models.ServerFilter) ([]*models.Server, int, error)
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Server, int, error)
GetByKey(ctx context.Context, key string) (*models.Server, error)
}

View File

@ -6,6 +6,7 @@ import (
"github.com/tribalwarshelp/api/middleware"
"github.com/tribalwarshelp/api/server"
"github.com/tribalwarshelp/api/utils"
"github.com/tribalwarshelp/shared/models"
)
@ -17,32 +18,40 @@ func New(repo server.Repository) server.Usecase {
return &usecase{repo}
}
func (ucase *usecase) Fetch(ctx context.Context, filter *models.ServerFilter) ([]*models.Server, int, error) {
if filter == nil {
filter = &models.ServerFilter{}
func (ucase *usecase) Fetch(ctx context.Context, cfg server.FetchConfig) ([]*models.Server, int, error) {
if cfg.Filter == nil {
cfg.Filter = &models.ServerFilter{}
}
if !middleware.CanExceedLimit(ctx) && (filter.Limit > server.PaginationLimit || filter.Limit <= 0) {
filter.Limit = server.PaginationLimit
if cfg.Filter.Limit > 0 {
cfg.Limit = cfg.Filter.Limit
}
if len(filter.LangVersionTag) > 0 {
filter.VersionCode = append(filter.VersionCode, filter.LangVersionTag...)
if cfg.Filter.Offset > 0 {
cfg.Offset = cfg.Filter.Offset
}
if len(filter.LangVersionTagNEQ) > 0 {
filter.VersionCodeNEQ = append(filter.VersionCode, filter.LangVersionTagNEQ...)
if cfg.Filter.Sort != "" {
cfg.Sort = append(cfg.Sort, cfg.Filter.Sort)
}
// filter.Sort = utils.SanitizeSortExpression(filter.Sort)
return ucase.repo.Fetch(ctx, server.FetchConfig{
Count: true,
Filter: filter,
})
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > server.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = server.PaginationLimit
}
if len(cfg.Filter.LangVersionTag) > 0 {
cfg.Filter.VersionCode = append(cfg.Filter.VersionCode, cfg.Filter.LangVersionTag...)
}
if len(cfg.Filter.LangVersionTagNEQ) > 0 {
cfg.Filter.VersionCodeNEQ = append(cfg.Filter.VersionCode, cfg.Filter.LangVersionTagNEQ...)
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.Fetch(ctx, cfg)
}
func (ucase *usecase) GetByKey(ctx context.Context, key string) (*models.Server, error) {
servers, _, err := ucase.repo.Fetch(ctx, server.FetchConfig{
Filter: &models.ServerFilter{
Key: []string{key},
Limit: 1,
Key: []string{key},
},
Limit: 1,
Count: false,
})
if err != nil {
return nil, err