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/bundb/server.go
Dawid Wysokiński badb7276fb
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
refactor: check if len() > 0 instead of != nil for slices
2023-02-08 07:04:22 +01:00

303 lines
8.3 KiB
Go

package bundb
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
"gitea.dwysokinski.me/twhelp/core/internal/bundb/internal/model"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
"github.com/uptrace/bun"
)
var (
serverMetaColumns = []string{"key", "open", "url"}
)
type Server struct {
db *bun.DB
}
func NewServer(db *bun.DB) *Server {
return &Server{db: db}
}
func (s *Server) CreateOrUpdate(ctx context.Context, params ...domain.CreateServerParams) ([]domain.Server, error) {
if len(params) == 0 {
return nil, nil
}
servers := make([]model.Server, 0, len(params))
for _, p := range params {
servers = append(servers, model.Server{
Key: p.Key,
URL: p.URL,
Open: p.Open,
Special: false,
VersionCode: p.VersionCode,
CreatedAt: time.Now(),
})
}
if _, err := s.db.NewInsert().
Model(&servers).
On("CONFLICT ON CONSTRAINT servers_pkey DO UPDATE").
Set("url = EXCLUDED.url").
Set("open = EXCLUDED.open").
Returning("*").
Exec(ctx); err != nil {
return nil, fmt.Errorf("something went wrong while inserting servers into the db: %w", err)
}
result := make([]domain.Server, 0, len(servers))
for _, srv := range servers {
result = append(result, srv.ToDomain())
}
return result, nil
}
func (s *Server) List(ctx context.Context, params domain.ListServersParams) ([]domain.Server, error) {
var servers []model.Server
if err := s.buildListQuery(&servers, params).Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("couldn't select servers from the db: %w", err)
}
result := make([]domain.Server, 0, len(servers))
for _, server := range servers {
result = append(result, server.ToDomain())
}
return result, nil
}
func (s *Server) ListCount(ctx context.Context, params domain.ListServersParams) ([]domain.Server, int64, error) {
var servers []model.Server
q := s.buildListQuery(&servers, params)
count, err := scanAndCount(ctx, q, q)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, 0, fmt.Errorf("couldn't select servers from the db: %w", err)
}
result := make([]domain.Server, 0, len(servers))
for _, server := range servers {
result = append(result, server.ToDomain())
}
return result, int64(count), nil
}
func (s *Server) buildListQuery(servers *[]model.Server, params domain.ListServersParams) *bun.SelectQuery {
return s.db.NewSelect().
Model(servers).
Order("server.version_code ASC", "server.open DESC", "server.key ASC").
Apply(listServersParamsApplier{params}.apply)
}
func (s *Server) Update(ctx context.Context, key string, params domain.UpdateServerParams) (domain.Server, error) {
if params.IsZero() {
return domain.Server{}, domain.ErrNothingToUpdate
}
var server model.Server
res, err := s.db.NewUpdate().
Model(&server).
Where("key = ?", key).
Apply(updateServerParamsApplier{params}.apply).
Returning("*").
Exec(ctx)
if err != nil {
return domain.Server{}, fmt.Errorf("couldn't update server (key=%s): %w", key, err)
}
if affected, _ := res.RowsAffected(); affected == 0 {
return domain.Server{}, domain.ServerNotFoundError{
Key: key,
}
}
return server.ToDomain(), nil
}
type listServersParamsApplier struct {
params domain.ListServersParams
}
func (l listServersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
return q.Apply(l.applyFilters).Apply(l.applyPagination)
}
func (l listServersParamsApplier) applyFilters(q *bun.SelectQuery) *bun.SelectQuery {
if l.params.Open.Valid {
q = q.Where("server.open = ?", l.params.Open.Bool)
}
if l.params.Special.Valid {
q = q.Where("server.special = ?", l.params.Special.Bool)
}
if len(l.params.VersionCodes) > 0 {
q = q.Where("server.version_code IN (?)", bun.In(l.params.VersionCodes))
}
if len(l.params.Keys) > 0 {
q = q.Where("server.key IN (?)", bun.In(l.params.Keys))
}
if !l.params.PlayerSnapshotsCreatedAtLT.IsZero() {
q = q.Where(
"server.player_snapshots_created_at < ? OR server.player_snapshots_created_at is null",
l.params.PlayerSnapshotsCreatedAtLT,
)
}
if !l.params.TribeSnapshotsCreatedAtLT.IsZero() {
q = q.Where(
"server.tribe_snapshots_created_at < ? OR server.tribe_snapshots_created_at is null",
l.params.TribeSnapshotsCreatedAtLT,
)
}
return q
}
func (l listServersParamsApplier) applyPagination(q *bun.SelectQuery) *bun.SelectQuery {
return (paginationApplier{pagination: l.params.Pagination}).apply(q)
}
type updateServerParamsApplier struct {
params domain.UpdateServerParams
}
func (u updateServerParamsApplier) apply(q *bun.UpdateQuery) *bun.UpdateQuery {
for _, fn := range [...]func(*bun.UpdateQuery) *bun.UpdateQuery{
u.applyConfig,
u.applyUnitInfo,
u.applyBuildingInfo,
u.applyNumPlayers,
u.applyPlayerDataUpdatedAt,
u.applyNumTribes,
u.applyTribeDataUpdatedAt,
u.applyNumVillages,
u.applyNumPlayerVillages,
u.applyNumBarbarianVillages,
u.applyNumBonusVillages,
u.applyVillageDataUpdatedAt,
u.applyEnnoblementDataUpdatedAt,
u.applyPlayerSnapshotsCreatedAt,
u.applyTribeSnapshotsCreatedAt,
} {
q = fn(q)
}
return q
}
func (u updateServerParamsApplier) applyConfig(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.Config.Valid {
return q
}
return q.Set("config = ?", model.NewServerConfig(u.params.Config.Config))
}
func (u updateServerParamsApplier) applyUnitInfo(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.UnitInfo.Valid {
return q
}
return q.Set("unit_info = ?", model.NewUnitInfo(u.params.UnitInfo.Info))
}
func (u updateServerParamsApplier) applyBuildingInfo(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.BuildingInfo.Valid {
return q
}
return q.Set("building_info = ?", model.NewBuildingInfo(u.params.BuildingInfo.Info))
}
func (u updateServerParamsApplier) applyNumPlayers(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumPlayers.Valid {
return q
}
return q.Set("num_players = ?", u.params.NumPlayers.Int64)
}
func (u updateServerParamsApplier) applyPlayerDataUpdatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.PlayerDataUpdatedAt.IsZero() {
return q
}
return q.Set("player_data_updated_at = ?", u.params.PlayerDataUpdatedAt)
}
func (u updateServerParamsApplier) applyNumTribes(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumTribes.Valid {
return q
}
return q.Set("num_tribes = ?", u.params.NumTribes.Int64)
}
func (u updateServerParamsApplier) applyTribeDataUpdatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.TribeDataUpdatedAt.IsZero() {
return q
}
return q.Set("tribe_data_updated_at = ?", u.params.TribeDataUpdatedAt)
}
func (u updateServerParamsApplier) applyNumVillages(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumVillages.Valid {
return q
}
return q.Set("num_villages = ?", u.params.NumVillages.Int64)
}
func (u updateServerParamsApplier) applyNumPlayerVillages(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumPlayerVillages.Valid {
return q
}
return q.Set("num_player_villages = ?", u.params.NumPlayerVillages.Int64)
}
func (u updateServerParamsApplier) applyNumBarbarianVillages(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumBarbarianVillages.Valid {
return q
}
return q.Set("num_barbarian_villages = ?", u.params.NumBarbarianVillages.Int64)
}
func (u updateServerParamsApplier) applyNumBonusVillages(q *bun.UpdateQuery) *bun.UpdateQuery {
if !u.params.NumBonusVillages.Valid {
return q
}
return q.Set("num_bonus_villages = ?", u.params.NumBonusVillages.Int64)
}
func (u updateServerParamsApplier) applyVillageDataUpdatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.VillageDataUpdatedAt.IsZero() {
return q
}
return q.Set("village_data_updated_at = ?", u.params.VillageDataUpdatedAt)
}
func (u updateServerParamsApplier) applyEnnoblementDataUpdatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.EnnoblementDataUpdatedAt.IsZero() {
return q
}
return q.Set("ennoblement_data_updated_at = ?", u.params.EnnoblementDataUpdatedAt)
}
func (u updateServerParamsApplier) applyPlayerSnapshotsCreatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.PlayerSnapshotsCreatedAt.IsZero() {
return q
}
return q.Set("player_snapshots_created_at = ?", u.params.PlayerSnapshotsCreatedAt)
}
func (u updateServerParamsApplier) applyTribeSnapshotsCreatedAt(q *bun.UpdateQuery) *bun.UpdateQuery {
if u.params.TribeSnapshotsCreatedAt.IsZero() {
return q
}
return q.Set("tribe_snapshots_created_at = ?", u.params.TribeSnapshotsCreatedAt)
}