[WIP] - refactor limit, sort, offset

- update the Version/Village repository and usecase
This commit is contained in:
Dawid Wysokiński 2020-11-21 12:34:25 +01:00
parent c18807c2f5
commit fb84bdbc55
15 changed files with 262 additions and 85 deletions

View File

@ -233,9 +233,9 @@ type ComplexityRoot struct {
TribeHistory func(childComplexity int, server string, filter *models.TribeHistoryFilter, limit *int, offset *int, sort []string) int
Tribes func(childComplexity int, server string, filter *models.TribeFilter, limit *int, offset *int, sort []string) int
Version func(childComplexity int, code models.VersionCode) int
Versions func(childComplexity int, filter *models.VersionFilter) int
Versions func(childComplexity int, filter *models.VersionFilter, limit *int, offset *int, sort []string) int
Village func(childComplexity int, server string, id int) int
Villages func(childComplexity int, server string, filter *models.VillageFilter) int
Villages func(childComplexity int, server string, filter *models.VillageFilter, limit *int, offset *int, sort []string) int
}
Server struct {
@ -595,9 +595,9 @@ type QueryResolver interface {
TribeHistory(ctx context.Context, server string, filter *models.TribeHistoryFilter, limit *int, offset *int, sort []string) (*TribeHistory, error)
LangVersions(ctx context.Context, filter *models.VersionFilter) (*VersionList, error)
LangVersion(ctx context.Context, tag models.VersionCode) (*models.Version, error)
Versions(ctx context.Context, filter *models.VersionFilter) (*VersionList, error)
Versions(ctx context.Context, filter *models.VersionFilter, limit *int, offset *int, sort []string) (*VersionList, error)
Version(ctx context.Context, code models.VersionCode) (*models.Version, error)
Villages(ctx context.Context, server string, filter *models.VillageFilter) (*VillageList, error)
Villages(ctx context.Context, server string, filter *models.VillageFilter, limit *int, offset *int, sort []string) (*VillageList, error)
Village(ctx context.Context, server string, id int) (*models.Village, error)
}
type ServerResolver interface {
@ -1681,7 +1681,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.Versions(childComplexity, args["filter"].(*models.VersionFilter)), true
return e.complexity.Query.Versions(childComplexity, args["filter"].(*models.VersionFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string)), true
case "Query.village":
if e.complexity.Query.Village == nil {
@ -1705,7 +1705,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.Villages(childComplexity, args["server"].(string), args["filter"].(*models.VillageFilter)), true
return e.complexity.Query.Villages(childComplexity, args["server"].(string), args["filter"].(*models.VillageFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string)), true
case "Server.buildingConfig":
if e.complexity.Server.BuildingConfig == nil {
@ -4327,7 +4327,9 @@ type UnitConfig {
}
type Version {
tag: VersionCode! @goField(forceResolver: true) @deprecated(reason: "Use ` + "`" + `code` + "`" + `.")
tag: VersionCode!
@goField(forceResolver: true)
@deprecated(reason: "Use ` + "`" + `code` + "`" + `.")
code: VersionCode!
name: String!
host: String!
@ -4346,8 +4348,17 @@ input VersionFilter {
hostIEQ: String
offset: Int
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `offset` + "`" + `."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `limit` + "`" + `."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `sort` + "`" + `."
)
}
type VersionList {
@ -4356,9 +4367,15 @@ type VersionList {
}
extend type Query {
langVersions(filter: VersionFilter): VersionList! @deprecated(reason: "Use ` + "`" + `versions` + "`" + `.")
langVersions(filter: VersionFilter): VersionList!
@deprecated(reason: "Use ` + "`" + `versions` + "`" + `.")
langVersion(tag: VersionCode!): Version @deprecated(reason: "Use ` + "`" + `version` + "`" + `.")
versions(filter: VersionFilter): VersionList!
versions(
filter: VersionFilter
limit: Int
offset: Int
sort: [String!]
): VersionList!
version(code: VersionCode!): Version
}
`, BuiltIn: false},
@ -4412,12 +4429,27 @@ input VillageFilter {
playerFilter: PlayerFilter
offset: Int
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `offset` + "`" + `."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `limit` + "`" + `."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query versions - ` + "`" + `sort` + "`" + `."
)
}
extend type Query {
villages(server: String!, filter: VillageFilter): VillageList!
villages(
server: String!
filter: VillageFilter
limit: Int
offset: Int
sort: [String!]
): VillageList!
village(server: String!, id: Int!): Village
}
`, BuiltIn: false},
@ -5079,6 +5111,33 @@ func (ec *executionContext) field_Query_versions_args(ctx context.Context, rawAr
}
}
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
}
@ -5127,6 +5186,33 @@ func (ec *executionContext) field_Query_villages_args(ctx context.Context, rawAr
}
}
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
}
@ -9958,7 +10044,7 @@ func (ec *executionContext) _Query_versions(ctx context.Context, field graphql.C
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().Versions(rctx, args["filter"].(*models.VersionFilter))
return ec.resolvers.Query().Versions(rctx, args["filter"].(*models.VersionFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string))
})
if err != nil {
ec.Error(ctx, err)
@ -10039,7 +10125,7 @@ func (ec *executionContext) _Query_villages(ctx context.Context, field graphql.C
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().Villages(rctx, args["server"].(string), args["filter"].(*models.VillageFilter))
return ec.resolvers.Query().Villages(rctx, args["server"].(string), args["filter"].(*models.VillageFilter), args["limit"].(*int), args["offset"].(*int), args["sort"].([]string))
})
if err != nil {
ec.Error(ctx, err)

View File

@ -55,6 +55,7 @@ func (r *Resolver) TribeChanges(ctx context.Context,
Limit: *limit,
Offset: *offset,
Count: true,
Server: server,
})
return list, err
}

View File

@ -39,6 +39,7 @@ func (r *Resolver) TribeHistory(ctx context.Context,
Limit: *limit,
Offset: *offset,
Count: true,
Server: server,
})
return list, err
}

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/tribalwarshelp/api/graphql/generated"
"github.com/tribalwarshelp/api/version"
"github.com/tribalwarshelp/shared/models"
)
@ -11,10 +12,29 @@ func (r *versionResolver) Tag(ctx context.Context, obj *models.Version) (models.
return obj.Code, nil
}
func (r *queryResolver) Versions(ctx context.Context, filter *models.VersionFilter) (*generated.VersionList, error) {
func (r *queryResolver) Versions(ctx context.Context,
f *models.VersionFilter,
limit *int,
offset *int,
sort []string) (*generated.VersionList, error) {
defLimit := 0
defOffset := 0
if limit == nil {
limit = &defLimit
}
if offset == nil {
offset = &defOffset
}
var err error
list := &generated.VersionList{}
list.Items, list.Total, err = r.VersionUcase.Fetch(ctx, filter)
list.Items, list.Total, err = r.VersionUcase.Fetch(ctx, version.FetchConfig{
Filter: f,
Sort: sort,
Limit: *limit,
Offset: *offset,
Count: true,
})
return list, err
}
@ -23,7 +43,7 @@ func (r *queryResolver) Version(ctx context.Context, code models.VersionCode) (*
}
func (r *queryResolver) LangVersions(ctx context.Context, filter *models.VersionFilter) (*generated.VersionList, error) {
return r.Versions(ctx, filter)
return r.Versions(ctx, filter, nil, nil, []string{})
}
func (r *queryResolver) LangVersion(ctx context.Context, tag models.VersionCode) (*models.Version, error) {

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/tribalwarshelp/api/graphql/generated"
"github.com/tribalwarshelp/api/village"
"github.com/tribalwarshelp/shared/models"
)
@ -15,10 +16,31 @@ func (r *villageResolver) Player(ctx context.Context, obj *models.Village) (*mod
return getPlayer(ctx, obj.PlayerID), nil
}
func (r *queryResolver) Villages(ctx context.Context, server string, filter *models.VillageFilter) (*generated.VillageList, error) {
func (r *queryResolver) Villages(ctx context.Context,
server string,
f *models.VillageFilter,
limit *int,
offset *int,
sort []string) (*generated.VillageList, error) {
defLimit := 0
defOffset := 0
if limit == nil {
limit = &defLimit
}
if offset == nil {
offset = &defOffset
}
var err error
list := &generated.VillageList{}
list.Items, list.Total, err = r.VillageUcase.Fetch(ctx, server, filter)
list.Items, list.Total, err = r.VillageUcase.Fetch(ctx, village.FetchConfig{
Filter: f,
Sort: sort,
Limit: *limit,
Offset: *offset,
Count: true,
Server: server,
})
return list, err
}

View File

@ -20,7 +20,9 @@ enum VersionCode {
}
type Version {
tag: VersionCode! @goField(forceResolver: true) @deprecated(reason: "Use `code`.")
tag: VersionCode!
@goField(forceResolver: true)
@deprecated(reason: "Use `code`.")
code: VersionCode!
name: String!
host: String!
@ -39,8 +41,17 @@ input VersionFilter {
hostIEQ: String
offset: Int
@deprecated(
reason: "Use a new variable added to the query versions - `offset`."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query versions - `limit`."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query versions - `sort`."
)
}
type VersionList {
@ -49,8 +60,14 @@ type VersionList {
}
extend type Query {
langVersions(filter: VersionFilter): VersionList! @deprecated(reason: "Use `versions`.")
langVersions(filter: VersionFilter): VersionList!
@deprecated(reason: "Use `versions`.")
langVersion(tag: VersionCode!): Version @deprecated(reason: "Use `version`.")
versions(filter: VersionFilter): VersionList!
versions(
filter: VersionFilter
limit: Int
offset: Int
sort: [String!]
): VersionList!
version(code: VersionCode!): Version
}

View File

@ -48,11 +48,26 @@ input VillageFilter {
playerFilter: PlayerFilter
offset: Int
@deprecated(
reason: "Use a new variable added to the query versions - `offset`."
)
limit: Int
@deprecated(
reason: "Use a new variable added to the query versions - `limit`."
)
sort: String
@deprecated(
reason: "Use a new variable added to the query versions - `sort`."
)
}
extend type Query {
villages(server: String!, filter: VillageFilter): VillageList!
villages(
server: String!
filter: VillageFilter
limit: Int
offset: Int
sort: [String!]
): VillageList!
village(server: String!, id: Int!): Village
}

View File

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

View File

@ -27,17 +27,15 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg version.FetchConfig) ([
var err error
data := []*models.Version{}
total := 0
query := repo.Model(&data).Context(ctx)
query := repo.
Model(&data).
Context(ctx).
Order(cfg.Sort...).
Limit(cfg.Limit).
Offset(cfg.Offset)
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 cfg.Count {

View File

@ -7,6 +7,6 @@ import (
)
type Usecase interface {
Fetch(ctx context.Context, filter *models.VersionFilter) ([]*models.Version, int, error)
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Version, int, error)
GetByCode(ctx context.Context, code models.VersionCode) (*models.Version, error)
}

View File

@ -21,24 +21,30 @@ func New(repo version.Repository) version.Usecase {
}
}
func (ucase *usecase) Fetch(ctx context.Context, filter *models.VersionFilter) ([]*models.Version, int, error) {
if filter == nil {
filter = &models.VersionFilter{}
func (ucase *usecase) Fetch(ctx context.Context, cfg version.FetchConfig) ([]*models.Version, int, error) {
if cfg.Filter == nil {
cfg.Filter = &models.VersionFilter{}
}
if !middleware.CanExceedLimit(ctx) && (filter.Limit > version.PaginationLimit || filter.Limit <= 0) {
filter.Limit = version.PaginationLimit
if cfg.Filter.Limit > 0 {
cfg.Limit = cfg.Filter.Limit
}
if len(filter.Tag) > 0 {
filter.Code = append(filter.Code, filter.Tag...)
if cfg.Filter.Offset > 0 {
cfg.Offset = cfg.Filter.Offset
}
if len(filter.TagNEQ) > 0 {
filter.CodeNEQ = append(filter.Code, filter.TagNEQ...)
if cfg.Filter.Sort != "" {
cfg.Sort = append(cfg.Sort, cfg.Filter.Sort)
}
filter.Sort = utils.SanitizeSortExpression(filter.Sort)
return ucase.repo.Fetch(ctx, version.FetchConfig{
Filter: filter,
Count: true,
})
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > version.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = version.PaginationLimit
}
if len(cfg.Filter.Tag) > 0 {
cfg.Filter.Code = append(cfg.Filter.Code, cfg.Filter.Tag...)
}
if len(cfg.Filter.TagNEQ) > 0 {
cfg.Filter.CodeNEQ = append(cfg.Filter.Code, cfg.Filter.TagNEQ...)
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.Fetch(ctx, cfg)
}
func (ucase *usecase) GetByCode(ctx context.Context, code models.VersionCode) (*models.Version, error) {

View File

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

View File

@ -9,6 +9,7 @@ import (
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
"github.com/tribalwarshelp/api/utils"
"github.com/tribalwarshelp/api/village"
"github.com/tribalwarshelp/shared/models"
)
@ -24,13 +25,18 @@ func NewPGRepository(db *pg.DB) village.Repository {
func (repo *pgRepository) Fetch(ctx context.Context, cfg village.FetchConfig) ([]*models.Village, int, error) {
var err error
data := []*models.Village{}
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.") != ""
tribeRequired := utils.FindStringWithPrefix(cfg.Sort, "tribe.") != ""
if cfg.Filter != nil {
query = query.
WhereStruct(cfg.Filter).
Limit(cfg.Filter.Limit).
Offset(cfg.Filter.Offset)
WhereStruct(cfg.Filter)
if cfg.Filter.XGTE != 0 {
query = query.Where("x >= ?", cfg.Filter.XGTE)
@ -78,34 +84,24 @@ func (repo *pgRepository) Fetch(ctx context.Context, cfg village.FetchConfig) ([
return q, nil
})
}
order := []string{}
if cfg.Filter.Sort != "" {
order = append(order, cfg.Filter.Sort)
}
if cfg.Filter.PlayerFilter != nil {
query = query.Relation("Player._").WhereStruct(cfg.Filter.PlayerFilter)
if cfg.Filter.PlayerFilter.Sort != "" {
order = append(order, fmt.Sprintf("player.%s", cfg.Filter.PlayerFilter.Sort))
}
playerRequired = true
query = query.WhereStruct(cfg.Filter.PlayerFilter)
if cfg.Filter.PlayerFilter.TribeFilter != nil {
tribeRequired = true
query = query.
Join("LEFT JOIN ?SERVER.tribes AS tribe ON tribe.id = player.tribe_id").
WhereStruct(cfg.Filter.PlayerFilter.TribeFilter)
if cfg.Filter.PlayerFilter.TribeFilter.Sort != "" {
order = append(order, fmt.Sprintf("tribe.%s", cfg.Filter.PlayerFilter.TribeFilter.Sort))
}
}
}
query = query.Order(order...)
}
if playerRequired {
query = query.Relation("Player._")
}
if tribeRequired {
query = query.Join("LEFT JOIN ?SERVER.tribes AS tribe ON tribe.id = player.tribe_id")
}
if len(cfg.Columns) > 0 {
query = query.Column(cfg.Columns...)
}

View File

@ -7,6 +7,6 @@ import (
)
type Usecase interface {
Fetch(ctx context.Context, server string, filter *models.VillageFilter) ([]*models.Village, int, error)
Fetch(ctx context.Context, cfg FetchConfig) ([]*models.Village, int, error)
GetByID(ctx context.Context, server string, id int) (*models.Village, error)
}

View File

@ -18,25 +18,34 @@ func New(repo village.Repository) village.Usecase {
return &usecase{repo}
}
func (ucase *usecase) Fetch(ctx context.Context, server string, filter *models.VillageFilter) ([]*models.Village, int, error) {
if filter == nil {
filter = &models.VillageFilter{}
func (ucase *usecase) Fetch(ctx context.Context, cfg village.FetchConfig) ([]*models.Village, int, error) {
if cfg.Filter == nil {
cfg.Filter = &models.VillageFilter{}
}
if !middleware.CanExceedLimit(ctx) && (filter.Limit > village.PaginationLimit || filter.Limit <= 0) {
filter.Limit = village.PaginationLimit
if cfg.Filter.Limit > 0 {
cfg.Limit = cfg.Filter.Limit
}
filter.Sort = utils.SanitizeSortExpression(filter.Sort)
if filter.PlayerFilter != nil {
filter.PlayerFilter.Sort = utils.SanitizeSortExpression(filter.PlayerFilter.Sort)
if filter.PlayerFilter.TribeFilter != nil {
filter.PlayerFilter.TribeFilter.Sort = utils.SanitizeSortExpression(filter.PlayerFilter.TribeFilter.Sort)
if cfg.Filter.Offset > 0 {
cfg.Offset = cfg.Filter.Offset
}
if cfg.Filter.Sort != "" {
cfg.Sort = append(cfg.Sort, cfg.Filter.Sort)
}
if cfg.Filter.PlayerFilter != nil {
if cfg.Filter.PlayerFilter.Sort != "" {
cfg.Sort = append(cfg.Sort, "player."+cfg.Filter.PlayerFilter.Sort)
}
if cfg.Filter.PlayerFilter.TribeFilter != nil && cfg.Filter.PlayerFilter.TribeFilter.Sort != "" {
cfg.Sort = append(cfg.Sort, "tribe."+cfg.Filter.PlayerFilter.TribeFilter.Sort)
}
}
return ucase.repo.Fetch(ctx, village.FetchConfig{
Server: server,
Count: true,
Filter: filter,
})
if !middleware.CanExceedLimit(ctx) && (cfg.Limit > village.PaginationLimit || cfg.Limit <= 0) {
cfg.Limit = village.PaginationLimit
}
cfg.Sort = utils.SanitizeSortExpressions(cfg.Sort)
return ucase.repo.Fetch(ctx, cfg)
}
func (ucase *usecase) GetByID(ctx context.Context, server string, id int) (*models.Village, error) {