feat: add a new model - EnnoblementWithRelations (#21)
ci/woodpecker/push/govulncheck Pipeline failed Details
ci/woodpecker/push/test Pipeline failed Details

Reviewed-on: twhelp/corev3#21
This commit is contained in:
Dawid Wysokiński 2024-03-10 09:37:44 +00:00
parent 5fa7c27d6d
commit d9a529167a
15 changed files with 566 additions and 38 deletions

View File

@ -72,6 +72,42 @@ func (repo *EnnoblementBunRepository) List(
return domain.NewListEnnoblementsResult(separateListResultAndNext(converted, params.Limit()))
}
func (repo *EnnoblementBunRepository) ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error) {
var ennoblements bunmodel.Ennoblements
if err := repo.db.NewSelect().
Model(&ennoblements).
Apply(listEnnoblementsParamsApplier{params: params}.apply).
Relation("Village", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Column(bunmodel.VillageMetaColumns...)
}).
Relation("NewOwner", 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("OldOwner", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Column(bunmodel.PlayerMetaColumns...)
}).
Relation("OldTribe", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Column(bunmodel.TribeMetaColumns...)
}).
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
return domain.ListEnnoblementsWithRelationsResult{}, fmt.Errorf("couldn't select ennoblements from the db: %w", err)
}
converted, err := ennoblements.ToDomainWithRelations()
if err != nil {
return domain.ListEnnoblementsWithRelationsResult{}, err
}
return domain.NewListEnnoblementsWithRelationsResult(separateListResultAndNext(converted, params.Limit()))
}
type listEnnoblementsParamsApplier struct {
params domain.ListEnnoblementsParams
}

View File

@ -118,7 +118,7 @@ func testEnnoblementRepository(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)
@ -448,6 +448,22 @@ func testEnnoblementRepository(t *testing.T, newRepos func(t *testing.T) reposit
res, err := repos.ennoblement.List(ctx, params)
tt.assertError(t, err)
tt.assertResult(t, params, res)
resWithRelations, err := repos.ennoblement.ListWithRelations(ctx, params)
tt.assertError(t, err)
require.Len(t, resWithRelations.Ennoblements(), len(res.Ennoblements()))
for i, e := range resWithRelations.Ennoblements() {
assert.Equal(t, res.Ennoblements()[i], e.Ennoblement())
assert.Equal(t, e.Ennoblement().VillageID(), e.Village().ID())
assert.Equal(t, e.Ennoblement().NewOwnerID(), e.NewOwner().V.ID())
assert.Equal(t, e.Ennoblement().NewOwnerID() != 0, e.NewOwner().Valid)
assert.Equal(t, e.Ennoblement().NewTribeID(), e.NewTribe().V.ID())
assert.Equal(t, e.Ennoblement().NewTribeID() != 0, e.NewTribe().Valid)
assert.Equal(t, e.Ennoblement().OldOwnerID(), e.OldOwner().V.ID())
assert.Equal(t, e.Ennoblement().OldOwnerID() != 0, e.OldOwner().Valid)
assert.Equal(t, e.Ennoblement().OldTribeID(), e.OldTribe().V.ID())
assert.Equal(t, e.Ennoblement().OldTribeID() != 0, e.OldTribe().Valid)
}
})
}
})

View File

@ -48,6 +48,10 @@ type villageRepository interface {
type ennoblementRepository interface {
Create(ctx context.Context, params ...domain.CreateEnnoblementParams) error
List(ctx context.Context, params domain.ListEnnoblementsParams) (domain.ListEnnoblementsResult, error)
ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error)
}
type tribeChangeRepository interface {

View File

@ -12,6 +12,10 @@ import (
type EnnoblementRepository interface {
Create(ctx context.Context, params ...domain.CreateEnnoblementParams) error
List(ctx context.Context, params domain.ListEnnoblementsParams) (domain.ListEnnoblementsResult, error)
ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error)
}
type EnnoblementService struct {
@ -125,3 +129,10 @@ func (svc *EnnoblementService) List(
) (domain.ListEnnoblementsResult, error) {
return svc.repo.List(ctx, params)
}
func (svc *EnnoblementService) ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error) {
return svc.repo.ListWithRelations(ctx, params)
}

View File

@ -51,6 +51,57 @@ func (e Ennoblement) ToDomain() (domain.Ennoblement, error) {
return converted, nil
}
//nolint:gocyclo
func (e Ennoblement) ToDomainWithRelations() (domain.EnnoblementWithRelations, error) {
converted, err := e.ToDomain()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
village, err := e.Village.ToMeta()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
var newOwner domain.NullPlayerMeta
if e.NewOwner.ID > 0 {
newOwner.Valid = true
newOwner.V, err = e.NewOwner.ToMeta()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
}
var newTribe domain.NullTribeMeta
if e.NewTribe.ID > 0 {
newTribe.Valid = true
newTribe.V, err = e.NewTribe.ToMeta()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
}
var oldOwner domain.NullPlayerMeta
if e.OldOwner.ID > 0 {
oldOwner.Valid = true
oldOwner.V, err = e.OldOwner.ToMeta()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
}
var oldTribe domain.NullTribeMeta
if e.OldTribe.ID > 0 {
oldTribe.Valid = true
oldTribe.V, err = e.OldTribe.ToMeta()
if err != nil {
return domain.EnnoblementWithRelations{}, err
}
}
return converted.WithRelations(village, newOwner, newTribe, oldOwner, oldTribe), nil
}
type Ennoblements []Ennoblement
func (es Ennoblements) ToDomain() (domain.Ennoblements, error) {
@ -67,3 +118,18 @@ func (es Ennoblements) ToDomain() (domain.Ennoblements, error) {
return res, nil
}
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
}

View File

@ -106,7 +106,7 @@ func (p Player) ToMeta() (domain.PlayerMeta, error) {
)
if err != nil {
return domain.PlayerMeta{}, fmt.Errorf(
"couldn't construct domain.TribeMeta (id=%d,serverKey=%s): %w",
"couldn't construct domain.PlayerMeta (id=%d,serverKey=%s): %w",
p.ID,
p.ServerKey,
err,

View File

@ -8,6 +8,8 @@ import (
"github.com/uptrace/bun"
)
var VillageMetaColumns = []string{"id", "name", "profile_url", "x", "y", "continent"}
type Village struct {
bun.BaseModel `bun:"table:villages,alias:village"`
@ -70,6 +72,26 @@ func (v Village) ToDomainWithRelations() (domain.VillageWithRelations, error) {
return converted.WithRelations(tribe), nil
}
func (v Village) ToMeta() (domain.VillageMeta, error) {
converted, err := domain.UnmarshalVillageMetaFromDatabase(
v.ID,
v.Name,
v.X,
v.Y,
v.Continent,
v.ProfileURL,
)
if err != nil {
return domain.VillageMeta{}, fmt.Errorf(
"couldn't construct domain.VillageMeta (id=%d,serverKey=%s): %w",
v.ID,
v.ServerKey,
err,
)
}
return converted, nil
}
type Villages []Village
func (vs Villages) ToDomain() (domain.Villages, error) {

View File

@ -71,3 +71,113 @@ func NewEnnoblement(tb TestingTB, opts ...func(cfg *EnnoblementConfig)) domain.E
return e
}
type EnnoblementWithRelationsConfig struct {
EnnoblementOptions []func(cfg *EnnoblementConfig)
VillageOptions []func(cfg *VillageConfig)
NewOwnerOptions []func(cfg *PlayerConfig)
NewTribeOptions []func(cfg *TribeConfig)
OldOwnerOptions []func(cfg *PlayerConfig)
OldTribeOptions []func(cfg *TribeConfig)
}
//nolint:gocyclo
func NewEnnoblementWithRelations(
tb TestingTB,
opts ...func(cfg *EnnoblementWithRelationsConfig),
) domain.EnnoblementWithRelations {
tb.Helper()
cfg := &EnnoblementWithRelationsConfig{}
for _, opt := range opts {
opt(cfg)
}
e := NewEnnoblement(tb, cfg.EnnoblementOptions...)
if e.VillageID() > 0 {
cfg.VillageOptions = append([]func(cfg *VillageConfig){
func(cfg *VillageConfig) {
cfg.ID = e.VillageID()
},
}, cfg.VillageOptions...)
}
if e.NewOwnerID() > 0 {
cfg.NewOwnerOptions = append([]func(cfg *PlayerConfig){
func(cfg *PlayerConfig) {
cfg.ID = e.NewOwnerID()
},
}, cfg.NewOwnerOptions...)
}
if e.NewTribeID() > 0 {
cfg.NewTribeOptions = append([]func(cfg *TribeConfig){
func(cfg *TribeConfig) {
cfg.ID = e.NewTribeID()
},
}, cfg.NewTribeOptions...)
}
if e.OldOwnerID() > 0 {
cfg.OldOwnerOptions = append([]func(cfg *PlayerConfig){
func(cfg *PlayerConfig) {
cfg.ID = e.OldOwnerID()
},
}, cfg.OldOwnerOptions...)
}
if e.OldTribeID() > 0 {
cfg.OldTribeOptions = append([]func(cfg *TribeConfig){
func(cfg *TribeConfig) {
cfg.ID = e.OldTribeID()
},
}, cfg.OldTribeOptions...)
}
var village domain.VillageMeta
if len(cfg.VillageOptions) > 0 {
village = NewVillage(tb, cfg.VillageOptions...).Meta()
}
var newOwner domain.PlayerMeta
if len(cfg.NewOwnerOptions) > 0 {
newOwner = NewPlayer(tb, cfg.NewOwnerOptions...).Meta()
}
var newTribe domain.TribeMeta
if len(cfg.NewTribeOptions) > 0 {
newTribe = NewTribe(tb, cfg.NewTribeOptions...).Meta()
}
var oldOwner domain.PlayerMeta
if len(cfg.OldOwnerOptions) > 0 {
oldOwner = NewPlayer(tb, cfg.OldOwnerOptions...).Meta()
}
var oldTribe domain.TribeMeta
if len(cfg.OldTribeOptions) > 0 {
newTribe = NewTribe(tb, cfg.OldTribeOptions...).Meta()
}
return e.WithRelations(
village,
domain.NullPlayerMeta{
V: newOwner,
Valid: !newOwner.IsZero(),
},
domain.NullTribeMeta{
V: newTribe,
Valid: !newTribe.IsZero(),
},
domain.NullPlayerMeta{
V: oldOwner,
Valid: !oldOwner.IsZero(),
},
domain.NullTribeMeta{
V: oldTribe,
Valid: !oldTribe.IsZero(),
},
)
}

View File

@ -123,6 +123,7 @@ func NewPlayer(tb TestingTB, opts ...func(cfg *PlayerConfig)) domain.Player {
type PlayerWithRelationsConfig struct {
PlayerOptions []func(cfg *PlayerConfig)
TribeOptions []func(cfg *TribeConfig)
}
func NewPlayerWithRelations(tb TestingTB, opts ...func(cfg *PlayerWithRelationsConfig)) domain.PlayerWithRelations {
@ -136,15 +137,21 @@ func NewPlayerWithRelations(tb TestingTB, opts ...func(cfg *PlayerWithRelationsC
p := NewPlayer(tb, cfg.PlayerOptions...)
var tribeMeta domain.TribeMeta
if p.TribeID() > 0 {
tribeMeta = NewTribeMeta(tb, func(cfg *TribeMetaConfig) {
cfg.ID = p.TribeID()
})
cfg.TribeOptions = append([]func(cfg *TribeConfig){
func(cfg *TribeConfig) {
cfg.ID = p.ID()
},
}, cfg.TribeOptions...)
}
var tribe domain.TribeMeta
if len(cfg.TribeOptions) > 0 {
tribe = NewTribe(tb, cfg.TribeOptions...).Meta()
}
return p.WithRelations(domain.NullTribeMeta{
V: tribeMeta,
Valid: !tribeMeta.IsZero(),
V: tribe,
Valid: !tribe.IsZero(),
})
}

View File

@ -120,26 +120,3 @@ func NewTribe(tb TestingTB, opts ...func(cfg *TribeConfig)) domain.Tribe {
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

@ -72,7 +72,8 @@ func NewVillage(tb TestingTB, opts ...func(cfg *VillageConfig)) domain.Village {
}
type VillageWithRelationsConfig struct {
PlayerOptions []func(cfg *PlayerWithRelationsConfig)
VillageOptions []func(cfg *VillageConfig)
PlayerOptions []func(cfg *PlayerWithRelationsConfig)
}
func NewVillageWithRelations(tb TestingTB, opts ...func(cfg *VillageWithRelationsConfig)) domain.VillageWithRelations {
@ -84,15 +85,25 @@ func NewVillageWithRelations(tb TestingTB, opts ...func(cfg *VillageWithRelation
opt(cfg)
}
v := NewVillage(tb)
v := NewVillage(tb, cfg.VillageOptions...)
var playerMeta domain.PlayerMetaWithRelations
if v.PlayerID() > 0 {
playerMeta = NewPlayerWithRelations(tb, cfg.PlayerOptions...).Meta()
cfg.PlayerOptions = append([]func(cfg *PlayerWithRelationsConfig){
func(cfg *PlayerWithRelationsConfig) {
cfg.PlayerOptions = append(cfg.PlayerOptions, func(cfg *PlayerConfig) {
cfg.ID = v.PlayerID()
})
},
}, cfg.PlayerOptions...)
}
var player domain.PlayerMetaWithRelations
if len(cfg.PlayerOptions) > 0 {
player = NewPlayerWithRelations(tb, cfg.PlayerOptions...).Meta()
}
return v.WithRelations(domain.NullPlayerMetaWithRelations{
V: playerMeta,
Valid: !playerMeta.IsZero(),
V: player,
Valid: !player.IsZero(),
})
}

View File

@ -101,6 +101,23 @@ func (e Ennoblement) CreatedAt() time.Time {
return e.createdAt
}
func (e Ennoblement) WithRelations(
village VillageMeta,
newOwner NullPlayerMeta,
newTribe NullTribeMeta,
oldOwner NullPlayerMeta,
oldTribe NullTribeMeta,
) EnnoblementWithRelations {
return EnnoblementWithRelations{
ennoblement: e,
village: village,
newOwner: newOwner,
newTribe: newTribe,
oldOwner: oldOwner,
oldTribe: oldTribe,
}
}
func (e Ennoblement) ToCursor() (EnnoblementCursor, error) {
return NewEnnoblementCursor(e.id, e.serverKey, e.createdAt)
}
@ -123,6 +140,45 @@ func (e Ennoblement) IsZero() bool {
type Ennoblements []Ennoblement
type EnnoblementWithRelations struct {
ennoblement Ennoblement
village VillageMeta
newOwner NullPlayerMeta
newTribe NullTribeMeta
oldOwner NullPlayerMeta
oldTribe NullTribeMeta
}
func (e EnnoblementWithRelations) Ennoblement() Ennoblement {
return e.ennoblement
}
func (e EnnoblementWithRelations) Village() VillageMeta {
return e.village
}
func (e EnnoblementWithRelations) NewOwner() NullPlayerMeta {
return e.newOwner
}
func (e EnnoblementWithRelations) NewTribe() NullTribeMeta {
return e.newTribe
}
func (e EnnoblementWithRelations) OldOwner() NullPlayerMeta {
return e.oldOwner
}
func (e EnnoblementWithRelations) OldTribe() NullTribeMeta {
return e.oldTribe
}
func (e EnnoblementWithRelations) IsZero() bool {
return e.ennoblement.IsZero()
}
type EnnoblementsWithRelations []EnnoblementWithRelations
type CreateEnnoblementParams struct {
base BaseEnnoblement
serverKey string
@ -455,3 +511,57 @@ func (res ListEnnoblementsResult) Self() EnnoblementCursor {
func (res ListEnnoblementsResult) Next() EnnoblementCursor {
return res.next
}
type ListEnnoblementsWithRelationsResult struct {
ennoblements EnnoblementsWithRelations
self EnnoblementCursor
next EnnoblementCursor
}
const listEnnoblementsWithRelationsResultModelName = "ListEnnoblementsWithRelationsResult"
func NewListEnnoblementsWithRelationsResult(
ennoblements EnnoblementsWithRelations,
next EnnoblementWithRelations,
) (ListEnnoblementsWithRelationsResult, error) {
var err error
res := ListEnnoblementsWithRelationsResult{
ennoblements: ennoblements,
}
if len(ennoblements) > 0 {
res.self, err = ennoblements[0].Ennoblement().ToCursor()
if err != nil {
return ListEnnoblementsWithRelationsResult{}, ValidationError{
Model: listEnnoblementsWithRelationsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.Ennoblement().ToCursor()
if err != nil {
return ListEnnoblementsWithRelationsResult{}, ValidationError{
Model: listEnnoblementsWithRelationsResultModelName,
Field: "next",
Err: err,
}
}
}
return res, nil
}
func (res ListEnnoblementsWithRelationsResult) Ennoblements() EnnoblementsWithRelations {
return res.ennoblements
}
func (res ListEnnoblementsWithRelationsResult) Self() EnnoblementCursor {
return res.self
}
func (res ListEnnoblementsWithRelationsResult) Next() EnnoblementCursor {
return res.next
}

View File

@ -490,8 +490,10 @@ func TestNewListEnnoblementsResult(t *testing.T) {
assert.Equal(t, ennoblements, res.Ennoblements())
assert.Equal(t, ennoblements[0].ID(), res.Self().ID())
assert.Equal(t, ennoblements[0].ServerKey(), res.Self().ServerKey())
assert.Equal(t, ennoblements[0].CreatedAt(), res.Self().CreatedAt())
assert.Equal(t, next.ID(), res.Next().ID())
assert.Equal(t, next.ServerKey(), res.Next().ServerKey())
assert.Equal(t, next.CreatedAt(), res.Next().CreatedAt())
})
t.Run("OK: without next", func(t *testing.T) {
@ -502,6 +504,7 @@ func TestNewListEnnoblementsResult(t *testing.T) {
assert.Equal(t, ennoblements, res.Ennoblements())
assert.Equal(t, ennoblements[0].ID(), res.Self().ID())
assert.Equal(t, ennoblements[0].ServerKey(), res.Self().ServerKey())
assert.Equal(t, ennoblements[0].CreatedAt(), res.Self().CreatedAt())
assert.True(t, res.Next().IsZero())
})
@ -515,3 +518,50 @@ func TestNewListEnnoblementsResult(t *testing.T) {
assert.True(t, res.Next().IsZero())
})
}
func TestNewListEnnoblementsWithRelationsResult(t *testing.T) {
t.Parallel()
ennoblements := domain.EnnoblementsWithRelations{
domaintest.NewEnnoblementWithRelations(t),
domaintest.NewEnnoblementWithRelations(t),
domaintest.NewEnnoblementWithRelations(t),
}
next := domaintest.NewEnnoblementWithRelations(t)
t.Run("OK: with next", func(t *testing.T) {
t.Parallel()
res, err := domain.NewListEnnoblementsWithRelationsResult(ennoblements, next)
require.NoError(t, err)
assert.Equal(t, ennoblements, res.Ennoblements())
assert.Equal(t, ennoblements[0].Ennoblement().ID(), res.Self().ID())
assert.Equal(t, ennoblements[0].Ennoblement().ServerKey(), res.Self().ServerKey())
assert.Equal(t, ennoblements[0].Ennoblement().CreatedAt(), res.Self().CreatedAt())
assert.Equal(t, next.Ennoblement().ID(), res.Next().ID())
assert.Equal(t, next.Ennoblement().ServerKey(), res.Next().ServerKey())
assert.Equal(t, next.Ennoblement().CreatedAt(), res.Next().CreatedAt())
})
t.Run("OK: without next", func(t *testing.T) {
t.Parallel()
res, err := domain.NewListEnnoblementsWithRelationsResult(ennoblements, domain.EnnoblementWithRelations{})
require.NoError(t, err)
assert.Equal(t, ennoblements, res.Ennoblements())
assert.Equal(t, ennoblements[0].Ennoblement().ID(), res.Self().ID())
assert.Equal(t, ennoblements[0].Ennoblement().ServerKey(), res.Self().ServerKey())
assert.Equal(t, ennoblements[0].Ennoblement().CreatedAt(), res.Self().CreatedAt())
assert.True(t, res.Next().IsZero())
})
t.Run("OK: 0 ennoblements", 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

@ -351,6 +351,12 @@ func (p PlayerMeta) WithRelations(tribe NullTribeMeta) PlayerMetaWithRelations {
}
}
type NullPlayerMeta NullValue[PlayerMeta]
func (p NullPlayerMeta) IsZero() bool {
return !p.Valid
}
type PlayerMetaWithRelations struct {
player PlayerMeta
tribe NullTribeMeta

View File

@ -102,7 +102,7 @@ func (v Village) Name() string {
}
func (v Village) FullName() string {
return fmt.Sprintf("%s (%d|%d) %s", v.name, v.x, v.y, v.continent)
return formatVillageFullName(v)
}
func (v Village) Points() int {
@ -155,6 +155,17 @@ func (v Village) ToCursor() (VillageCursor, error) {
return NewVillageCursor(v.id, v.serverKey)
}
func (v Village) Meta() VillageMeta {
return VillageMeta{
id: v.id,
name: v.name,
x: v.x,
y: v.y,
continent: v.continent,
profileURL: v.profileURL,
}
}
func (v Village) Base() BaseVillage {
return BaseVillage{
id: v.id,
@ -220,6 +231,88 @@ func (v VillageWithRelations) IsZero() bool {
type VillagesWithRelations []VillageWithRelations
type VillageMeta struct {
id int
name string
x int
y int
continent string
profileURL *url.URL
}
const villageMetaModelName = "VillageMeta"
// UnmarshalVillageMetaFromDatabase unmarshals VillageMeta from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalVillageMetaFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalVillageMetaFromDatabase(
id int,
name string,
x int,
y int,
continent string,
rawProfileURL string,
) (VillageMeta, error) {
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return VillageMeta{}, ValidationError{
Model: villageMetaModelName,
Field: "id",
Err: err,
}
}
profileURL, err := parseURL(rawProfileURL)
if err != nil {
return VillageMeta{}, ValidationError{
Model: villageMetaModelName,
Field: "profileURL",
Err: err,
}
}
return VillageMeta{
id: id,
name: name,
x: x,
y: y,
continent: continent,
profileURL: profileURL,
}, nil
}
func (v VillageMeta) ID() int {
return v.id
}
func (v VillageMeta) Name() string {
return v.name
}
func (v VillageMeta) FullName() string {
return formatVillageFullName(v)
}
func (v VillageMeta) X() int {
return v.x
}
func (v VillageMeta) Y() int {
return v.y
}
func (v VillageMeta) Continent() string {
return v.continent
}
func (v VillageMeta) ProfileURL() *url.URL {
return v.profileURL
}
func (v VillageMeta) IsZero() bool {
return v == VillageMeta{}
}
type CreateVillageParams struct {
base BaseVillage
serverKey string
@ -732,3 +825,12 @@ func (e VillageNotFoundError) Params() map[string]any {
"ServerKey": e.ServerKey,
}
}
func formatVillageFullName(v interface {
Name() string
X() int
Y() int
Continent() string
}) string {
return fmt.Sprintf("%s (%d|%d) %s", v.Name(), v.X(), v.Y(), v.Continent())
}