feat: add the DeletedAt field to Player and Tribe
This commit is contained in:
parent
f246e205b4
commit
06e8706115
|
@ -18,6 +18,7 @@ type Player struct {
|
|||
Rank int64 `bun:"rank,default:0"`
|
||||
TribeID int64 `bun:"tribe_id,nullzero"`
|
||||
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
|
||||
DeletedAt time.Time `bun:"deleted_at,nullzero"`
|
||||
|
||||
OpponentsDefeated
|
||||
}
|
||||
|
@ -49,5 +50,6 @@ func (p Player) ToDomain() domain.Player {
|
|||
},
|
||||
ServerKey: p.ServerKey,
|
||||
CreatedAt: p.CreatedAt,
|
||||
DeletedAt: p.DeletedAt,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ type Tribe struct {
|
|||
Rank int64 `bun:"rank,default:0"`
|
||||
Dominance float64 `bun:"dominance,default:0"`
|
||||
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
|
||||
DeletedAt time.Time `bun:"deleted_at,nullzero"`
|
||||
|
||||
OpponentsDefeated
|
||||
}
|
||||
|
@ -58,5 +59,6 @@ func (t Tribe) ToDomain() domain.Tribe {
|
|||
ServerKey: t.ServerKey,
|
||||
Dominance: t.Dominance,
|
||||
CreatedAt: t.CreatedAt,
|
||||
DeletedAt: t.DeletedAt,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/bundb/internal/model"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
|
||||
return db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
||||
models := []interface{}{
|
||||
&model.Player{},
|
||||
&model.Tribe{},
|
||||
}
|
||||
for _, m := range models {
|
||||
if _, err := db.NewAddColumn().
|
||||
Model(m).
|
||||
ColumnExpr("deleted_at timestamp with time zone").
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't add the deleted_at column (model=%T): %w", m, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}, func(ctx context.Context, db *bun.DB) error {
|
||||
return db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
||||
models := []interface{}{
|
||||
&model.Player{},
|
||||
&model.Tribe{},
|
||||
}
|
||||
for _, m := range models {
|
||||
if _, err := db.NewDropColumn().
|
||||
Model(m).
|
||||
Column("deleted_at").
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't drop the deleted_at column (model=%T): %w", m, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/bundb/internal/model"
|
||||
|
||||
|
@ -19,7 +20,7 @@ func NewPlayer(db *bun.DB) *Player {
|
|||
return &Player{db: db}
|
||||
}
|
||||
|
||||
func (t *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error {
|
||||
func (p *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error {
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ func (t *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlay
|
|||
for _, p := range params {
|
||||
players = append(players, model.NewPlayer(p))
|
||||
}
|
||||
if _, err := t.db.NewInsert().
|
||||
if _, err := p.db.NewInsert().
|
||||
Model(&players).
|
||||
On("CONFLICT ON CONSTRAINT players_pkey DO UPDATE").
|
||||
Set("name = EXCLUDED.name").
|
||||
|
@ -36,6 +37,7 @@ func (t *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlay
|
|||
Set("points = EXCLUDED.points").
|
||||
Set("rank = EXCLUDED.rank").
|
||||
Set("tribe_id = EXCLUDED.tribe_id").
|
||||
Set("deleted_at = null").
|
||||
Apply(appendODSetClauses).
|
||||
Returning("NULL").
|
||||
Exec(ctx); err != nil {
|
||||
|
@ -45,12 +47,30 @@ func (t *Player) CreateOrUpdate(ctx context.Context, params ...domain.CreatePlay
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *Player) List(ctx context.Context, params domain.ListPlayersParams) ([]domain.Player, int64, error) {
|
||||
func (p *Player) DeleteByID(ctx context.Context, ids ...int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := p.db.NewUpdate().
|
||||
Model(&model.Player{}).
|
||||
Where("deleted_at IS NULL").
|
||||
Where("id IN (?)", bun.In(ids)).
|
||||
Set("deleted_at = ?", time.Now()).
|
||||
Returning("NULL").
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't delete players: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) List(ctx context.Context, params domain.ListPlayersParams) ([]domain.Player, int64, error) {
|
||||
var players []model.Player
|
||||
var count int
|
||||
var err error
|
||||
|
||||
q := t.db.NewSelect().
|
||||
q := p.db.NewSelect().
|
||||
Model(&players).
|
||||
Order("server_key ASC", "id ASC").
|
||||
Apply((listPlayersParamsApplier{params}).Apply)
|
||||
|
|
|
@ -159,6 +159,40 @@ func TestPlayer_CreateOrUpdate(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestPlayer_DeleteByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := newDB(t)
|
||||
fixture := loadFixtures(t, db)
|
||||
repo := bundb.NewPlayer(db)
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
playerChceszRemont := getPlayerFromFixture(t, fixture, "pl169-chcesz-remont")
|
||||
require.Zero(t, playerChceszRemont.DeletedAt)
|
||||
playerMaddov := getPlayerFromFixture(t, fixture, "pl169-maddov")
|
||||
require.Zero(t, playerMaddov.DeletedAt)
|
||||
|
||||
assert.NoError(t, repo.DeleteByID(context.Background(), playerChceszRemont.ID, playerMaddov.ID))
|
||||
players, _, err := repo.List(context.Background(), domain.ListPlayersParams{
|
||||
IDs: []int64{playerChceszRemont.ID, playerMaddov.ID},
|
||||
ServerKeys: []string{playerChceszRemont.ServerKey},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, players, 2)
|
||||
for _, player := range players {
|
||||
assert.WithinDuration(t, time.Now(), player.DeletedAt, 1*time.Second)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("OK: len(ids) == 0", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.NoError(t, repo.DeleteByID(context.Background()))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPlayer_List(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/core/internal/bundb/internal/model"
|
||||
|
||||
|
@ -45,6 +46,7 @@ func (t *Tribe) CreateOrUpdate(ctx context.Context, params ...domain.CreateTribe
|
|||
Set("points = EXCLUDED.points").
|
||||
Set("all_points = EXCLUDED.all_points").
|
||||
Set("rank = EXCLUDED.rank").
|
||||
Set("deleted_at = null").
|
||||
Apply(appendODSetClauses).
|
||||
Returning("NULL").
|
||||
Exec(ctx); err != nil {
|
||||
|
@ -54,6 +56,46 @@ func (t *Tribe) CreateOrUpdate(ctx context.Context, params ...domain.CreateTribe
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *Tribe) DeleteByID(ctx context.Context, ids ...int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := t.db.NewUpdate().
|
||||
Model(&model.Tribe{}).
|
||||
Where("deleted_at IS NULL").
|
||||
Where("id IN (?)", bun.In(ids)).
|
||||
Set("deleted_at = ?", time.Now()).
|
||||
Returning("NULL").
|
||||
Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't delete tribes: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tribe) UpdateDominance(ctx context.Context, serverKey string, numPlayerVillages int64) error {
|
||||
if numPlayerVillages < 0 {
|
||||
return ErrNumPlayerVillagesGTE
|
||||
}
|
||||
|
||||
q := t.db.NewUpdate().
|
||||
Model(&model.Tribe{}).
|
||||
Returning("NULL").
|
||||
Where("server_key = ?", serverKey).
|
||||
Where("deleted_at IS NULL")
|
||||
if numPlayerVillages > 0 {
|
||||
q = q.Set("dominance = num_villages::double precision / ? * 100", numPlayerVillages)
|
||||
} else {
|
||||
q = q.Set("dominance = 0")
|
||||
}
|
||||
if _, err := q.Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't update dominance (server=%s): %w", serverKey, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tribe) List(ctx context.Context, params domain.ListTribesParams) ([]domain.Tribe, int64, error) {
|
||||
var tribes []model.Tribe
|
||||
var count int
|
||||
|
@ -79,27 +121,6 @@ func (t *Tribe) List(ctx context.Context, params domain.ListTribesParams) ([]dom
|
|||
return result, int64(count), nil
|
||||
}
|
||||
|
||||
func (t *Tribe) UpdateDominance(ctx context.Context, serverKey string, numPlayerVillages int64) error {
|
||||
if numPlayerVillages < 0 {
|
||||
return ErrNumPlayerVillagesGTE
|
||||
}
|
||||
|
||||
q := t.db.NewUpdate().
|
||||
Model(&model.Tribe{}).
|
||||
Returning("NULL").
|
||||
Where("server_key = ?", serverKey)
|
||||
if numPlayerVillages > 0 {
|
||||
q = q.Set("dominance = num_villages::double precision / ? * 100", numPlayerVillages)
|
||||
} else {
|
||||
q = q.Set("dominance = 0")
|
||||
}
|
||||
if _, err := q.Exec(ctx); err != nil {
|
||||
return fmt.Errorf("couldn't update dominance (server=%s): %w", serverKey, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type listTribesParamsApplier struct {
|
||||
params domain.ListTribesParams
|
||||
}
|
||||
|
|
|
@ -164,6 +164,40 @@ func TestTribe_CreateOrUpdate(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestTribe_DeleteByID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := newDB(t)
|
||||
fixture := loadFixtures(t, db)
|
||||
repo := bundb.NewTribe(db)
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tribeCSA := getTribeFromFixture(t, fixture, "pl169-csa")
|
||||
require.Zero(t, tribeCSA.DeletedAt)
|
||||
tribeCSAJR := getTribeFromFixture(t, fixture, "pl169-csa-jr")
|
||||
require.Zero(t, tribeCSAJR.DeletedAt)
|
||||
|
||||
assert.NoError(t, repo.DeleteByID(context.Background(), tribeCSA.ID, tribeCSAJR.ID))
|
||||
tribes, _, err := repo.List(context.Background(), domain.ListTribesParams{
|
||||
IDs: []int64{tribeCSA.ID, tribeCSAJR.ID},
|
||||
ServerKeys: []string{tribeCSA.ServerKey},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, tribes, 2)
|
||||
for _, tribe := range tribes {
|
||||
assert.WithinDuration(t, time.Now(), tribe.DeletedAt, 1*time.Second)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("OK: len(ids) == 0", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.NoError(t, repo.DeleteByID(context.Background()))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTribe_List(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ type Player struct {
|
|||
|
||||
ServerKey string
|
||||
CreatedAt time.Time
|
||||
DeletedAt time.Time
|
||||
}
|
||||
|
||||
type CreatePlayerParams struct {
|
||||
|
|
|
@ -21,6 +21,7 @@ type Tribe struct {
|
|||
ServerKey string
|
||||
Dominance float64
|
||||
CreatedAt time.Time
|
||||
DeletedAt time.Time
|
||||
}
|
||||
|
||||
type CreateTribeParams struct {
|
||||
|
|
Reference in New Issue
Block a user