feat: api - extend player schema (#8)
ci/woodpecker/push/govulncheck Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details

Reviewed-on: twhelp/corev3#8
This commit is contained in:
Dawid Wysokiński 2024-02-28 06:59:10 +00:00
parent bc3f61ec86
commit 0be010ab50
41 changed files with 538 additions and 144 deletions

View File

@ -941,6 +941,23 @@ components:
deletedAt: deletedAt:
type: string type: string
format: date-time format: date-time
TribeMeta:
type: object
required:
- id
- name
- tag
- profileUrl
properties:
id:
type: integer
name:
type: string
tag:
type: string
profileUrl:
type: string
format: uri
PlayerOpponentsDefeated: PlayerOpponentsDefeated:
allOf: allOf:
- $ref: "#/components/schemas/TribeOpponentsDefeated" - $ref: "#/components/schemas/TribeOpponentsDefeated"
@ -985,6 +1002,8 @@ components:
profileUrl: profileUrl:
type: string type: string
format: uri format: uri
tribe:
$ref: "#/components/schemas/TribeMeta"
lastActivityAt: lastActivityAt:
type: string type: string
format: date-time format: date-time
@ -1140,7 +1159,7 @@ components:
required: true required: true
schema: schema:
type: integer type: integer
minimum: 0 minimum: 1
responses: responses:
ListVersionsResponse: ListVersionsResponse:
description: "" description: ""

View File

@ -110,6 +110,30 @@ func (repo *PlayerBunRepository) List(
return domain.NewListPlayersResult(separateListResultAndNext(converted, params.Limit())) return domain.NewListPlayersResult(separateListResultAndNext(converted, params.Limit()))
} }
func (repo *PlayerBunRepository) ListWithRelations(
ctx context.Context,
params domain.ListPlayersParams,
) (domain.ListPlayersWithRelationsResult, error) {
var players bunmodel.Players
if err := repo.db.NewSelect().
Model(&players).
Apply(listPlayersParamsApplier{params: params}.apply).
Relation("Tribe", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Column(bunmodel.TribeMetaColumns...)
}).
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
return domain.ListPlayersWithRelationsResult{}, fmt.Errorf("couldn't select players from the db: %w", err)
}
converted, err := players.ToDomainWithRelations()
if err != nil {
return domain.ListPlayersWithRelationsResult{}, err
}
return domain.NewListPlayersWithRelationsResult(separateListResultAndNext(converted, params.Limit()))
}
func (repo *PlayerBunRepository) Delete(ctx context.Context, serverKey string, ids ...int) error { func (repo *PlayerBunRepository) Delete(ctx context.Context, serverKey string, ids ...int) error {
if len(ids) == 0 { if len(ids) == 0 {
return nil return nil
@ -145,7 +169,7 @@ func (a listPlayersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
} }
if deleted := a.params.Deleted(); deleted.Valid { if deleted := a.params.Deleted(); deleted.Valid {
if deleted.Value { if deleted.V {
q = q.Where("player.deleted_at IS NOT NULL") q = q.Where("player.deleted_at IS NOT NULL")
} else { } else {
q = q.Where("player.deleted_at IS NULL") q = q.Where("player.deleted_at IS NULL")

View File

@ -115,67 +115,67 @@ type updateServerParamsApplier struct {
//nolint:gocyclo //nolint:gocyclo
func (a updateServerParamsApplier) apply(q *bun.UpdateQuery) *bun.UpdateQuery { func (a updateServerParamsApplier) apply(q *bun.UpdateQuery) *bun.UpdateQuery {
if config := a.params.Config(); config.Valid { if config := a.params.Config(); config.Valid {
q = q.Set("config = ?", bunmodel.NewServerConfig(config.Value)) q = q.Set("config = ?", bunmodel.NewServerConfig(config.V))
} }
if unitInfo := a.params.UnitInfo(); unitInfo.Valid { if unitInfo := a.params.UnitInfo(); unitInfo.Valid {
q = q.Set("unit_info = ?", bunmodel.NewUnitInfo(unitInfo.Value)) q = q.Set("unit_info = ?", bunmodel.NewUnitInfo(unitInfo.V))
} }
if buildingInfo := a.params.BuildingInfo(); buildingInfo.Valid { if buildingInfo := a.params.BuildingInfo(); buildingInfo.Valid {
q = q.Set("building_info = ?", bunmodel.NewBuildingInfo(buildingInfo.Value)) q = q.Set("building_info = ?", bunmodel.NewBuildingInfo(buildingInfo.V))
} }
if numTribes := a.params.NumTribes(); numTribes.Valid { if numTribes := a.params.NumTribes(); numTribes.Valid {
q = q.Set("num_tribes = ?", numTribes.Value) q = q.Set("num_tribes = ?", numTribes.V)
} }
if tribeDataSyncedAt := a.params.TribeDataSyncedAt(); tribeDataSyncedAt.Valid { if tribeDataSyncedAt := a.params.TribeDataSyncedAt(); tribeDataSyncedAt.Valid {
// TODO: rename this column to tribe_data_synced_at // TODO: rename this column to tribe_data_synced_at
q = q.Set("tribe_data_updated_at = ?", tribeDataSyncedAt.Value) q = q.Set("tribe_data_updated_at = ?", tribeDataSyncedAt.V)
} }
if numPlayers := a.params.NumPlayers(); numPlayers.Valid { if numPlayers := a.params.NumPlayers(); numPlayers.Valid {
q = q.Set("num_players = ?", numPlayers.Value) q = q.Set("num_players = ?", numPlayers.V)
} }
if playerDataSyncedAt := a.params.PlayerDataSyncedAt(); playerDataSyncedAt.Valid { if playerDataSyncedAt := a.params.PlayerDataSyncedAt(); playerDataSyncedAt.Valid {
// TODO: rename this column to player_data_synced_at // TODO: rename this column to player_data_synced_at
q = q.Set("player_data_updated_at = ?", playerDataSyncedAt.Value) q = q.Set("player_data_updated_at = ?", playerDataSyncedAt.V)
} }
if numVillages := a.params.NumVillages(); numVillages.Valid { if numVillages := a.params.NumVillages(); numVillages.Valid {
q = q.Set("num_villages = ?", numVillages.Value) q = q.Set("num_villages = ?", numVillages.V)
} }
if numPlayerVillages := a.params.NumPlayerVillages(); numPlayerVillages.Valid { if numPlayerVillages := a.params.NumPlayerVillages(); numPlayerVillages.Valid {
q = q.Set("num_player_villages = ?", numPlayerVillages.Value) q = q.Set("num_player_villages = ?", numPlayerVillages.V)
} }
if numBarbarianVillages := a.params.NumBarbarianVillages(); numBarbarianVillages.Valid { if numBarbarianVillages := a.params.NumBarbarianVillages(); numBarbarianVillages.Valid {
q = q.Set("num_barbarian_villages = ?", numBarbarianVillages.Value) q = q.Set("num_barbarian_villages = ?", numBarbarianVillages.V)
} }
if numBonusVillages := a.params.NumBonusVillages(); numBonusVillages.Valid { if numBonusVillages := a.params.NumBonusVillages(); numBonusVillages.Valid {
q = q.Set("num_bonus_villages = ?", numBonusVillages.Value) q = q.Set("num_bonus_villages = ?", numBonusVillages.V)
} }
if villageDataSyncedAt := a.params.VillageDataSyncedAt(); villageDataSyncedAt.Valid { if villageDataSyncedAt := a.params.VillageDataSyncedAt(); villageDataSyncedAt.Valid {
// TODO: rename this column to village_data_synced_at // TODO: rename this column to village_data_synced_at
q = q.Set("village_data_updated_at = ?", villageDataSyncedAt.Value) q = q.Set("village_data_updated_at = ?", villageDataSyncedAt.V)
} }
if ennoblementDataSyncedAt := a.params.EnnoblementDataSyncedAt(); ennoblementDataSyncedAt.Valid { if ennoblementDataSyncedAt := a.params.EnnoblementDataSyncedAt(); ennoblementDataSyncedAt.Valid {
// TODO: rename this column to ennoblement_data_synced_at // TODO: rename this column to ennoblement_data_synced_at
q = q.Set("ennoblement_data_updated_at = ?", ennoblementDataSyncedAt.Value) q = q.Set("ennoblement_data_updated_at = ?", ennoblementDataSyncedAt.V)
} }
if tribeSnapshotsCreatedAt := a.params.TribeSnapshotsCreatedAt(); tribeSnapshotsCreatedAt.Valid { if tribeSnapshotsCreatedAt := a.params.TribeSnapshotsCreatedAt(); tribeSnapshotsCreatedAt.Valid {
q = q.Set("tribe_snapshots_created_at = ?", tribeSnapshotsCreatedAt.Value) q = q.Set("tribe_snapshots_created_at = ?", tribeSnapshotsCreatedAt.V)
} }
if playerSnapshotsCreatedAt := a.params.PlayerSnapshotsCreatedAt(); playerSnapshotsCreatedAt.Valid { if playerSnapshotsCreatedAt := a.params.PlayerSnapshotsCreatedAt(); playerSnapshotsCreatedAt.Valid {
q = q.Set("player_snapshots_created_at = ?", playerSnapshotsCreatedAt.Value) q = q.Set("player_snapshots_created_at = ?", playerSnapshotsCreatedAt.V)
} }
return q return q
@ -196,24 +196,24 @@ func (a listServersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
} }
if open := a.params.Open(); open.Valid { if open := a.params.Open(); open.Valid {
q = q.Where("server.open = ?", open.Value) q = q.Where("server.open = ?", open.V)
} }
if special := a.params.Special(); special.Valid { if special := a.params.Special(); special.Valid {
q = q.Where("server.special = ?", special.Value) q = q.Where("server.special = ?", special.V)
} }
if tribeSnapshotsCreatedAtLT := a.params.TribeSnapshotsCreatedAtLT(); tribeSnapshotsCreatedAtLT.Valid { if tribeSnapshotsCreatedAtLT := a.params.TribeSnapshotsCreatedAtLT(); tribeSnapshotsCreatedAtLT.Valid {
q = q.Where( q = q.Where(
"server.tribe_snapshots_created_at < ? OR server.tribe_snapshots_created_at is null", "server.tribe_snapshots_created_at < ? OR server.tribe_snapshots_created_at is null",
tribeSnapshotsCreatedAtLT.Value, tribeSnapshotsCreatedAtLT.V,
) )
} }
if playerSnapshotsCreatedAtLT := a.params.PlayerSnapshotsCreatedAtLT(); playerSnapshotsCreatedAtLT.Valid { if playerSnapshotsCreatedAtLT := a.params.PlayerSnapshotsCreatedAtLT(); playerSnapshotsCreatedAtLT.Valid {
q = q.Where( q = q.Where(
"server.player_snapshots_created_at < ? OR server.player_snapshots_created_at is null", "server.player_snapshots_created_at < ? OR server.player_snapshots_created_at is null",
playerSnapshotsCreatedAtLT.Value, playerSnapshotsCreatedAtLT.V,
) )
} }

View File

@ -117,10 +117,6 @@ func (repo *TribeBunRepository) List(
) (domain.ListTribesResult, error) { ) (domain.ListTribesResult, error) {
var tribes bunmodel.Tribes var tribes bunmodel.Tribes
fmt.Println(repo.db.NewSelect().
Model(&tribes).
Apply(listTribesParamsApplier{params: params}.apply).String())
if err := repo.db.NewSelect(). if err := repo.db.NewSelect().
Model(&tribes). Model(&tribes).
Apply(listTribesParamsApplier{params: params}.apply). Apply(listTribesParamsApplier{params: params}.apply).
@ -174,7 +170,7 @@ func (a listTribesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
} }
if deleted := a.params.Deleted(); deleted.Valid { if deleted := a.params.Deleted(); deleted.Valid {
if deleted.Value { if deleted.V {
q = q.Where("tribe.deleted_at IS NOT NULL") q = q.Where("tribe.deleted_at IS NOT NULL")
} else { } else {
q = q.Where("tribe.deleted_at IS NULL") q = q.Where("tribe.deleted_at IS NULL")

View File

@ -117,7 +117,7 @@ func (a listVillagesParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
} }
if idGT := a.params.IDGT(); idGT.Valid { if idGT := a.params.IDGT(); idGT.Valid {
q = q.Where("village.id > ?", idGT.Value) q = q.Where("village.id > ?", idGT.V)
} }
if serverKeys := a.params.ServerKeys(); len(serverKeys) > 0 { if serverKeys := a.params.ServerKeys(); len(serverKeys) > 0 {

View File

@ -85,7 +85,7 @@ func testPlayerSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repo
listPlayersParams := domain.NewListPlayersParams() listPlayersParams := domain.NewListPlayersParams()
require.NoError(t, listPlayersParams.SetDeleted(domain.NullBool{ require.NoError(t, listPlayersParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(t, listPlayersParams.SetLimit(domain.PlayerSnapshotListMaxLimit/2)) require.NoError(t, listPlayersParams.SetLimit(domain.PlayerSnapshotListMaxLimit/2))

View File

@ -100,7 +100,7 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
}) })
}) })
t.Run("List", func(t *testing.T) { t.Run("List & ListWithRelations", func(t *testing.T) {
t.Parallel() t.Parallel()
repos := newRepos(t) repos := newRepos(t)
@ -374,7 +374,7 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListPlayersParams() params := domain.NewListPlayersParams()
require.NoError(t, params.SetDeleted(domain.NullBool{ require.NoError(t, params.SetDeleted(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
})) }))
return params return params
@ -398,7 +398,7 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListPlayersParams() params := domain.NewListPlayersParams()
require.NoError(t, params.SetDeleted(domain.NullBool{ require.NoError(t, params.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
return params return params
@ -567,6 +567,15 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
res, err := repos.player.List(ctx, params) res, err := repos.player.List(ctx, params)
tt.assertError(t, err) tt.assertError(t, err)
tt.assertResult(t, params, res) tt.assertResult(t, params, res)
resWithRelations, err := repos.player.ListWithRelations(ctx, params)
tt.assertError(t, err)
require.Len(t, resWithRelations.Players(), len(res.Players()))
for i, p := range resWithRelations.Players() {
assert.Equal(t, res.Players()[i], p.Player())
assert.Equal(t, p.Player().TribeID(), p.Tribe().V.ID())
assert.Equal(t, p.Player().TribeID() != 0, p.Tribe().Valid)
}
}) })
} }
}) })
@ -577,7 +586,7 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
repos := newRepos(t) repos := newRepos(t)
listServersParams := domain.NewListServersParams() listServersParams := domain.NewListServersParams()
require.NoError(t, listServersParams.SetSpecial(domain.NullBool{Value: false, Valid: true})) require.NoError(t, listServersParams.SetSpecial(domain.NullBool{V: false, Valid: true}))
listServersRes, listServersErr := repos.server.List(ctx, listServersParams) listServersRes, listServersErr := repos.server.List(ctx, listServersParams)
require.NoError(t, listServersErr) require.NoError(t, listServersErr)
require.NotEmpty(t, listServersRes) require.NotEmpty(t, listServersRes)
@ -591,7 +600,7 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
} }
listPlayersParams := domain.NewListPlayersParams() listPlayersParams := domain.NewListPlayersParams()
require.NoError(t, listPlayersParams.SetDeleted(domain.NullBool{Value: false, Valid: true})) require.NoError(t, listPlayersParams.SetDeleted(domain.NullBool{V: false, Valid: true}))
require.NoError(t, listPlayersParams.SetServerKeys(serverKeys)) require.NoError(t, listPlayersParams.SetServerKeys(serverKeys))
res, err := repos.player.List(ctx, listPlayersParams) res, err := repos.player.List(ctx, listPlayersParams)

View File

@ -267,7 +267,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListServersParams() params := domain.NewListServersParams()
require.NoError(t, params.SetSpecial(domain.NullBool{ require.NoError(t, params.SetSpecial(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
})) }))
return params return params
@ -291,7 +291,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListServersParams() params := domain.NewListServersParams()
require.NoError(t, params.SetOpen(domain.NullBool{ require.NoError(t, params.SetOpen(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
return params return params
@ -315,7 +315,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListServersParams() params := domain.NewListServersParams()
require.NoError(t, params.SetPlayerSnapshotsCreatedAtLT(domain.NullTime{ require.NoError(t, params.SetPlayerSnapshotsCreatedAtLT(domain.NullTime{
Value: snapshotsCreatedAtLT, V: snapshotsCreatedAtLT,
Valid: true, Valid: true,
})) }))
return params return params
@ -339,7 +339,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
t.Helper() t.Helper()
params := domain.NewListServersParams() params := domain.NewListServersParams()
require.NoError(t, params.SetTribeSnapshotsCreatedAtLT(domain.NullTime{ require.NoError(t, params.SetTribeSnapshotsCreatedAtLT(domain.NullTime{
Value: snapshotsCreatedAtLT, V: snapshotsCreatedAtLT,
Valid: true, Valid: true,
})) }))
return params return params
@ -528,63 +528,63 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
require.NoError(t, updateParams.SetConfig(domain.NullServerConfig{ require.NoError(t, updateParams.SetConfig(domain.NullServerConfig{
Value: domaintest.NewServerConfig(t), V: domaintest.NewServerConfig(t),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetUnitInfo(domain.NullUnitInfo{ require.NoError(t, updateParams.SetUnitInfo(domain.NullUnitInfo{
Value: domaintest.NewUnitInfo(t), V: domaintest.NewUnitInfo(t),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetBuildingInfo(domain.NullBuildingInfo{ require.NoError(t, updateParams.SetBuildingInfo(domain.NullBuildingInfo{
Value: domaintest.NewBuildingInfo(t), V: domaintest.NewBuildingInfo(t),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumTribes(domain.NullInt{ require.NoError(t, updateParams.SetNumTribes(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetTribeDataSyncedAt(domain.NullTime{ require.NoError(t, updateParams.SetTribeDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumPlayers(domain.NullInt{ require.NoError(t, updateParams.SetNumPlayers(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetPlayerDataSyncedAt(domain.NullTime{ require.NoError(t, updateParams.SetPlayerDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumVillages(domain.NullInt{ require.NoError(t, updateParams.SetNumVillages(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumPlayerVillages(domain.NullInt{ require.NoError(t, updateParams.SetNumPlayerVillages(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumBonusVillages(domain.NullInt{ require.NoError(t, updateParams.SetNumBonusVillages(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetNumBarbarianVillages(domain.NullInt{ require.NoError(t, updateParams.SetNumBarbarianVillages(domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetVillageDataSyncedAt(domain.NullTime{ require.NoError(t, updateParams.SetVillageDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetEnnoblementDataSyncedAt(domain.NullTime{ require.NoError(t, updateParams.SetEnnoblementDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetTribeSnapshotsCreatedAt(domain.NullTime{ require.NoError(t, updateParams.SetTribeSnapshotsCreatedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
require.NoError(t, updateParams.SetPlayerSnapshotsCreatedAt(domain.NullTime{ require.NoError(t, updateParams.SetPlayerSnapshotsCreatedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
})) }))
@ -598,48 +598,48 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, serversAfterUpdate) require.NotEmpty(t, serversAfterUpdate)
serverAfterUpdate := serversAfterUpdate.Servers()[0] serverAfterUpdate := serversAfterUpdate.Servers()[0]
assert.Equal(t, updateParams.Config().Value, serverAfterUpdate.Config()) assert.Equal(t, updateParams.Config().V, serverAfterUpdate.Config())
assert.Equal(t, updateParams.UnitInfo().Value, serverAfterUpdate.UnitInfo()) assert.Equal(t, updateParams.UnitInfo().V, serverAfterUpdate.UnitInfo())
assert.Equal(t, updateParams.BuildingInfo().Value, serverAfterUpdate.BuildingInfo()) assert.Equal(t, updateParams.BuildingInfo().V, serverAfterUpdate.BuildingInfo())
assert.Equal(t, updateParams.NumTribes().Value, serverAfterUpdate.NumTribes()) assert.Equal(t, updateParams.NumTribes().V, serverAfterUpdate.NumTribes())
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.TribeDataSyncedAt().Value, updateParams.TribeDataSyncedAt().V,
serverAfterUpdate.TribeDataSyncedAt(), serverAfterUpdate.TribeDataSyncedAt(),
time.Minute, time.Minute,
) )
assert.Equal(t, updateParams.NumPlayers().Value, serverAfterUpdate.NumPlayers()) assert.Equal(t, updateParams.NumPlayers().V, serverAfterUpdate.NumPlayers())
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.PlayerDataSyncedAt().Value, updateParams.PlayerDataSyncedAt().V,
serverAfterUpdate.PlayerDataSyncedAt(), serverAfterUpdate.PlayerDataSyncedAt(),
time.Minute, time.Minute,
) )
assert.Equal(t, updateParams.NumVillages().Value, serverAfterUpdate.NumVillages()) assert.Equal(t, updateParams.NumVillages().V, serverAfterUpdate.NumVillages())
assert.Equal(t, updateParams.NumPlayerVillages().Value, serverAfterUpdate.NumPlayerVillages()) assert.Equal(t, updateParams.NumPlayerVillages().V, serverAfterUpdate.NumPlayerVillages())
assert.Equal(t, updateParams.NumBarbarianVillages().Value, serverAfterUpdate.NumBarbarianVillages()) assert.Equal(t, updateParams.NumBarbarianVillages().V, serverAfterUpdate.NumBarbarianVillages())
assert.Equal(t, updateParams.NumBonusVillages().Value, serverAfterUpdate.NumBonusVillages()) assert.Equal(t, updateParams.NumBonusVillages().V, serverAfterUpdate.NumBonusVillages())
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.VillageDataSyncedAt().Value, updateParams.VillageDataSyncedAt().V,
serverAfterUpdate.VillageDataSyncedAt(), serverAfterUpdate.VillageDataSyncedAt(),
time.Minute, time.Minute,
) )
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.EnnoblementDataSyncedAt().Value, updateParams.EnnoblementDataSyncedAt().V,
serverAfterUpdate.EnnoblementDataSyncedAt(), serverAfterUpdate.EnnoblementDataSyncedAt(),
time.Minute, time.Minute,
) )
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.TribeSnapshotsCreatedAt().Value, updateParams.TribeSnapshotsCreatedAt().V,
serverAfterUpdate.TribeSnapshotsCreatedAt(), serverAfterUpdate.TribeSnapshotsCreatedAt(),
time.Minute, time.Minute,
) )
assert.WithinDuration( assert.WithinDuration(
t, t,
updateParams.PlayerSnapshotsCreatedAt().Value, updateParams.PlayerSnapshotsCreatedAt().V,
serverAfterUpdate.PlayerSnapshotsCreatedAt(), serverAfterUpdate.PlayerSnapshotsCreatedAt(),
time.Minute, time.Minute,
) )
@ -650,7 +650,7 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
require.NoError(t, updateParams.SetConfig(domain.NullServerConfig{ require.NoError(t, updateParams.SetConfig(domain.NullServerConfig{
Value: domaintest.NewServerConfig(t), V: domaintest.NewServerConfig(t),
Valid: true, Valid: true,
})) }))

View File

@ -31,6 +31,7 @@ type tribeRepository interface {
type playerRepository interface { type playerRepository interface {
CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error
List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error) List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error)
ListWithRelations(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersWithRelationsResult, error)
Delete(ctx context.Context, serverKey string, ids ...int) error Delete(ctx context.Context, serverKey string, ids ...int) error
} }

View File

@ -87,7 +87,7 @@ func testTribeSnapshotRepository(t *testing.T, newRepos func(t *testing.T) repos
listTribesParams := domain.NewListTribesParams() listTribesParams := domain.NewListTribesParams()
require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{ require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))

View File

@ -106,11 +106,11 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
listServersParams := domain.NewListServersParams() listServersParams := domain.NewListServersParams()
require.NoError(t, listServersParams.SetOpen(domain.NullBool{ require.NoError(t, listServersParams.SetOpen(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
})) }))
require.NoError(t, listServersParams.SetSpecial(domain.NullBool{ require.NoError(t, listServersParams.SetSpecial(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
@ -143,7 +143,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
listTribesParams := domain.NewListTribesParams() listTribesParams := domain.NewListTribesParams()
require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{ require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(t, listTribesParams.SetServerKeys([]string{tt.serverKey})) require.NoError(t, listTribesParams.SetServerKeys([]string{tt.serverKey}))
@ -501,7 +501,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
t.Helper() t.Helper()
params := domain.NewListTribesParams() params := domain.NewListTribesParams()
require.NoError(t, params.SetDeleted(domain.NullBool{ require.NoError(t, params.SetDeleted(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
})) }))
return params return params
@ -525,7 +525,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
t.Helper() t.Helper()
params := domain.NewListTribesParams() params := domain.NewListTribesParams()
require.NoError(t, params.SetDeleted(domain.NullBool{ require.NoError(t, params.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
return params return params
@ -797,7 +797,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
repos := newRepos(t) repos := newRepos(t)
listServersParams := domain.NewListServersParams() listServersParams := domain.NewListServersParams()
require.NoError(t, listServersParams.SetSpecial(domain.NullBool{Value: false, Valid: true})) require.NoError(t, listServersParams.SetSpecial(domain.NullBool{V: false, Valid: true}))
listServersRes, listServersErr := repos.server.List(ctx, listServersParams) listServersRes, listServersErr := repos.server.List(ctx, listServersParams)
require.NoError(t, listServersErr) require.NoError(t, listServersErr)
require.NotEmpty(t, listServersRes) require.NotEmpty(t, listServersRes)
@ -811,7 +811,7 @@ func testTribeRepository(t *testing.T, newRepos func(t *testing.T) repositories)
} }
listTribesParams := domain.NewListTribesParams() listTribesParams := domain.NewListTribesParams()
require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{Value: false, Valid: true})) require.NoError(t, listTribesParams.SetDeleted(domain.NullBool{V: false, Valid: true}))
require.NoError(t, listTribesParams.SetServerKeys(serverKeys)) require.NoError(t, listTribesParams.SetServerKeys(serverKeys))
res, err := repos.tribe.List(ctx, listTribesParams) res, err := repos.tribe.List(ctx, listTribesParams)

View File

@ -196,7 +196,7 @@ func testVillageRepository(t *testing.T, newRepos func(t *testing.T) repositorie
t.Helper() t.Helper()
params := domain.NewListVillagesParams() params := domain.NewListVillagesParams()
require.NoError(t, params.SetIDGT(domain.NullInt{ require.NoError(t, params.SetIDGT(domain.NullInt{
Value: randVillage.ID(), V: randVillage.ID(),
Valid: true, Valid: true,
})) }))
return params return params
@ -205,7 +205,7 @@ func testVillageRepository(t *testing.T, newRepos func(t *testing.T) repositorie
t.Helper() t.Helper()
assert.NotEmpty(t, villages) assert.NotEmpty(t, villages)
for _, v := range villages { for _, v := range villages {
assert.Greater(t, v.ID(), params.IDGT().Value, v.ID()) assert.Greater(t, v.ID(), params.IDGT().V, v.ID())
} }
}, },
assertError: func(t *testing.T, err error) { assertError: func(t *testing.T, err error) {
@ -260,7 +260,7 @@ func testVillageRepository(t *testing.T, newRepos func(t *testing.T) repositorie
repos := newRepos(t) repos := newRepos(t)
listServersParams := domain.NewListServersParams() listServersParams := domain.NewListServersParams()
require.NoError(t, listServersParams.SetSpecial(domain.NullBool{Value: false, Valid: true})) require.NoError(t, listServersParams.SetSpecial(domain.NullBool{V: false, Valid: true}))
listServersRes, listServersErr := repos.server.List(ctx, listServersParams) listServersRes, listServersErr := repos.server.List(ctx, listServersParams)
require.NoError(t, listServersErr) require.NoError(t, listServersErr)
require.NotEmpty(t, listServersRes) require.NotEmpty(t, listServersRes)

View File

@ -10,6 +10,7 @@ import (
type PlayerRepository interface { type PlayerRepository interface {
CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error CreateOrUpdate(ctx context.Context, params ...domain.CreatePlayerParams) error
List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error) List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error)
ListWithRelations(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersWithRelationsResult, error)
// Delete marks players with the given serverKey and ids as deleted (sets deleted at to now). // Delete marks players with the given serverKey and ids as deleted (sets deleted at to now).
// In addition, Delete sets TribeID to null. // In addition, Delete sets TribeID to null.
// //
@ -134,7 +135,7 @@ func (svc *PlayerService) delete(ctx context.Context, serverKey string, players
return err return err
} }
if err := listParams.SetDeleted(domain.NullBool{ if err := listParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err
@ -182,3 +183,10 @@ func (svc *PlayerService) delete(ctx context.Context, serverKey string, players
func (svc *PlayerService) List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error) { func (svc *PlayerService) List(ctx context.Context, params domain.ListPlayersParams) (domain.ListPlayersResult, error) {
return svc.repo.List(ctx, params) return svc.repo.List(ctx, params)
} }
func (svc *PlayerService) ListWithRelations(
ctx context.Context,
params domain.ListPlayersParams,
) (domain.ListPlayersWithRelationsResult, error) {
return svc.repo.ListWithRelations(ctx, params)
}

View File

@ -40,7 +40,7 @@ func (svc *PlayerSnapshotService) Create(
return fmt.Errorf("%s: %w", serverKey, err) return fmt.Errorf("%s: %w", serverKey, err)
} }
if err := listPlayersParams.SetDeleted(domain.NullBool{ if err := listPlayersParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", serverKey, err) return fmt.Errorf("%s: %w", serverKey, err)

View File

@ -76,7 +76,7 @@ func (svc *ServerService) listAllSpecial(ctx context.Context, versionCode string
return nil, err return nil, err
} }
if err := params.SetSpecial(domain.NullBool{ if err := params.SetSpecial(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return nil, err return nil, err
@ -91,7 +91,7 @@ func (svc *ServerService) ListAllOpen(ctx context.Context, versionCode string) (
return nil, err return nil, err
} }
if err := params.SetOpen(domain.NullBool{ if err := params.SetOpen(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return nil, err return nil, err
@ -158,19 +158,19 @@ func (svc *ServerService) SyncConfigAndInfo(ctx context.Context, payload domain.
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err = updateParams.SetConfig(domain.NullServerConfig{ if err = updateParams.SetConfig(domain.NullServerConfig{
Value: cfg, V: cfg,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err = updateParams.SetBuildingInfo(domain.NullBuildingInfo{ if err = updateParams.SetBuildingInfo(domain.NullBuildingInfo{
Value: buildingInfo, V: buildingInfo,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err = updateParams.SetUnitInfo(domain.NullUnitInfo{ if err = updateParams.SetUnitInfo(domain.NullUnitInfo{
Value: unitInfo, V: unitInfo,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -184,13 +184,13 @@ func (svc *ServerService) UpdateNumTribes(ctx context.Context, payload domain.Tr
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetNumTribes(domain.NullInt{ if err := updateParams.SetNumTribes(domain.NullInt{
Value: payload.NumTribes(), V: payload.NumTribes(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetTribeDataSyncedAt(domain.NullTime{ if err := updateParams.SetTribeDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -204,13 +204,13 @@ func (svc *ServerService) UpdateNumPlayers(ctx context.Context, payload domain.P
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetNumPlayers(domain.NullInt{ if err := updateParams.SetNumPlayers(domain.NullInt{
Value: payload.NumPlayers(), V: payload.NumPlayers(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetPlayerDataSyncedAt(domain.NullTime{ if err := updateParams.SetPlayerDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -224,31 +224,31 @@ func (svc *ServerService) UpdateNumVillages(ctx context.Context, payload domain.
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetNumVillages(domain.NullInt{ if err := updateParams.SetNumVillages(domain.NullInt{
Value: payload.NumVillages(), V: payload.NumVillages(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetNumPlayerVillages(domain.NullInt{ if err := updateParams.SetNumPlayerVillages(domain.NullInt{
Value: payload.NumPlayerVillages(), V: payload.NumPlayerVillages(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetNumBarbarianVillages(domain.NullInt{ if err := updateParams.SetNumBarbarianVillages(domain.NullInt{
Value: payload.NumBarbarianVillages(), V: payload.NumBarbarianVillages(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetNumBonusVillages(domain.NullInt{ if err := updateParams.SetNumBonusVillages(domain.NullInt{
Value: payload.NumBonusVillages(), V: payload.NumBonusVillages(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
} }
if err := updateParams.SetVillageDataSyncedAt(domain.NullTime{ if err := updateParams.SetVillageDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -265,7 +265,7 @@ func (svc *ServerService) UpdateEnnoblementDataSyncedAt(
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetEnnoblementDataSyncedAt(domain.NullTime{ if err := updateParams.SetEnnoblementDataSyncedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -282,7 +282,7 @@ func (svc *ServerService) UpdateTribeSnapshotsCreatedAt(
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetTribeSnapshotsCreatedAt(domain.NullTime{ if err := updateParams.SetTribeSnapshotsCreatedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -299,7 +299,7 @@ func (svc *ServerService) UpdatePlayerSnapshotsCreatedAt(
var updateParams domain.UpdateServerParams var updateParams domain.UpdateServerParams
if err := updateParams.SetPlayerSnapshotsCreatedAt(domain.NullTime{ if err := updateParams.SetPlayerSnapshotsCreatedAt(domain.NullTime{
Value: time.Now(), V: time.Now(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", key, err) return fmt.Errorf("%s: %w", key, err)
@ -320,7 +320,7 @@ func (svc *ServerService) GetNormalByVersionCodeAndServerKey(
return domain.Server{}, err return domain.Server{}, err
} }
if err := params.SetSpecial(domain.NullBool{ if err := params.SetSpecial(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return domain.Server{}, err return domain.Server{}, err

View File

@ -70,13 +70,13 @@ func (svc *SnapshotService) publishTribe(
return err return err
} }
if err := params.SetOpen(domain.NullBool{ if err := params.SetOpen(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err
} }
if err := params.SetTribeSnapshotsCreatedAtLT(domain.NullTime{ if err := params.SetTribeSnapshotsCreatedAtLT(domain.NullTime{
Value: snapshotsCreatedAtLT, V: snapshotsCreatedAtLT,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err
@ -106,13 +106,13 @@ func (svc *SnapshotService) publishPlayer(
return err return err
} }
if err := params.SetOpen(domain.NullBool{ if err := params.SetOpen(domain.NullBool{
Value: true, V: true,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err
} }
if err := params.SetPlayerSnapshotsCreatedAtLT(domain.NullTime{ if err := params.SetPlayerSnapshotsCreatedAtLT(domain.NullTime{
Value: snapshotsCreatedAtLT, V: snapshotsCreatedAtLT,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err

View File

@ -117,7 +117,7 @@ func (svc *TribeService) delete(ctx context.Context, serverKey string, tribes do
return err return err
} }
if err := listParams.SetDeleted(domain.NullBool{ if err := listParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err

View File

@ -40,7 +40,7 @@ func (svc *TribeSnapshotService) Create(
return fmt.Errorf("%s: %w", serverKey, err) return fmt.Errorf("%s: %w", serverKey, err)
} }
if err := listTribesParams.SetDeleted(domain.NullBool{ if err := listTribesParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return fmt.Errorf("%s: %w", serverKey, err) return fmt.Errorf("%s: %w", serverKey, err)

View File

@ -106,7 +106,7 @@ func (svc *VillageService) delete(ctx context.Context, serverKey string, village
toDelete = append(toDelete, storedVillages.Delete(serverKey, villages)...) toDelete = append(toDelete, storedVillages.Delete(serverKey, villages)...)
if err = listParams.SetIDGT(domain.NullInt{ if err = listParams.SetIDGT(domain.NullInt{
Value: storedVillages[len(storedVillages)-1].ID(), V: storedVillages[len(storedVillages)-1].ID(),
Valid: true, Valid: true,
}); err != nil { }); err != nil {
return err return err

View File

@ -93,3 +93,29 @@ func (ps Players) ToDomain() (domain.Players, error) {
return res, nil return res, nil
} }
func (ps Players) ToDomainWithRelations() (domain.PlayersWithRelations, error) {
res := make(domain.PlayersWithRelations, 0, len(ps))
for _, p := range ps {
var err error
var tribe domain.NullTribeMeta
if p.Tribe.ID > 0 {
tribe.Valid = true
tribe.V, err = p.Tribe.ToMeta()
if err != nil {
return nil, err
}
}
converted, err := p.ToDomain()
if err != nil {
return nil, err
}
res = append(res, converted.WithRelations(tribe))
}
return res, nil
}

View File

@ -8,6 +8,8 @@ import (
"github.com/uptrace/bun" "github.com/uptrace/bun"
) )
var TribeMetaColumns = []string{"id", "name", "tag", "profile_url"}
type Tribe struct { type Tribe struct {
bun.BaseModel `bun:"table:tribes,alias:tribe"` bun.BaseModel `bun:"table:tribes,alias:tribe"`
@ -34,6 +36,24 @@ type Tribe struct {
OpponentsDefeated OpponentsDefeated
} }
func (t Tribe) ToMeta() (domain.TribeMeta, error) {
converted, err := domain.UnmarshalTribeMetaFromDatabase(
t.ID,
t.Name,
t.Tag,
t.ProfileURL,
)
if err != nil {
return domain.TribeMeta{}, fmt.Errorf(
"couldn't construct domain.TribeMeta (id=%d,serverKey=%s): %w",
t.ID,
t.ServerKey,
err,
)
}
return converted, nil
}
func (t Tribe) ToDomain() (domain.Tribe, error) { func (t Tribe) ToDomain() (domain.Tribe, error) {
od, err := t.OpponentsDefeated.ToDomain() od, err := t.OpponentsDefeated.ToDomain()
if err != nil { if err != nil {

View File

@ -117,3 +117,35 @@ func NewPlayer(tb TestingTB, opts ...func(cfg *PlayerConfig)) domain.Player {
return p return p
} }
type PlayerWithRelationsConfig struct {
TribeID int
}
func NewPlayerWithRelations(tb TestingTB, opts ...func(cfg *PlayerWithRelationsConfig)) domain.PlayerWithRelations {
tb.Helper()
cfg := &PlayerWithRelationsConfig{
TribeID: RandID(),
}
for _, opt := range opts {
opt(cfg)
}
p := NewPlayer(tb, func(playerCfg *PlayerConfig) {
playerCfg.TribeID = cfg.TribeID
})
var tribeMeta domain.TribeMeta
if p.TribeID() > 0 {
tribeMeta = NewTribeMeta(tb, func(cfg *TribeMetaConfig) {
cfg.ID = p.TribeID()
})
}
return p.WithRelations(domain.NullTribeMeta{
V: tribeMeta,
Valid: !tribeMeta.IsZero(),
})
}

View File

@ -120,3 +120,26 @@ func NewTribe(tb TestingTB, opts ...func(cfg *TribeConfig)) domain.Tribe {
return t return t
} }
type TribeMetaConfig struct {
ID int
Tag string
}
func NewTribeMeta(tb TestingTB, opts ...func(cfg *TribeMetaConfig)) domain.TribeMeta {
tb.Helper()
cfg := &TribeMetaConfig{
ID: RandID(),
Tag: RandTribeTag(),
}
for _, opt := range opts {
opt(cfg)
}
return NewTribe(tb, func(tribeCfg *TribeConfig) {
tribeCfg.ID = cfg.ID
tribeCfg.Tag = cfg.Tag
}).Meta()
}

View File

@ -3,8 +3,8 @@ package domain
import "time" import "time"
type NullValue[T any] struct { type NullValue[T any] struct {
Value T V T
Valid bool // Valid is true if Value is not NULL Valid bool // Valid is true if V is not NULL
} }
type NullInt = NullValue[int] type NullInt = NullValue[int]

View File

@ -181,6 +181,13 @@ func (p Player) DeletedAt() time.Time {
return p.deletedAt return p.deletedAt
} }
func (p Player) WithRelations(tribe NullTribeMeta) PlayerWithRelations {
return PlayerWithRelations{
player: p,
tribe: tribe,
}
}
func (p Player) Base() BasePlayer { func (p Player) Base() BasePlayer {
return BasePlayer{ return BasePlayer{
id: p.id, id: p.id,
@ -241,6 +248,23 @@ func (ps Players) Delete(serverKey string, active BasePlayers) ([]int, []CreateT
return toDelete, params, nil return toDelete, params, nil
} }
type PlayerWithRelations struct {
player Player
tribe NullTribeMeta
}
func (p PlayerWithRelations) Player() Player {
return p.player
}
func (p PlayerWithRelations) Tribe() NullTribeMeta {
return p.tribe
}
func (p PlayerWithRelations) IsZero() bool {
return p.player.IsZero() && p.tribe.IsZero()
}
type CreatePlayerParams struct { type CreatePlayerParams struct {
base BasePlayer base BasePlayer
serverKey string serverKey string
@ -253,6 +277,8 @@ type CreatePlayerParams struct {
lastActivityAt time.Time lastActivityAt time.Time
} }
type PlayersWithRelations []PlayerWithRelations
const createPlayerParamsModelName = "CreatePlayerParams" const createPlayerParamsModelName = "CreatePlayerParams"
// NewCreatePlayerParams constructs a slice of CreatePlayerParams based on the given parameters. // NewCreatePlayerParams constructs a slice of CreatePlayerParams based on the given parameters.
@ -630,7 +656,7 @@ func (params *ListPlayersParams) IDs() []int {
func (params *ListPlayersParams) SetIDs(ids []int) error { func (params *ListPlayersParams) SetIDs(ids []int) error {
for i, id := range ids { for i, id := range ids {
if err := validateIntInRange(id, 0, math.MaxInt); err != nil { if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return SliceElementValidationError{ return SliceElementValidationError{
Model: listPlayersParamsModelName, Model: listPlayersParamsModelName,
Field: "ids", Field: "ids",
@ -821,3 +847,78 @@ func (res ListPlayersResult) Self() PlayerCursor {
func (res ListPlayersResult) Next() PlayerCursor { func (res ListPlayersResult) Next() PlayerCursor {
return res.next return res.next
} }
type ListPlayersWithRelationsResult struct {
players PlayersWithRelations
self PlayerCursor
next PlayerCursor
}
const listPlayersWithRelationsResultModelName = "ListPlayersWithRelationsResult"
func NewListPlayersWithRelationsResult(
players PlayersWithRelations,
next PlayerWithRelations,
) (ListPlayersWithRelationsResult, error) {
var err error
res := ListPlayersWithRelationsResult{
players: players,
}
if len(players) > 0 {
player := players[0].Player()
od := player.OD()
res.self, err = NewPlayerCursor(
player.ID(),
player.ServerKey(),
od.ScoreAtt(),
od.ScoreDef(),
od.ScoreTotal(),
player.Points(),
player.DeletedAt(),
)
if err != nil {
return ListPlayersWithRelationsResult{}, ValidationError{
Model: listPlayersWithRelationsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
fmt.Println(next.IsZero())
player := next.Player()
od := player.OD()
res.next, err = NewPlayerCursor(
player.ID(),
player.ServerKey(),
od.ScoreAtt(),
od.ScoreDef(),
od.ScoreTotal(),
player.Points(),
player.DeletedAt(),
)
if err != nil {
return ListPlayersWithRelationsResult{}, ValidationError{
Model: listPlayersWithRelationsResultModelName,
Field: "next",
Err: err,
}
}
}
return res, nil
}
func (res ListPlayersWithRelationsResult) Players() PlayersWithRelations {
return res.players
}
func (res ListPlayersWithRelationsResult) Self() PlayerCursor {
return res.self
}
func (res ListPlayersWithRelationsResult) Next() PlayerCursor {
return res.next
}

View File

@ -437,13 +437,13 @@ func TestListPlayersParams_SetIDs(t *testing.T) {
}, },
}, },
{ {
name: "ERR: value < 0", name: "ERR: value < 1",
args: args{ args: args{
ids: []int{ ids: []int{
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
-1, 0,
domaintest.RandID(), domaintest.RandID(),
}, },
}, },
@ -452,8 +452,8 @@ func TestListPlayersParams_SetIDs(t *testing.T) {
Field: "ids", Field: "ids",
Index: 3, Index: 3,
Err: domain.MinGreaterEqualError{ Err: domain.MinGreaterEqualError{
Min: 0, Min: 1,
Current: -1, Current: 0,
}, },
}, },
}, },
@ -910,3 +910,47 @@ func TestNewListPlayersResult(t *testing.T) {
assert.True(t, res.Next().IsZero()) assert.True(t, res.Next().IsZero())
}) })
} }
func TestNewListPlayersWithRelationsResult(t *testing.T) {
t.Parallel()
players := domain.PlayersWithRelations{
domaintest.NewPlayerWithRelations(t),
domaintest.NewPlayerWithRelations(t),
domaintest.NewPlayerWithRelations(t),
}
next := domaintest.NewPlayerWithRelations(t)
t.Run("OK: with next", func(t *testing.T) {
t.Parallel()
res, err := domain.NewListPlayersWithRelationsResult(players, next)
require.NoError(t, err)
assert.Equal(t, players, res.Players())
assert.Equal(t, players[0].Player().ID(), res.Self().ID())
assert.Equal(t, players[0].Player().ServerKey(), res.Self().ServerKey())
assert.Equal(t, next.Player().ID(), res.Next().ID())
assert.Equal(t, next.Player().ServerKey(), res.Next().ServerKey())
})
t.Run("OK: without next", func(t *testing.T) {
t.Parallel()
res, err := domain.NewListPlayersWithRelationsResult(players, domain.PlayerWithRelations{})
require.NoError(t, err)
assert.Equal(t, players, res.Players())
assert.Equal(t, players[0].Player().ID(), res.Self().ID())
assert.Equal(t, players[0].Player().ServerKey(), res.Self().ServerKey())
assert.True(t, res.Next().IsZero())
})
t.Run("OK: 0 players", func(t *testing.T) {
t.Parallel()
res, err := domain.NewListPlayersWithRelationsResult(nil, domain.PlayerWithRelations{})
require.NoError(t, err)
assert.Zero(t, res.Players())
assert.True(t, res.Self().IsZero())
assert.True(t, res.Next().IsZero())
})
}

View File

@ -330,7 +330,7 @@ func (params *UpdateServerParams) NumTribes() NullInt {
func (params *UpdateServerParams) SetNumTribes(numTribes NullInt) error { func (params *UpdateServerParams) SetNumTribes(numTribes NullInt) error {
if numTribes.Valid { if numTribes.Valid {
if err := validateIntInRange(numTribes.Value, 0, math.MaxInt); err != nil { if err := validateIntInRange(numTribes.V, 0, math.MaxInt); err != nil {
return ValidationError{ return ValidationError{
Model: updateServerParamsModelName, Model: updateServerParamsModelName,
Field: "numTribes", Field: "numTribes",
@ -556,7 +556,7 @@ func NewListServersParams() ListServersParams {
sort: []ServerSort{ServerSortKeyASC}, sort: []ServerSort{ServerSortKeyASC},
limit: ServerListMaxLimit, limit: ServerListMaxLimit,
special: NullBool{ special: NullBool{
Value: false, V: false,
Valid: true, Valid: true,
}, },
} }

View File

@ -136,7 +136,7 @@ func TestUpdateServerParams_SetNumTribes(t *testing.T) {
name: "OK", name: "OK",
args: args{ args: args{
numTribes: domain.NullInt{ numTribes: domain.NullInt{
Value: gofakeit.IntRange(0, math.MaxInt), V: gofakeit.IntRange(0, math.MaxInt),
Valid: true, Valid: true,
}, },
}, },
@ -153,7 +153,7 @@ func TestUpdateServerParams_SetNumTribes(t *testing.T) {
name: "ERR: numTribes < 0", name: "ERR: numTribes < 0",
args: args{ args: args{
numTribes: domain.NullInt{ numTribes: domain.NullInt{
Value: -1, V: -1,
Valid: true, Valid: true,
}, },
}, },

View File

@ -216,6 +216,15 @@ func (t Tribe) Base() BaseTribe {
} }
} }
func (t Tribe) Meta() TribeMeta {
return TribeMeta{
id: t.id,
name: t.name,
tag: t.tag,
profileURL: t.profileURL,
}
}
func (t Tribe) IsZero() bool { func (t Tribe) IsZero() bool {
return t == Tribe{} return t == Tribe{}
} }
@ -247,6 +256,66 @@ func (ts Tribes) Delete(serverKey string, active BaseTribes) []int {
return toDelete return toDelete
} }
type TribeMeta struct {
id int
name string
tag string
profileURL *url.URL
}
const tribeMetaModelName = "TribeMeta"
// UnmarshalTribeMetaFromDatabase unmarshals TribeMeta from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalTribeMetaFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalTribeMetaFromDatabase(id int, name string, tag string, rawProfileURL string) (TribeMeta, error) {
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return TribeMeta{}, ValidationError{
Model: tribeMetaModelName,
Field: "id",
Err: err,
}
}
profileURL, err := parseURL(rawProfileURL)
if err != nil {
return TribeMeta{}, ValidationError{
Model: tribeMetaModelName,
Field: "profileURL",
Err: err,
}
}
return TribeMeta{id: id, name: name, tag: tag, profileURL: profileURL}, nil
}
func (t TribeMeta) ID() int {
return t.id
}
func (t TribeMeta) Name() string {
return t.name
}
func (t TribeMeta) Tag() string {
return t.tag
}
func (t TribeMeta) ProfileURL() *url.URL {
return t.profileURL
}
func (t TribeMeta) IsZero() bool {
return t == TribeMeta{}
}
type NullTribeMeta NullValue[TribeMeta]
func (t NullTribeMeta) IsZero() bool {
return !t.Valid
}
type CreateTribeParams struct { type CreateTribeParams struct {
base BaseTribe base BaseTribe
serverKey string serverKey string
@ -646,7 +715,7 @@ func (params *ListTribesParams) IDs() []int {
func (params *ListTribesParams) SetIDs(ids []int) error { func (params *ListTribesParams) SetIDs(ids []int) error {
for i, id := range ids { for i, id := range ids {
if err := validateIntInRange(id, 0, math.MaxInt); err != nil { if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return SliceElementValidationError{ return SliceElementValidationError{
Model: listTribesParamsModelName, Model: listTribesParamsModelName,
Field: "ids", Field: "ids",

View File

@ -399,13 +399,13 @@ func TestListTribesParams_SetIDs(t *testing.T) {
}, },
}, },
{ {
name: "ERR: value < 0", name: "ERR: value < 1",
args: args{ args: args{
ids: []int{ ids: []int{
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
-1, 0,
domaintest.RandID(), domaintest.RandID(),
}, },
}, },
@ -414,8 +414,8 @@ func TestListTribesParams_SetIDs(t *testing.T) {
Field: "ids", Field: "ids",
Index: 3, Index: 3,
Err: domain.MinGreaterEqualError{ Err: domain.MinGreaterEqualError{
Min: 0, Min: 1,
Current: -1, Current: 0,
}, },
}, },
}, },

View File

@ -254,7 +254,7 @@ func (params *ListVillagesParams) IDs() []int {
func (params *ListVillagesParams) SetIDs(ids []int) error { func (params *ListVillagesParams) SetIDs(ids []int) error {
for i, id := range ids { for i, id := range ids {
if err := validateIntInRange(id, 0, math.MaxInt); err != nil { if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return SliceElementValidationError{ return SliceElementValidationError{
Model: listVillagesParamsModelName, Model: listVillagesParamsModelName,
Field: "ids", Field: "ids",
@ -275,7 +275,7 @@ func (params *ListVillagesParams) IDGT() NullInt {
func (params *ListVillagesParams) SetIDGT(idGT NullInt) error { func (params *ListVillagesParams) SetIDGT(idGT NullInt) error {
if idGT.Valid { if idGT.Valid {
if err := validateIntInRange(idGT.Value, 0, math.MaxInt); err != nil { if err := validateIntInRange(idGT.V, 0, math.MaxInt); err != nil {
return ValidationError{ return ValidationError{
Model: listVillagesParamsModelName, Model: listVillagesParamsModelName,
Field: "idGT", Field: "idGT",

View File

@ -111,13 +111,13 @@ func TestListVillagesParams_SetIDs(t *testing.T) {
}, },
}, },
{ {
name: "ERR: value < 0", name: "ERR: value < 1",
args: args{ args: args{
ids: []int{ ids: []int{
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
domaintest.RandID(), domaintest.RandID(),
-1, 0,
domaintest.RandID(), domaintest.RandID(),
}, },
}, },
@ -126,8 +126,8 @@ func TestListVillagesParams_SetIDs(t *testing.T) {
Field: "ids", Field: "ids",
Index: 3, Index: 3,
Err: domain.MinGreaterEqualError{ Err: domain.MinGreaterEqualError{
Min: 0, Min: 1,
Current: -1, Current: 0,
}, },
}, },
}, },
@ -164,7 +164,7 @@ func TestListVillagesParams_SetIDGT(t *testing.T) {
name: "OK", name: "OK",
args: args{ args: args{
idGT: domain.NullInt{ idGT: domain.NullInt{
Value: domaintest.RandID(), V: domaintest.RandID(),
Valid: true, Valid: true,
}, },
}, },
@ -173,7 +173,7 @@ func TestListVillagesParams_SetIDGT(t *testing.T) {
name: "ERR: value < 0", name: "ERR: value < 0",
args: args{ args: args{
idGT: domain.NullInt{ idGT: domain.NullInt{
Value: -1, V: -1,
Valid: true, Valid: true,
}, },
}, },

View File

@ -207,7 +207,7 @@ func TestDataSync(t *testing.T) {
domain.ServerSortKeyASC, domain.ServerSortKeyASC,
})) }))
require.NoError(collect, listParams.SetSpecial(domain.NullBool{ require.NoError(collect, listParams.SetSpecial(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit)) require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit))
@ -431,7 +431,7 @@ func TestDataSync(t *testing.T) {
allVillages = append(allVillages, villages...) allVillages = append(allVillages, villages...)
require.NoError(collect, listParams.SetIDGT(domain.NullInt{ require.NoError(collect, listParams.SetIDGT(domain.NullInt{
Value: villages[len(villages)-1].ID(), V: villages[len(villages)-1].ID(),
Valid: true, Valid: true,
})) }))
} }

View File

@ -167,7 +167,7 @@ func TestEnnoblementSync(t *testing.T) {
domain.ServerSortKeyASC, domain.ServerSortKeyASC,
})) }))
require.NoError(collect, listParams.SetSpecial(domain.NullBool{ require.NoError(collect, listParams.SetSpecial(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit)) require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit))

View File

@ -151,7 +151,7 @@ func TestSnapshotCreation(t *testing.T) {
domain.ServerSortKeyASC, domain.ServerSortKeyASC,
})) }))
require.NoError(collect, listParams.SetSpecial(domain.NullBool{ require.NoError(collect, listParams.SetSpecial(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit)) require.NoError(collect, listParams.SetLimit(domain.ServerListMaxLimit))
@ -182,7 +182,7 @@ func TestSnapshotCreation(t *testing.T) {
domain.TribeSortIDASC, domain.TribeSortIDASC,
})) }))
require.NoError(collect, listTribesParams.SetDeleted(domain.NullBool{ require.NoError(collect, listTribesParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(collect, listTribesParams.SetLimit(domain.TribeListMaxLimit)) require.NoError(collect, listTribesParams.SetLimit(domain.TribeListMaxLimit))
@ -268,7 +268,7 @@ func TestSnapshotCreation(t *testing.T) {
domain.PlayerSortIDASC, domain.PlayerSortIDASC,
})) }))
require.NoError(collect, listPlayersParams.SetDeleted(domain.NullBool{ require.NoError(collect, listPlayersParams.SetDeleted(domain.NullBool{
Value: false, V: false,
Valid: true, Valid: true,
})) }))
require.NoError(collect, listPlayersParams.SetLimit(domain.PlayerListMaxLimit)) require.NoError(collect, listPlayersParams.SetLimit(domain.PlayerListMaxLimit))

View File

@ -37,7 +37,7 @@ func (h *apiHTTPHandler) ListPlayers(
if params.Deleted != nil { if params.Deleted != nil {
if err := domainParams.SetDeleted(domain.NullBool{ if err := domainParams.SetDeleted(domain.NullBool{
Value: *params.Deleted, V: *params.Deleted,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err) h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
@ -59,7 +59,7 @@ func (h *apiHTTPHandler) ListPlayers(
} }
} }
res, err := h.playerSvc.List(r.Context(), domainParams) res, err := h.playerSvc.ListWithRelations(r.Context(), domainParams)
if err != nil { if err != nil {
h.errorRenderer.render(w, r, err) h.errorRenderer.render(w, r, err)
return return

View File

@ -30,7 +30,7 @@ func (h *apiHTTPHandler) ListServers(
if params.Open != nil { if params.Open != nil {
if err := domainParams.SetOpen(domain.NullBool{ if err := domainParams.SetOpen(domain.NullBool{
Value: *params.Open, V: *params.Open,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListServersErrorPath).render(w, r, err) h.errorRenderer.withErrorPathFormatter(formatListServersErrorPath).render(w, r, err)

View File

@ -47,7 +47,7 @@ func (h *apiHTTPHandler) ListTribes(
if params.Deleted != nil { if params.Deleted != nil {
if err := domainParams.SetDeleted(domain.NullBool{ if err := domainParams.SetDeleted(domain.NullBool{
Value: *params.Deleted, V: *params.Deleted,
Valid: true, Valid: true,
}); err != nil { }); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListTribesErrorPath).render(w, r, err) h.errorRenderer.withErrorPathFormatter(formatListTribesErrorPath).render(w, r, err)

View File

@ -704,7 +704,7 @@ func TestGetTribe(t *testing.T) {
}, },
}, },
{ {
name: "ERR: id < 0", name: "ERR: id < 1",
reqModifier: func(t *testing.T, req *http.Request) { reqModifier: func(t *testing.T, req *http.Request) {
t.Helper() t.Helper()
req.URL.Path = fmt.Sprintf( req.URL.Path = fmt.Sprintf(
@ -726,7 +726,7 @@ func TestGetTribe(t *testing.T) {
id, err := strconv.Atoi(pathSegments[7]) id, err := strconv.Atoi(pathSegments[7])
require.NoError(t, err) require.NoError(t, err)
domainErr := domain.MinGreaterEqualError{ domainErr := domain.MinGreaterEqualError{
Min: 0, Min: 1,
Current: id, Current: id,
} }
assert.Equal(t, apimodel.ErrorResponse{ assert.Equal(t, apimodel.ErrorResponse{

View File

@ -17,7 +17,9 @@ func NewPlayerOpponentsDefeated(od domain.OpponentsDefeated) PlayerOpponentsDefe
} }
} }
func NewPlayer(p domain.Player) Player { func NewPlayer(withRelations domain.PlayerWithRelations) Player {
p := withRelations.Player()
converted := Player{ converted := Player{
BestRank: p.BestRank(), BestRank: p.BestRank(),
BestRankAt: p.BestRankAt(), BestRankAt: p.BestRankAt(),
@ -34,6 +36,7 @@ func NewPlayer(p domain.Player) Player {
Points: p.Points(), Points: p.Points(),
ProfileUrl: p.ProfileURL().String(), ProfileUrl: p.ProfileURL().String(),
Rank: p.Rank(), Rank: p.Rank(),
Tribe: NewNullTribeMeta(withRelations.Tribe()),
} }
if deletedAt := p.DeletedAt(); !deletedAt.IsZero() { if deletedAt := p.DeletedAt(); !deletedAt.IsZero() {
@ -43,7 +46,7 @@ func NewPlayer(p domain.Player) Player {
return converted return converted
} }
func NewListPlayersResponse(res domain.ListPlayersResult) ListPlayersResponse { func NewListPlayersResponse(res domain.ListPlayersWithRelationsResult) ListPlayersResponse {
players := res.Players() players := res.Players()
resp := ListPlayersResponse{ resp := ListPlayersResponse{

View File

@ -44,6 +44,25 @@ func NewTribe(t domain.Tribe) Tribe {
return converted return converted
} }
func NewTribeMeta(t domain.TribeMeta) TribeMeta {
return TribeMeta{
Id: t.ID(),
Name: t.Name(),
ProfileUrl: t.ProfileURL().String(),
Tag: t.Tag(),
}
}
func NewNullTribeMeta(t domain.NullTribeMeta) *TribeMeta {
if !t.Valid {
return nil
}
converted := NewTribeMeta(t.V)
return &converted
}
func NewListTribesResponse(res domain.ListTribesResult) ListTribesResponse { func NewListTribesResponse(res domain.ListTribesResult) ListTribesResponse {
tribes := res.Tribes() tribes := res.Tribes()