This repository has been archived on 2024-04-06. You can view files and clone it, but cannot push or open issues or pull requests.
core-old/internal/service/ennoblement.go
Dawid Wysokiński 767eb5d5f2
All checks were successful
continuous-integration/drone/push Build is passing
refactor: optimize queries and models (#107)
Reviewed-on: twhelp/core#107
2022-10-21 05:19:04 +00:00

185 lines
5.0 KiB
Go

package service
import (
"context"
"errors"
"fmt"
"time"
"gitea.dwysokinski.me/twhelp/core/internal/tw"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
)
const (
ennoblementChunkSize = 1000
ennoblementMaxLimit = 200
ennoblementSortMaxLen = 2
)
var (
errEnnoblementNotFound = errors.New("ennoblement not found")
)
//counterfeiter:generate -o internal/mock/ennoblement_repository.gen.go . EnnoblementRepository
type EnnoblementRepository interface {
Create(ctx context.Context, params ...domain.CreateEnnoblementParams) error
List(
ctx context.Context,
params domain.ListEnnoblementsParams,
) ([]domain.EnnoblementWithRelations, int64, error)
}
//counterfeiter:generate -o internal/mock/ennoblement_getter.gen.go . EnnoblementGetter
type EnnoblementGetter interface {
GetEnnoblements(ctx context.Context, baseURL string, since time.Time) ([]tw.Ennoblement, error)
}
type Ennoblement struct {
repo EnnoblementRepository
client EnnoblementGetter
}
func NewEnnoblement(repo EnnoblementRepository, client EnnoblementGetter) *Ennoblement {
return &Ennoblement{repo: repo, client: client}
}
func (e *Ennoblement) Refresh(ctx context.Context, key, url string) error {
ctx, span := tracer.Start(ctx, "Ennoblement.Refresh", trace.WithAttributes(
attribute.String("server.key", key),
attribute.String("server.url", url),
))
defer span.End()
latestEnnoblement, err := e.getLatestEnnoblement(ctx, key)
if err != nil && !errors.Is(err, errEnnoblementNotFound) {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return fmt.Errorf("EnnoblementService.getLatestEnnoblements: %w", err)
}
var since time.Time
if err == nil {
since = latestEnnoblement.CreatedAt
}
span.SetAttributes(attribute.Int64("since", since.Unix()))
ennoblements, err := e.client.GetEnnoblements(ctx, url, since)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return fmt.Errorf("TWClient.GetEnnoblements: %w", err)
}
for i := 0; i < len(ennoblements); i += ennoblementChunkSize {
end := i + ennoblementChunkSize
if end > len(ennoblements) {
end = len(ennoblements)
}
chunk := ennoblements[i:end]
params := make([]domain.CreateEnnoblementParams, 0, len(chunk))
for _, ennoblement := range chunk {
params = append(params, domain.CreateEnnoblementParams{
VillageID: ennoblement.VillageID,
NewOwnerID: ennoblement.NewOwnerID,
NewTribeID: ennoblement.NewTribeID,
OldOwnerID: ennoblement.OldOwnerID,
OldTribeID: ennoblement.OldTribeID,
Points: ennoblement.Points,
CreatedAt: ennoblement.CreatedAt,
ServerKey: key,
})
}
if err = e.repo.Create(ctx, params...); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return fmt.Errorf("EnnoblementRepository.Create: %w", err)
}
}
return nil
}
func (e *Ennoblement) List(
ctx context.Context,
params domain.ListEnnoblementsParams,
) ([]domain.EnnoblementWithRelations, int64, error) {
ctx, span := tracer.Start(ctx, "Ennoblement.List")
defer span.End()
if len(params.Sort) == 0 {
params.Sort = []domain.EnnoblementSort{
{
By: domain.EnnoblementSortByID,
Direction: domain.SortDirectionASC,
},
}
}
if len(params.Sort) > ennoblementSortMaxLen {
err := domain.ValidationError{
Field: "sort",
Err: domain.MaxLengthError{
Max: ennoblementSortMaxLen,
},
}
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return nil, 0, err
}
if params.Pagination.Limit == 0 {
params.Pagination.Limit = ennoblementMaxLimit
}
if err := validatePagination(params.Pagination, ennoblementMaxLimit); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return nil, 0, fmt.Errorf("validatePagination: %w", err)
}
ennoblements, count, err := e.repo.List(ctx, params)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return nil, 0, fmt.Errorf("EnnoblementRepository.List: %w", err)
}
return ennoblements, count, nil
}
func (e *Ennoblement) getLatestEnnoblement(ctx context.Context, key string) (domain.EnnoblementWithRelations, error) {
ctx, span := tracer.Start(ctx, "Ennoblement.getLatestEnnoblement", trace.WithAttributes(
attribute.String("server.key", key),
))
defer span.End()
ennoblements, _, err := e.repo.List(ctx, domain.ListEnnoblementsParams{
ServerKeys: []string{key},
Pagination: domain.Pagination{
Limit: 1,
},
Sort: []domain.EnnoblementSort{
{By: domain.EnnoblementSortByCreatedAt, Direction: domain.SortDirectionDESC},
},
Count: false,
})
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return domain.EnnoblementWithRelations{}, fmt.Errorf("EnnoblementRepository.List: %w", err)
}
if len(ennoblements) == 0 {
span.RecordError(errEnnoblementNotFound)
return domain.EnnoblementWithRelations{}, errEnnoblementNotFound
}
return ennoblements[0], nil
}