feat: add a new domain model - PlayerSnapshotWithRelations
This commit is contained in:
parent
267953ea61
commit
387fe30b82
|
@ -114,7 +114,7 @@ func getErrorCodesFromFolder(root string) (map[string]string, error) {
|
|||
break
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "ignorecode") {
|
||||
if strings.Contains(desc, "errorcode:ignore") {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,36 @@ func (repo *PlayerSnapshotBunRepository) List(
|
|||
return domain.NewListPlayerSnapshotsResult(separateListResultAndNext(converted, params.Limit()))
|
||||
}
|
||||
|
||||
func (repo *PlayerSnapshotBunRepository) ListWithRelations(
|
||||
ctx context.Context,
|
||||
params domain.ListPlayerSnapshotsParams,
|
||||
) (domain.ListPlayerSnapshotsWithRelationsResult, error) {
|
||||
var playerSnapshots bunmodel.PlayerSnapshots
|
||||
|
||||
if err := repo.db.NewSelect().
|
||||
Model(&playerSnapshots).
|
||||
Apply(listPlayerSnapshotsParamsApplier{params: params}.apply).
|
||||
Relation("Player", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
return q.Column(bunmodel.PlayerMetaColumns...)
|
||||
}).
|
||||
Relation("Tribe", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
return q.Column(bunmodel.TribeMetaColumns...)
|
||||
}).
|
||||
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.ListPlayerSnapshotsWithRelationsResult{}, fmt.Errorf(
|
||||
"couldn't select player snapshots from the db: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
converted, err := playerSnapshots.ToDomainWithRelations()
|
||||
if err != nil {
|
||||
return domain.ListPlayerSnapshotsWithRelationsResult{}, err
|
||||
}
|
||||
|
||||
return domain.NewListPlayerSnapshotsWithRelationsResult(separateListResultAndNext(converted, params.Limit()))
|
||||
}
|
||||
|
||||
type listPlayerSnapshotsParamsApplier struct {
|
||||
params domain.ListPlayerSnapshotsParams
|
||||
}
|
||||
|
|
|
@ -85,7 +85,9 @@ func (repo *TribeSnapshotBunRepository) ListWithRelations(
|
|||
if err := repo.db.NewSelect().
|
||||
Model(&tribeSnapshots).
|
||||
Apply(listTribeSnapshotsParamsApplier{params: params}.apply).
|
||||
Relation("Tribe").
|
||||
Relation("Tribe", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
return q.Column(bunmodel.TribeMetaColumns...)
|
||||
}).
|
||||
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.ListTribeSnapshotsWithRelationsResult{}, fmt.Errorf(
|
||||
"couldn't select tribe snapshots from the db: %w",
|
||||
|
|
|
@ -116,7 +116,7 @@ func testPlayerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repo
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("List", func(t *testing.T) {
|
||||
t.Run("List & ListWithRelations", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
repos := newRepos(t)
|
||||
|
@ -443,6 +443,16 @@ func testPlayerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repo
|
|||
res, err := repos.playerSnapshot.List(ctx, params)
|
||||
assertError(t, err)
|
||||
tt.assertResult(t, params, res)
|
||||
|
||||
resWithRelations, err := repos.playerSnapshot.ListWithRelations(ctx, params)
|
||||
assertError(t, err)
|
||||
require.Len(t, resWithRelations.PlayerSnapshots(), len(res.PlayerSnapshots()))
|
||||
for i, ps := range resWithRelations.PlayerSnapshots() {
|
||||
assert.Equal(t, res.PlayerSnapshots()[i], ps.PlayerSnapshot())
|
||||
assert.Equal(t, ps.PlayerSnapshot().PlayerID(), ps.Player().ID())
|
||||
assert.Equal(t, ps.PlayerSnapshot().TribeID(), ps.Tribe().V.ID())
|
||||
assert.Equal(t, ps.PlayerSnapshot().TribeID() != 0, ps.Tribe().Valid)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -75,6 +75,10 @@ type tribeSnapshotRepository interface {
|
|||
type playerSnapshotRepository interface {
|
||||
Create(ctx context.Context, params ...domain.CreatePlayerSnapshotParams) error
|
||||
List(ctx context.Context, params domain.ListPlayerSnapshotsParams) (domain.ListPlayerSnapshotsResult, error)
|
||||
ListWithRelations(
|
||||
ctx context.Context,
|
||||
params domain.ListPlayerSnapshotsParams,
|
||||
) (domain.ListPlayerSnapshotsWithRelationsResult, error)
|
||||
}
|
||||
|
||||
type repositories struct {
|
||||
|
|
|
@ -58,7 +58,7 @@ func (e Ennoblement) ToDomainWithRelations() (domain.EnnoblementWithRelations, e
|
|||
return domain.EnnoblementWithRelations{}, err
|
||||
}
|
||||
|
||||
// in some cases there is no corresponding village in the db (for example, for old ennoblements)
|
||||
// in some cases there is no corresponding village in the db (old ennoblements)
|
||||
var village domain.VillageMeta
|
||||
if e.Village.ID > 0 {
|
||||
village, err = e.Village.ToMeta()
|
||||
|
@ -67,7 +67,7 @@ func (e Ennoblement) ToDomainWithRelations() (domain.EnnoblementWithRelations, e
|
|||
}
|
||||
}
|
||||
|
||||
// in some cases there is no corresponding player in the db (for example, for old ennoblements)
|
||||
// in some cases there is no corresponding player in the db (old ennoblements)
|
||||
var newOwner domain.PlayerMeta
|
||||
if e.NewOwner.ID > 0 {
|
||||
newOwner, err = e.NewOwner.ToMeta()
|
||||
|
|
|
@ -86,7 +86,6 @@ func (p Player) ToDomainWithRelations() (domain.PlayerWithRelations, error) {
|
|||
}
|
||||
|
||||
var tribe domain.NullTribeMeta
|
||||
|
||||
if p.Tribe.ID > 0 {
|
||||
tribe.Valid = true
|
||||
tribe.V, err = p.Tribe.ToMeta()
|
||||
|
|
|
@ -13,12 +13,13 @@ type PlayerSnapshot struct {
|
|||
|
||||
ID int `bun:"id,pk,autoincrement,identity"`
|
||||
PlayerID int `bun:"player_id,nullzero"`
|
||||
TribeID int `bun:"tribe_id,nullzero"`
|
||||
ServerKey string `bun:"server_key,nullzero"`
|
||||
Tribe Tribe `bun:"tribe,rel:belongs-to,join:tribe_id=id,join:server_key=server_key"`
|
||||
Player Player `bun:"player,rel:belongs-to,join:player_id=id,join:server_key=server_key"`
|
||||
NumVillages int `bun:"num_villages"`
|
||||
Points int `bun:"points"`
|
||||
Rank int `bun:"rank"`
|
||||
TribeID int `bun:"tribe_id,nullzero"`
|
||||
Tribe Tribe `bun:"tribe,rel:belongs-to,join:tribe_id=id,join:server_key=server_key"`
|
||||
ServerKey string `bun:"server_key,nullzero"`
|
||||
Date time.Time `bun:"date,nullzero"`
|
||||
CreatedAt time.Time `bun:"created_at,nullzero"`
|
||||
|
||||
|
@ -58,8 +59,35 @@ func (ps PlayerSnapshot) ToDomain() (domain.PlayerSnapshot, error) {
|
|||
return converted, nil
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshot) ToDomainWithRelations() (domain.PlayerSnapshotWithRelations, error) {
|
||||
converted, err := ps.ToDomain()
|
||||
if err != nil {
|
||||
return domain.PlayerSnapshotWithRelations{}, err
|
||||
}
|
||||
|
||||
player, err := ps.Player.ToMeta()
|
||||
if err != nil {
|
||||
return domain.PlayerSnapshotWithRelations{}, err
|
||||
}
|
||||
|
||||
var tribe domain.NullTribeMeta
|
||||
if ps.Tribe.ID > 0 {
|
||||
tribe.Valid = true
|
||||
tribe.V, err = ps.Tribe.ToMeta()
|
||||
if err != nil {
|
||||
return domain.PlayerSnapshotWithRelations{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return converted.WithRelations(player, tribe), nil
|
||||
}
|
||||
|
||||
type PlayerSnapshots []PlayerSnapshot
|
||||
|
||||
func (pss PlayerSnapshots) ToDomain() (domain.PlayerSnapshots, error) {
|
||||
return sliceToDomain(pss)
|
||||
}
|
||||
|
||||
func (pss PlayerSnapshots) ToDomainWithRelations() (domain.PlayerSnapshotsWithRelations, error) {
|
||||
return sliceToDomainWithRelations(pss)
|
||||
}
|
||||
|
|
|
@ -59,17 +59,16 @@ func (v Village) ToDomainWithRelations() (domain.VillageWithRelations, error) {
|
|||
return domain.VillageWithRelations{}, err
|
||||
}
|
||||
|
||||
var tribe domain.NullPlayerMetaWithRelations
|
||||
|
||||
var player domain.NullPlayerMetaWithRelations
|
||||
if v.Player.ID > 0 {
|
||||
tribe.Valid = true
|
||||
tribe.V, err = v.Player.ToMetaWithRelations()
|
||||
player.Valid = true
|
||||
player.V, err = v.Player.ToMetaWithRelations()
|
||||
if err != nil {
|
||||
return domain.VillageWithRelations{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return converted.WithRelations(tribe), nil
|
||||
return converted.WithRelations(player), nil
|
||||
}
|
||||
|
||||
func (v Village) ToMeta() (domain.VillageMeta, error) {
|
||||
|
|
|
@ -88,3 +88,55 @@ func NewPlayerSnapshot(tb TestingTB, opts ...func(cfg *PlayerSnapshotConfig)) do
|
|||
|
||||
return ps
|
||||
}
|
||||
|
||||
type PlayerSnapshotWithRelationsConfig struct {
|
||||
PlayerSnapshotOptions []func(cfg *PlayerSnapshotConfig)
|
||||
PlayerOptions []func(cfg *PlayerConfig)
|
||||
TribeOptions []func(cfg *TribeConfig)
|
||||
}
|
||||
|
||||
func NewPlayerSnapshotWithRelations(
|
||||
tb TestingTB,
|
||||
opts ...func(cfg *PlayerSnapshotWithRelationsConfig),
|
||||
) domain.PlayerSnapshotWithRelations {
|
||||
tb.Helper()
|
||||
|
||||
cfg := &PlayerSnapshotWithRelationsConfig{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(cfg)
|
||||
}
|
||||
|
||||
ps := NewPlayerSnapshot(tb, cfg.PlayerSnapshotOptions...)
|
||||
|
||||
if ps.PlayerID() > 0 {
|
||||
cfg.PlayerOptions = append([]func(cfg *PlayerConfig){
|
||||
func(cfg *PlayerConfig) {
|
||||
cfg.ID = ps.ID()
|
||||
},
|
||||
}, cfg.PlayerOptions...)
|
||||
}
|
||||
|
||||
if ps.TribeID() > 0 {
|
||||
cfg.TribeOptions = append([]func(cfg *TribeConfig){
|
||||
func(cfg *TribeConfig) {
|
||||
cfg.ID = ps.ID()
|
||||
},
|
||||
}, cfg.TribeOptions...)
|
||||
}
|
||||
|
||||
var player domain.PlayerMeta
|
||||
if len(cfg.PlayerOptions) > 0 {
|
||||
player = NewPlayer(tb, cfg.PlayerOptions...).Meta()
|
||||
}
|
||||
|
||||
var tribe domain.TribeMeta
|
||||
if len(cfg.TribeOptions) > 0 {
|
||||
tribe = NewTribe(tb, cfg.TribeOptions...).Meta()
|
||||
}
|
||||
|
||||
return ps.WithRelations(player, domain.NullTribeMeta{
|
||||
V: tribe,
|
||||
Valid: tribe.IsZero(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -115,6 +115,14 @@ func (ps PlayerSnapshot) CreatedAt() time.Time {
|
|||
return ps.createdAt
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshot) WithRelations(player PlayerMeta, tribe NullTribeMeta) PlayerSnapshotWithRelations {
|
||||
return PlayerSnapshotWithRelations{
|
||||
snapshot: ps,
|
||||
player: player,
|
||||
tribe: tribe,
|
||||
}
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshot) ToCursor() (PlayerSnapshotCursor, error) {
|
||||
return NewPlayerSnapshotCursor(ps.id, ps.serverKey, ps.date)
|
||||
}
|
||||
|
@ -125,6 +133,30 @@ func (ps PlayerSnapshot) IsZero() bool {
|
|||
|
||||
type PlayerSnapshots []PlayerSnapshot
|
||||
|
||||
type PlayerSnapshotWithRelations struct {
|
||||
snapshot PlayerSnapshot
|
||||
player PlayerMeta
|
||||
tribe NullTribeMeta
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshotWithRelations) PlayerSnapshot() PlayerSnapshot {
|
||||
return ps.snapshot
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshotWithRelations) Player() PlayerMeta {
|
||||
return ps.player
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshotWithRelations) Tribe() NullTribeMeta {
|
||||
return ps.tribe
|
||||
}
|
||||
|
||||
func (ps PlayerSnapshotWithRelations) IsZero() bool {
|
||||
return ps.snapshot.IsZero()
|
||||
}
|
||||
|
||||
type PlayerSnapshotsWithRelations []PlayerSnapshotWithRelations
|
||||
|
||||
type CreatePlayerSnapshotParams struct {
|
||||
playerID int
|
||||
serverKey string
|
||||
|
@ -545,3 +577,57 @@ func (res ListPlayerSnapshotsResult) Self() PlayerSnapshotCursor {
|
|||
func (res ListPlayerSnapshotsResult) Next() PlayerSnapshotCursor {
|
||||
return res.next
|
||||
}
|
||||
|
||||
type ListPlayerSnapshotsWithRelationsResult struct {
|
||||
snapshots PlayerSnapshotsWithRelations
|
||||
self PlayerSnapshotCursor
|
||||
next PlayerSnapshotCursor
|
||||
}
|
||||
|
||||
const listPlayerSnapshotsWithRelationsResultModelName = "ListPlayerSnapshotsWithRelationsResult"
|
||||
|
||||
func NewListPlayerSnapshotsWithRelationsResult(
|
||||
snapshots PlayerSnapshotsWithRelations,
|
||||
next PlayerSnapshotWithRelations,
|
||||
) (ListPlayerSnapshotsWithRelationsResult, error) {
|
||||
var err error
|
||||
res := ListPlayerSnapshotsWithRelationsResult{
|
||||
snapshots: snapshots,
|
||||
}
|
||||
|
||||
if len(snapshots) > 0 {
|
||||
res.self, err = snapshots[0].PlayerSnapshot().ToCursor()
|
||||
if err != nil {
|
||||
return ListPlayerSnapshotsWithRelationsResult{}, ValidationError{
|
||||
Model: listPlayerSnapshotsWithRelationsResultModelName,
|
||||
Field: "self",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !next.IsZero() {
|
||||
res.next, err = next.PlayerSnapshot().ToCursor()
|
||||
if err != nil {
|
||||
return ListPlayerSnapshotsWithRelationsResult{}, ValidationError{
|
||||
Model: listPlayerSnapshotsWithRelationsResultModelName,
|
||||
Field: "next",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (res ListPlayerSnapshotsWithRelationsResult) PlayerSnapshots() PlayerSnapshotsWithRelations {
|
||||
return res.snapshots
|
||||
}
|
||||
|
||||
func (res ListPlayerSnapshotsWithRelationsResult) Self() PlayerSnapshotCursor {
|
||||
return res.self
|
||||
}
|
||||
|
||||
func (res ListPlayerSnapshotsWithRelationsResult) Next() PlayerSnapshotCursor {
|
||||
return res.next
|
||||
}
|
||||
|
|
|
@ -720,3 +720,50 @@ func TestNewListPlayerSnapshotsResult(t *testing.T) {
|
|||
assert.True(t, res.Next().IsZero())
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewListPlayerSnapshotsWithRelationsResult(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
snapshots := domain.PlayerSnapshotsWithRelations{
|
||||
domaintest.NewPlayerSnapshotWithRelations(t),
|
||||
domaintest.NewPlayerSnapshotWithRelations(t),
|
||||
domaintest.NewPlayerSnapshotWithRelations(t),
|
||||
}
|
||||
next := domaintest.NewPlayerSnapshotWithRelations(t)
|
||||
|
||||
t.Run("OK: with next", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := domain.NewListPlayerSnapshotsWithRelationsResult(snapshots, next)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, snapshots, res.PlayerSnapshots())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().ID(), res.Self().ID())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().ServerKey(), res.Self().ServerKey())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().Date(), res.Self().Date())
|
||||
assert.Equal(t, next.PlayerSnapshot().ID(), res.Next().ID())
|
||||
assert.Equal(t, next.PlayerSnapshot().ServerKey(), res.Next().ServerKey())
|
||||
assert.Equal(t, next.PlayerSnapshot().Date(), res.Next().Date())
|
||||
})
|
||||
|
||||
t.Run("OK: without next", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := domain.NewListPlayerSnapshotsWithRelationsResult(snapshots, domain.PlayerSnapshotWithRelations{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, snapshots, res.PlayerSnapshots())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().ID(), res.Self().ID())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().ServerKey(), res.Self().ServerKey())
|
||||
assert.Equal(t, snapshots[0].PlayerSnapshot().Date(), res.Self().Date())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
})
|
||||
|
||||
t.Run("OK: 0 snapshots", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
res, err := domain.NewListPlayerSnapshotsWithRelationsResult(nil, domain.PlayerSnapshotWithRelations{})
|
||||
require.NoError(t, err)
|
||||
assert.Zero(t, res.PlayerSnapshots())
|
||||
assert.True(t, res.Self().IsZero())
|
||||
assert.True(t, res.Next().IsZero())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func (e ValidationError) Type() ErrorType {
|
|||
return ErrorTypeIncorrectInput
|
||||
}
|
||||
|
||||
// ignorecode
|
||||
// errorcode:ignore
|
||||
const errorCodeValidationFailed = "validation-failed"
|
||||
|
||||
func (e ValidationError) Code() string {
|
||||
|
@ -99,7 +99,7 @@ func (e SliceElementValidationError) Type() ErrorType {
|
|||
return ErrorTypeIncorrectInput
|
||||
}
|
||||
|
||||
// ignorecode
|
||||
// errorcode:ignore
|
||||
const errorCodeSliceElementValidationFailed = "slice-element-validation-failed"
|
||||
|
||||
func (e SliceElementValidationError) Code() string {
|
||||
|
|
Loading…
Reference in New Issue