fix: optimize ennoblements query (#108)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

Reviewed-on: twhelp/core#108
This commit is contained in:
Dawid Wysokiński 2022-10-21 06:28:17 +00:00
parent 767eb5d5f2
commit 317559e29b

View File

@ -5,6 +5,7 @@ import (
"database/sql"
"errors"
"fmt"
"sync"
"gitea.dwysokinski.me/twhelp/core/internal/bundb/internal/model"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
@ -56,19 +57,28 @@ func (e *Ennoblement) List(
var count int
var err error
q := e.db.NewSelect().
Model(&ennoblements).
Order("ennoblement.server_key ASC")
paramsApplier := listEnnoblementsParamsApplier{params}
q, err = listEnnoblementsParamsApplier{params}.apply(q)
base := e.db.NewSelect().
Model(&model.Ennoblement{}).
Order("ennoblement.server_key ASC").
Apply(paramsApplier.applyFilters).
Apply(paramsApplier.applyPagination)
base, err = paramsApplier.applySort(base)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return nil, 0, fmt.Errorf("listEnnoblementsParamsApplier.apply: %w", err)
return nil, 0, fmt.Errorf("listEnnoblementsParamsApplier.applySort: %w", err)
}
q := e.db.NewSelect().
With("ennoblements_base", base).
Model(&ennoblements).
ModelTableExpr("ennoblements_base AS ennoblement").
Apply(paramsApplier.applyRelations)
if params.Count {
count, err = q.ScanAndCount(ctx)
count, err = e.listScanAndCount(ctx, base, q)
} else {
err = q.Scan(ctx)
}
@ -86,25 +96,53 @@ func (e *Ennoblement) List(
return result, int64(count), nil
}
func (e *Ennoblement) listScanAndCount(
ctx context.Context,
base *bun.SelectQuery,
q *bun.SelectQuery,
) (int, error) {
var wg sync.WaitGroup
var mu sync.Mutex
var count int
var err error
wg.Add(1)
go func() {
defer wg.Done()
if scanErr := q.Scan(ctx); scanErr == nil {
mu.Lock()
if err == nil {
err = scanErr
}
mu.Unlock()
}
}()
wg.Add(1)
go func() {
defer wg.Done()
var countErr error
if count, countErr = base.Count(ctx); countErr != nil {
mu.Lock()
if err == nil {
err = countErr
}
mu.Unlock()
}
}()
wg.Wait()
return count, err
}
type listEnnoblementsParamsApplier struct {
params domain.ListEnnoblementsParams
}
func (l listEnnoblementsParamsApplier) apply(q *bun.SelectQuery) (*bun.SelectQuery, error) {
var err error
if l.params.ServerKeys != nil {
q = q.Where("ennoblement.server_key IN (?)", bun.In(l.params.ServerKeys))
}
if l.params.CreatedAtGTE.Valid {
q = q.Where("ennoblement.created_at >= ?", l.params.CreatedAtGTE.Time)
}
if l.params.CreatedAtLTE.Valid {
q = q.Where("ennoblement.created_at <= ?", l.params.CreatedAtLTE.Time)
}
func (l listEnnoblementsParamsApplier) applyRelations(q *bun.SelectQuery) *bun.SelectQuery {
if l.params.IncludeVillage {
q = q.Relation("Village", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Column(villageMetaColumns...)
@ -135,12 +173,23 @@ func (l listEnnoblementsParamsApplier) apply(q *bun.SelectQuery) (*bun.SelectQue
})
}
q, err = l.applySort(q)
if err != nil {
return nil, fmt.Errorf("listEnnoblementsParamsApplier.applySort: %w", err)
return q
}
func (l listEnnoblementsParamsApplier) applyFilters(q *bun.SelectQuery) *bun.SelectQuery {
if l.params.ServerKeys != nil {
q = q.Where("ennoblement.server_key IN (?)", bun.In(l.params.ServerKeys))
}
return l.applyPagination(q), nil
if l.params.CreatedAtGTE.Valid {
q = q.Where("ennoblement.created_at >= ?", l.params.CreatedAtGTE.Time)
}
if l.params.CreatedAtLTE.Valid {
q = q.Where("ennoblement.created_at <= ?", l.params.CreatedAtLTE.Time)
}
return q
}
func (l listEnnoblementsParamsApplier) applySort(q *bun.SelectQuery) (*bun.SelectQuery, error) {