From 48f6a56a5ece7d3a465e36c5d9ea460e0de11d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Wysoki=C5=84ski?= Date: Tue, 12 Mar 2024 06:52:41 +0000 Subject: [PATCH] feat: add a new model - TribeChangeWithRelations (#26) Reviewed-on: https://gitea.dwysokinski.me/twhelp/corev3/pulls/26 --- cmd/twhelp/app.go | 3 +- cmd/twhelp/cmd_consumer.go | 11 +- cmd/twhelp/cmd_job.go | 7 +- cmd/twhelp/cmd_serve.go | 3 +- cmd/twhelp/utils.go | 18 --- .../adapter/repository_bun_tribe_change.go | 30 +++++ internal/adapter/repository_test.go | 4 + .../adapter/repository_tribe_change_test.go | 14 ++- internal/app/service_tribe_change.go | 19 ++++ internal/bun/bunmodel/ennoblement.go | 26 +---- internal/bun/bunmodel/player.go | 26 +---- internal/bun/bunmodel/player_snapshot.go | 13 +-- internal/bun/bunmodel/server.go | 13 +-- internal/bun/bunmodel/tribe.go | 13 +-- internal/bun/bunmodel/tribe_change.go | 50 +++++++-- internal/bun/bunmodel/tribe_snapshot.go | 13 +-- internal/bun/bunmodel/utils.go | 35 ++++++ internal/bun/bunmodel/version.go | 15 +-- internal/bun/bunmodel/village.go | 26 +---- internal/domain/domaintest/ennoblement.go | 2 +- internal/domain/domaintest/tribe_change.go | 74 +++++++++++++ internal/domain/ennoblement_test.go | 4 +- internal/domain/tribe_change.go | 104 +++++++++++++++++- internal/domain/tribe_change_test.go | 47 ++++++++ 24 files changed, 388 insertions(+), 182 deletions(-) create mode 100644 internal/bun/bunmodel/utils.go diff --git a/cmd/twhelp/app.go b/cmd/twhelp/app.go index 1b4eaf7..0c6efdb 100644 --- a/cmd/twhelp/app.go +++ b/cmd/twhelp/app.go @@ -3,6 +3,7 @@ package main import ( "fmt" "log/slog" + "slices" "github.com/urfave/cli/v2" ) @@ -45,7 +46,7 @@ func newApp(name, version string) *appWrapper { app.Version = version app.Commands = []*cli.Command{cmdDB, cmdJob, cmdConsumer, cmdServe} app.DefaultCommand = cmdServe.Name - app.Flags = concatSlices(appFlags, logFlags) + app.Flags = slices.Concat(appFlags, logFlags) app.Before = app.handleBefore return app } diff --git a/cmd/twhelp/cmd_consumer.go b/cmd/twhelp/cmd_consumer.go index 644266f..d0d0680 100644 --- a/cmd/twhelp/cmd_consumer.go +++ b/cmd/twhelp/cmd_consumer.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "slices" "sync" "time" @@ -28,7 +29,7 @@ var cmdConsumer = &cli.Command{ { Name: "server", Usage: "Run the worker responsible for consuming server-related messages", - Flags: concatSlices(dbFlags, rmqFlags, twSvcFlags), + Flags: slices.Concat(dbFlags, rmqFlags, twSvcFlags), Action: func(c *cli.Context) error { return runConsumer( c, @@ -78,7 +79,7 @@ var cmdConsumer = &cli.Command{ { Name: "tribe", Usage: "Run the worker responsible for consuming tribe-related messages", - Flags: concatSlices(dbFlags, rmqFlags, twSvcFlags), + Flags: slices.Concat(dbFlags, rmqFlags, twSvcFlags), Action: func(c *cli.Context) error { return runConsumer( c, @@ -135,7 +136,7 @@ var cmdConsumer = &cli.Command{ { Name: "player", Usage: "Run the worker responsible for consuming player-related messages", - Flags: concatSlices(dbFlags, rmqFlags, twSvcFlags), + Flags: slices.Concat(dbFlags, rmqFlags, twSvcFlags), Action: func(c *cli.Context) error { return runConsumer( c, @@ -198,7 +199,7 @@ var cmdConsumer = &cli.Command{ { Name: "village", Usage: "Run the worker responsible for consuming village-related messages", - Flags: concatSlices(dbFlags, rmqFlags, twSvcFlags), + Flags: slices.Concat(dbFlags, rmqFlags, twSvcFlags), Action: func(c *cli.Context) error { return runConsumer( c, @@ -240,7 +241,7 @@ var cmdConsumer = &cli.Command{ { Name: "ennoblement", Usage: "Run the worker responsible for consuming ennoblement-related messages", - Flags: concatSlices(dbFlags, rmqFlags, twSvcFlags), + Flags: slices.Concat(dbFlags, rmqFlags, twSvcFlags), Action: func(c *cli.Context) error { return runConsumer( c, diff --git a/cmd/twhelp/cmd_job.go b/cmd/twhelp/cmd_job.go index c2e07c5..a3bebce 100644 --- a/cmd/twhelp/cmd_job.go +++ b/cmd/twhelp/cmd_job.go @@ -3,6 +3,7 @@ package main import ( "fmt" "log/slog" + "slices" "gitea.dwysokinski.me/twhelp/corev3/internal/adapter" "gitea.dwysokinski.me/twhelp/corev3/internal/app" @@ -21,7 +22,7 @@ var ( { Name: "data", Usage: "Trigger data sync (servers, players, tribes, villages)", - Flags: concatSlices(dbFlags, rmqFlags), + Flags: slices.Concat(dbFlags, rmqFlags), Action: func(c *cli.Context) error { logger := loggerFromCtx(c.Context) watermillLogger := newWatermillLogger(logger) @@ -84,7 +85,7 @@ var ( { Name: "ennoblements", Usage: "Trigger ennoblement sync", - Flags: concatSlices(dbFlags, rmqFlags), + Flags: slices.Concat(dbFlags, rmqFlags), Action: func(c *cli.Context) error { logger := loggerFromCtx(c.Context) watermillLogger := newWatermillLogger(logger) @@ -153,7 +154,7 @@ var ( { Name: "snapshots", Usage: "Trigger snapshot creation (players/tribes)", - Flags: concatSlices(dbFlags, rmqFlags), + Flags: slices.Concat(dbFlags, rmqFlags), Action: func(c *cli.Context) error { logger := loggerFromCtx(c.Context) watermillLogger := newWatermillLogger(logger) diff --git a/cmd/twhelp/cmd_serve.go b/cmd/twhelp/cmd_serve.go index 0357ed1..0a135d7 100644 --- a/cmd/twhelp/cmd_serve.go +++ b/cmd/twhelp/cmd_serve.go @@ -7,6 +7,7 @@ import ( "log/slog" "net/http" "net/url" + "slices" "strings" "time" @@ -85,7 +86,7 @@ const ( var cmdServe = &cli.Command{ Name: "serve", Usage: "Run the HTTP server", - Flags: concatSlices(apiServerFlags, dbFlags), + Flags: slices.Concat(apiServerFlags, dbFlags), Action: func(c *cli.Context) error { logger := loggerFromCtx(c.Context) diff --git a/cmd/twhelp/utils.go b/cmd/twhelp/utils.go index 4e4c0d6..d5a934c 100644 --- a/cmd/twhelp/utils.go +++ b/cmd/twhelp/utils.go @@ -7,24 +7,6 @@ import ( "syscall" ) -func concatSlices[T any](slices ...[]T) []T { - var totalLen int - - for _, s := range slices { - totalLen += len(s) - } - - result := make([]T, totalLen) - - var i int - - for _, s := range slices { - i += copy(result[i:], s) - } - - return result -} - var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} // newShutdownSignalContext returns a copy of the parent context that is marked done diff --git a/internal/adapter/repository_bun_tribe_change.go b/internal/adapter/repository_bun_tribe_change.go index 5ae09d9..337ea25 100644 --- a/internal/adapter/repository_bun_tribe_change.go +++ b/internal/adapter/repository_bun_tribe_change.go @@ -70,6 +70,36 @@ func (repo *TribeChangeBunRepository) List( return domain.NewListTribeChangesResult(separateListResultAndNext(converted, params.Limit())) } +func (repo *TribeChangeBunRepository) ListWithRelations( + ctx context.Context, + params domain.ListTribeChangesParams, +) (domain.ListTribeChangesWithRelationsResult, error) { + var tribeChanges bunmodel.TribeChanges + + if err := repo.db.NewSelect(). + Model(&tribeChanges). + Apply(listTribeChangesParamsApplier{params: params}.apply). + Relation("Player", func(q *bun.SelectQuery) *bun.SelectQuery { + return q.Column(bunmodel.PlayerMetaColumns...) + }). + Relation("NewTribe", func(q *bun.SelectQuery) *bun.SelectQuery { + return q.Column(bunmodel.TribeMetaColumns...) + }). + Relation("OldTribe", func(q *bun.SelectQuery) *bun.SelectQuery { + return q.Column(bunmodel.TribeMetaColumns...) + }). + Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) { + return domain.ListTribeChangesWithRelationsResult{}, fmt.Errorf("couldn't select tribe changes from the db: %w", err) + } + + converted, err := tribeChanges.ToDomainWithRelations() + if err != nil { + return domain.ListTribeChangesWithRelationsResult{}, err + } + + return domain.NewListTribeChangesWithRelationsResult(separateListResultAndNext(converted, params.Limit())) +} + type listTribeChangesParamsApplier struct { params domain.ListTribeChangesParams } diff --git a/internal/adapter/repository_test.go b/internal/adapter/repository_test.go index 8681efb..6de9714 100644 --- a/internal/adapter/repository_test.go +++ b/internal/adapter/repository_test.go @@ -57,6 +57,10 @@ type ennoblementRepository interface { type tribeChangeRepository interface { Create(ctx context.Context, params ...domain.CreateTribeChangeParams) error List(ctx context.Context, params domain.ListTribeChangesParams) (domain.ListTribeChangesResult, error) + ListWithRelations( + ctx context.Context, + params domain.ListTribeChangesParams, + ) (domain.ListTribeChangesWithRelationsResult, error) } type tribeSnapshotRepository interface { diff --git a/internal/adapter/repository_tribe_change_test.go b/internal/adapter/repository_tribe_change_test.go index aa6fa27..8cc4b26 100644 --- a/internal/adapter/repository_tribe_change_test.go +++ b/internal/adapter/repository_tribe_change_test.go @@ -136,7 +136,7 @@ func testTribeChangeRepository(t *testing.T, newRepos func(t *testing.T) reposit }) }) - t.Run("List", func(t *testing.T) { + t.Run("List & ListWithRelations", func(t *testing.T) { t.Parallel() repos := newRepos(t) @@ -428,6 +428,18 @@ func testTribeChangeRepository(t *testing.T, newRepos func(t *testing.T) reposit res, err := repos.tribeChange.List(ctx, params) tt.assertError(t, err) tt.assertResult(t, params, res) + + resWithRelations, err := repos.tribeChange.ListWithRelations(ctx, params) + tt.assertError(t, err) + require.Len(t, resWithRelations.TribeChanges(), len(res.TribeChanges())) + for i, e := range resWithRelations.TribeChanges() { + assert.Equal(t, res.TribeChanges()[i], e.TribeChange()) + assert.Equal(t, e.TribeChange().PlayerID(), e.Player().ID()) + assert.Equal(t, e.TribeChange().NewTribeID(), e.NewTribe().V.ID()) + assert.Equal(t, e.TribeChange().NewTribeID() != 0, e.NewTribe().Valid) + assert.Equal(t, e.TribeChange().OldTribeID(), e.OldTribe().V.ID()) + assert.Equal(t, e.TribeChange().OldTribeID() != 0, e.OldTribe().Valid) + } }) } }) diff --git a/internal/app/service_tribe_change.go b/internal/app/service_tribe_change.go index 8e8445e..dc0f967 100644 --- a/internal/app/service_tribe_change.go +++ b/internal/app/service_tribe_change.go @@ -10,6 +10,11 @@ type TribeChangeRepository interface { // Create persists tribe changes in a store (e.g. Postgres). // Duplicates are ignored. Create(ctx context.Context, params ...domain.CreateTribeChangeParams) error + List(ctx context.Context, params domain.ListTribeChangesParams) (domain.ListTribeChangesResult, error) + ListWithRelations( + ctx context.Context, + params domain.ListTribeChangesParams, + ) (domain.ListTribeChangesWithRelationsResult, error) } type TribeChangeService struct { @@ -38,3 +43,17 @@ func (svc *TribeChangeService) Create(ctx context.Context, params ...domain.Crea return nil } + +func (svc *TribeChangeService) List( + ctx context.Context, + params domain.ListTribeChangesParams, +) (domain.ListTribeChangesResult, error) { + return svc.repo.List(ctx, params) +} + +func (svc *TribeChangeService) ListWithRelations( + ctx context.Context, + params domain.ListTribeChangesParams, +) (domain.ListTribeChangesWithRelationsResult, error) { + return svc.repo.ListWithRelations(ctx, params) +} diff --git a/internal/bun/bunmodel/ennoblement.go b/internal/bun/bunmodel/ennoblement.go index 4c86116..98d81f6 100644 --- a/internal/bun/bunmodel/ennoblement.go +++ b/internal/bun/bunmodel/ennoblement.go @@ -109,31 +109,9 @@ func (e Ennoblement) ToDomainWithRelations() (domain.EnnoblementWithRelations, e type Ennoblements []Ennoblement func (es Ennoblements) ToDomain() (domain.Ennoblements, error) { - res := make(domain.Ennoblements, 0, len(es)) - - for _, e := range es { - converted, err := e.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(es) } func (es Ennoblements) ToDomainWithRelations() (domain.EnnoblementsWithRelations, error) { - res := make(domain.EnnoblementsWithRelations, 0, len(es)) - - for _, e := range es { - converted, err := e.ToDomainWithRelations() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomainWithRelations(es) } diff --git a/internal/bun/bunmodel/player.go b/internal/bun/bunmodel/player.go index 44052fb..c46e2d5 100644 --- a/internal/bun/bunmodel/player.go +++ b/internal/bun/bunmodel/player.go @@ -137,31 +137,9 @@ func (p Player) ToMetaWithRelations() (domain.PlayerMetaWithRelations, error) { type Players []Player func (ps Players) ToDomain() (domain.Players, error) { - res := make(domain.Players, 0, len(ps)) - - for _, p := range ps { - converted, err := p.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(ps) } func (ps Players) ToDomainWithRelations() (domain.PlayersWithRelations, error) { - res := make(domain.PlayersWithRelations, 0, len(ps)) - - for _, p := range ps { - converted, err := p.ToDomainWithRelations() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomainWithRelations(ps) } diff --git a/internal/bun/bunmodel/player_snapshot.go b/internal/bun/bunmodel/player_snapshot.go index 1cfd20a..f0c8fd8 100644 --- a/internal/bun/bunmodel/player_snapshot.go +++ b/internal/bun/bunmodel/player_snapshot.go @@ -61,16 +61,5 @@ func (ps PlayerSnapshot) ToDomain() (domain.PlayerSnapshot, error) { type PlayerSnapshots []PlayerSnapshot func (pss PlayerSnapshots) ToDomain() (domain.PlayerSnapshots, error) { - res := make(domain.PlayerSnapshots, 0, len(pss)) - - for _, ps := range pss { - converted, err := ps.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(pss) } diff --git a/internal/bun/bunmodel/server.go b/internal/bun/bunmodel/server.go index b43afec..91bb93d 100644 --- a/internal/bun/bunmodel/server.go +++ b/internal/bun/bunmodel/server.go @@ -86,16 +86,5 @@ func (s Server) ToDomain() (domain.Server, error) { type Servers []Server func (ss Servers) ToDomain() (domain.Servers, error) { - res := make(domain.Servers, 0, len(ss)) - - for _, s := range ss { - converted, err := s.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(ss) } diff --git a/internal/bun/bunmodel/tribe.go b/internal/bun/bunmodel/tribe.go index 6d4e2bf..1b81d94 100644 --- a/internal/bun/bunmodel/tribe.go +++ b/internal/bun/bunmodel/tribe.go @@ -92,16 +92,5 @@ func (t Tribe) ToDomain() (domain.Tribe, error) { type Tribes []Tribe func (ts Tribes) ToDomain() (domain.Tribes, error) { - res := make(domain.Tribes, 0, len(ts)) - - for _, t := range ts { - converted, err := t.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(ts) } diff --git a/internal/bun/bunmodel/tribe_change.go b/internal/bun/bunmodel/tribe_change.go index 7e21a0f..49ff4d2 100644 --- a/internal/bun/bunmodel/tribe_change.go +++ b/internal/bun/bunmodel/tribe_change.go @@ -42,19 +42,45 @@ func (tc TribeChange) ToDomain() (domain.TribeChange, error) { return converted, nil } +//nolint:gocyclo +func (tc TribeChange) ToDomainWithRelations() (domain.TribeChangeWithRelations, error) { + converted, err := tc.ToDomain() + if err != nil { + return domain.TribeChangeWithRelations{}, err + } + + player, err := tc.Player.ToMeta() + if err != nil { + return domain.TribeChangeWithRelations{}, err + } + + var oldTribe domain.NullTribeMeta + if tc.OldTribe.ID > 0 { + oldTribe.Valid = true + oldTribe.V, err = tc.OldTribe.ToMeta() + if err != nil { + return domain.TribeChangeWithRelations{}, err + } + } + + var newTribe domain.NullTribeMeta + if tc.NewTribe.ID > 0 { + newTribe.Valid = true + newTribe.V, err = tc.NewTribe.ToMeta() + if err != nil { + return domain.TribeChangeWithRelations{}, err + } + } + + return converted.WithRelations(player, oldTribe, newTribe), nil +} + type TribeChanges []TribeChange func (tcs TribeChanges) ToDomain() (domain.TribeChanges, error) { - res := make(domain.TribeChanges, 0, len(tcs)) - - for _, tc := range tcs { - converted, err := tc.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(tcs) +} + +func (tcs TribeChanges) ToDomainWithRelations() (domain.TribeChangesWithRelations, error) { + return sliceToDomainWithRelations(tcs) } diff --git a/internal/bun/bunmodel/tribe_snapshot.go b/internal/bun/bunmodel/tribe_snapshot.go index 757db1c..a1b7979 100644 --- a/internal/bun/bunmodel/tribe_snapshot.go +++ b/internal/bun/bunmodel/tribe_snapshot.go @@ -64,16 +64,5 @@ func (ts TribeSnapshot) ToDomain() (domain.TribeSnapshot, error) { type TribeSnapshots []TribeSnapshot func (tss TribeSnapshots) ToDomain() (domain.TribeSnapshots, error) { - res := make(domain.TribeSnapshots, 0, len(tss)) - - for _, ts := range tss { - converted, err := ts.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(tss) } diff --git a/internal/bun/bunmodel/utils.go b/internal/bun/bunmodel/utils.go new file mode 100644 index 0000000..fb21bd3 --- /dev/null +++ b/internal/bun/bunmodel/utils.go @@ -0,0 +1,35 @@ +package bunmodel + +func sliceToDomain[T interface { + ToDomain() (V, error) +}, V any](s []T) ([]V, error) { + res := make([]V, 0, len(s)) + + for _, el := range s { + converted, err := el.ToDomain() + if err != nil { + return nil, err + } + + res = append(res, converted) + } + + return res, nil +} + +func sliceToDomainWithRelations[T interface { + ToDomainWithRelations() (V, error) +}, V any](s []T) ([]V, error) { + res := make([]V, 0, len(s)) + + for _, el := range s { + converted, err := el.ToDomainWithRelations() + if err != nil { + return nil, err + } + + res = append(res, converted) + } + + return res, nil +} diff --git a/internal/bun/bunmodel/version.go b/internal/bun/bunmodel/version.go index f6bdd47..32ca148 100644 --- a/internal/bun/bunmodel/version.go +++ b/internal/bun/bunmodel/version.go @@ -1,8 +1,6 @@ package bunmodel import ( - "fmt" - "gitea.dwysokinski.me/twhelp/corev3/internal/domain" "github.com/uptrace/bun" ) @@ -28,16 +26,5 @@ func (v Version) ToDomain() (domain.Version, error) { type Versions []Version func (vs Versions) ToDomain() (domain.Versions, error) { - res := make(domain.Versions, 0, len(vs)) - - for _, v := range vs { - converted, err := v.ToDomain() - if err != nil { - return nil, fmt.Errorf("couldn't construct domain.Version (version=%s): %w", v.Code, err) - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(vs) } diff --git a/internal/bun/bunmodel/village.go b/internal/bun/bunmodel/village.go index 3c46e94..a00bde2 100644 --- a/internal/bun/bunmodel/village.go +++ b/internal/bun/bunmodel/village.go @@ -95,31 +95,9 @@ func (v Village) ToMeta() (domain.VillageMeta, error) { type Villages []Village func (vs Villages) ToDomain() (domain.Villages, error) { - res := make(domain.Villages, 0, len(vs)) - - for _, v := range vs { - converted, err := v.ToDomain() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomain(vs) } func (vs Villages) ToDomainWithRelations() (domain.VillagesWithRelations, error) { - res := make(domain.VillagesWithRelations, 0, len(vs)) - - for _, v := range vs { - converted, err := v.ToDomainWithRelations() - if err != nil { - return nil, err - } - - res = append(res, converted) - } - - return res, nil + return sliceToDomainWithRelations(vs) } diff --git a/internal/domain/domaintest/ennoblement.go b/internal/domain/domaintest/ennoblement.go index a8a66da..94a1f8b 100644 --- a/internal/domain/domaintest/ennoblement.go +++ b/internal/domain/domaintest/ennoblement.go @@ -158,7 +158,7 @@ func NewEnnoblementWithRelations( var oldTribe domain.TribeMeta if len(cfg.OldTribeOptions) > 0 { - newTribe = NewTribe(tb, cfg.OldTribeOptions...).Meta() + oldTribe = NewTribe(tb, cfg.OldTribeOptions...).Meta() } return e.WithRelations( diff --git a/internal/domain/domaintest/tribe_change.go b/internal/domain/domaintest/tribe_change.go index e5b502f..e7b9df8 100644 --- a/internal/domain/domaintest/tribe_change.go +++ b/internal/domain/domaintest/tribe_change.go @@ -74,3 +74,77 @@ func NewTribeChange(tb TestingTB, opts ...func(cfg *TribeChangeConfig)) domain.T return tc } + +type TribeChangeWithRelationsConfig struct { + TribeChangeOptions []func(cfg *TribeChangeConfig) + PlayerOptions []func(cfg *PlayerConfig) + OldTribeOptions []func(cfg *TribeConfig) + NewTribeOptions []func(cfg *TribeConfig) +} + +//nolint:gocyclo +func NewTribeChangeWithRelations( + tb TestingTB, + opts ...func(cfg *TribeChangeWithRelationsConfig), +) domain.TribeChangeWithRelations { + tb.Helper() + + cfg := &TribeChangeWithRelationsConfig{} + + for _, opt := range opts { + opt(cfg) + } + + tc := NewTribeChange(tb, cfg.TribeChangeOptions...) + + if tc.PlayerID() > 0 { + cfg.PlayerOptions = append([]func(cfg *PlayerConfig){ + func(cfg *PlayerConfig) { + cfg.ID = tc.PlayerID() + }, + }, cfg.PlayerOptions...) + } + + if tc.OldTribeID() > 0 { + cfg.OldTribeOptions = append([]func(cfg *TribeConfig){ + func(cfg *TribeConfig) { + cfg.ID = tc.OldTribeID() + }, + }, cfg.OldTribeOptions...) + } + + if tc.NewTribeID() > 0 { + cfg.NewTribeOptions = append([]func(cfg *TribeConfig){ + func(cfg *TribeConfig) { + cfg.ID = tc.NewTribeID() + }, + }, cfg.NewTribeOptions...) + } + + var player domain.PlayerMeta + if len(cfg.PlayerOptions) > 0 { + player = NewPlayer(tb, cfg.PlayerOptions...).Meta() + } + + var oldTribe domain.TribeMeta + if len(cfg.OldTribeOptions) > 0 { + oldTribe = NewTribe(tb, cfg.OldTribeOptions...).Meta() + } + + var newTribe domain.TribeMeta + if len(cfg.NewTribeOptions) > 0 { + newTribe = NewTribe(tb, cfg.NewTribeOptions...).Meta() + } + + return tc.WithRelations( + player, + domain.NullTribeMeta{ + V: oldTribe, + Valid: !oldTribe.IsZero(), + }, + domain.NullTribeMeta{ + V: newTribe, + Valid: !newTribe.IsZero(), + }, + ) +} diff --git a/internal/domain/ennoblement_test.go b/internal/domain/ennoblement_test.go index 23c2c6f..bca0fb9 100644 --- a/internal/domain/ennoblement_test.go +++ b/internal/domain/ennoblement_test.go @@ -875,9 +875,9 @@ func TestNewListEnnoblementsWithRelationsResult(t *testing.T) { t.Run("OK: 0 ennoblements", func(t *testing.T) { t.Parallel() - res, err := domain.NewListPlayersWithRelationsResult(nil, domain.PlayerWithRelations{}) + res, err := domain.NewListEnnoblementsWithRelationsResult(nil, domain.EnnoblementWithRelations{}) require.NoError(t, err) - assert.Zero(t, res.Players()) + assert.Zero(t, res.Ennoblements()) assert.True(t, res.Self().IsZero()) assert.True(t, res.Next().IsZero()) }) diff --git a/internal/domain/tribe_change.go b/internal/domain/tribe_change.go index 60cc25c..56b5c50 100644 --- a/internal/domain/tribe_change.go +++ b/internal/domain/tribe_change.go @@ -81,6 +81,19 @@ func (tc TribeChange) CreatedAt() time.Time { return tc.createdAt } +func (tc TribeChange) WithRelations( + player PlayerMeta, + oldTribe NullTribeMeta, + newTribe NullTribeMeta, +) TribeChangeWithRelations { + return TribeChangeWithRelations{ + tribeChange: tc, + player: player, + oldTribe: oldTribe, + newTribe: newTribe, + } +} + func (tc TribeChange) ToCursor() (TribeChangeCursor, error) { return NewTribeChangeCursor(tc.id, tc.serverKey, tc.createdAt) } @@ -91,6 +104,35 @@ func (tc TribeChange) IsZero() bool { type TribeChanges []TribeChange +type TribeChangeWithRelations struct { + tribeChange TribeChange + player PlayerMeta + oldTribe NullTribeMeta + newTribe NullTribeMeta +} + +func (tc TribeChangeWithRelations) TribeChange() TribeChange { + return tc.tribeChange +} + +func (tc TribeChangeWithRelations) Player() PlayerMeta { + return tc.player +} + +func (tc TribeChangeWithRelations) OldTribe() NullTribeMeta { + return tc.oldTribe +} + +func (tc TribeChangeWithRelations) NewTribe() NullTribeMeta { + return tc.newTribe +} + +func (tc TribeChangeWithRelations) IsZero() bool { + return tc.tribeChange.IsZero() +} + +type TribeChangesWithRelations []TribeChangeWithRelations + type CreateTribeChangeParams struct { serverKey string playerID int @@ -460,14 +502,14 @@ type ListTribeChangesResult struct { const listTribeChangesResultModelName = "ListTribeChangesResult" -func NewListTribeChangesResult(ennoblements TribeChanges, next TribeChange) (ListTribeChangesResult, error) { +func NewListTribeChangesResult(tribeChanges TribeChanges, next TribeChange) (ListTribeChangesResult, error) { var err error res := ListTribeChangesResult{ - tribeChanges: ennoblements, + tribeChanges: tribeChanges, } - if len(ennoblements) > 0 { - res.self, err = ennoblements[0].ToCursor() + if len(tribeChanges) > 0 { + res.self, err = tribeChanges[0].ToCursor() if err != nil { return ListTribeChangesResult{}, ValidationError{ Model: listTribeChangesResultModelName, @@ -502,3 +544,57 @@ func (res ListTribeChangesResult) Self() TribeChangeCursor { func (res ListTribeChangesResult) Next() TribeChangeCursor { return res.next } + +type ListTribeChangesWithRelationsResult struct { + tribeChanges TribeChangesWithRelations + self TribeChangeCursor + next TribeChangeCursor +} + +const listTribeChangesWithRelationsResultModelName = "ListTribeChangesWithRelationsResult" + +func NewListTribeChangesWithRelationsResult( + tribeChanges TribeChangesWithRelations, + next TribeChangeWithRelations, +) (ListTribeChangesWithRelationsResult, error) { + var err error + res := ListTribeChangesWithRelationsResult{ + tribeChanges: tribeChanges, + } + + if len(tribeChanges) > 0 { + res.self, err = tribeChanges[0].TribeChange().ToCursor() + if err != nil { + return ListTribeChangesWithRelationsResult{}, ValidationError{ + Model: listTribeChangesWithRelationsResultModelName, + Field: "self", + Err: err, + } + } + } + + if !next.IsZero() { + res.next, err = next.TribeChange().ToCursor() + if err != nil { + return ListTribeChangesWithRelationsResult{}, ValidationError{ + Model: listTribeChangesWithRelationsResultModelName, + Field: "next", + Err: err, + } + } + } + + return res, nil +} + +func (res ListTribeChangesWithRelationsResult) TribeChanges() TribeChangesWithRelations { + return res.tribeChanges +} + +func (res ListTribeChangesWithRelationsResult) Self() TribeChangeCursor { + return res.self +} + +func (res ListTribeChangesWithRelationsResult) Next() TribeChangeCursor { + return res.next +} diff --git a/internal/domain/tribe_change_test.go b/internal/domain/tribe_change_test.go index 1643dde..78ac367 100644 --- a/internal/domain/tribe_change_test.go +++ b/internal/domain/tribe_change_test.go @@ -694,3 +694,50 @@ func TestNewListTribeChangesResult(t *testing.T) { assert.True(t, res.Next().IsZero()) }) } + +func TestNewListTribeChangesWithRelationsResult(t *testing.T) { + t.Parallel() + + tcs := domain.TribeChangesWithRelations{ + domaintest.NewTribeChangeWithRelations(t), + domaintest.NewTribeChangeWithRelations(t), + domaintest.NewTribeChangeWithRelations(t), + } + next := domaintest.NewTribeChangeWithRelations(t) + + t.Run("OK: with next", func(t *testing.T) { + t.Parallel() + + res, err := domain.NewListTribeChangesWithRelationsResult(tcs, next) + require.NoError(t, err) + assert.Equal(t, tcs, res.TribeChanges()) + assert.Equal(t, tcs[0].TribeChange().ID(), res.Self().ID()) + assert.Equal(t, tcs[0].TribeChange().ServerKey(), res.Self().ServerKey()) + assert.Equal(t, tcs[0].TribeChange().CreatedAt(), res.Self().CreatedAt()) + assert.Equal(t, next.TribeChange().ID(), res.Next().ID()) + assert.Equal(t, next.TribeChange().ServerKey(), res.Next().ServerKey()) + assert.Equal(t, next.TribeChange().CreatedAt(), res.Next().CreatedAt()) + }) + + t.Run("OK: without next", func(t *testing.T) { + t.Parallel() + + res, err := domain.NewListTribeChangesWithRelationsResult(tcs, domain.TribeChangeWithRelations{}) + require.NoError(t, err) + assert.Equal(t, tcs, res.TribeChanges()) + assert.Equal(t, tcs[0].TribeChange().ID(), res.Self().ID()) + assert.Equal(t, tcs[0].TribeChange().ServerKey(), res.Self().ServerKey()) + assert.Equal(t, tcs[0].TribeChange().CreatedAt(), res.Self().CreatedAt()) + assert.True(t, res.Next().IsZero()) + }) + + t.Run("OK: 0 tribe changes", func(t *testing.T) { + t.Parallel() + + res, err := domain.NewListTribeChangesWithRelationsResult(nil, domain.TribeChangeWithRelations{}) + require.NoError(t, err) + assert.Zero(t, res.TribeChanges()) + assert.True(t, res.Self().IsZero()) + assert.True(t, res.Next().IsZero()) + }) +}