From 02e003ffd1b905b08d5f6f6cb16067be537efc06 Mon Sep 17 00:00:00 2001 From: Tyler J Cvetan Date: Fri, 11 Oct 2024 18:52:17 +0000 Subject: [PATCH] feat: add character type, refactor http translations, fetch additional data --- .../http/character/character_request.go | 9 ++ .../adapter/http/game/game_request.go | 16 ++++ .../adapter/http/game/location_request.go | 16 ++++ .../chronicle/adapter/http/game/server.go | 83 ++----------------- .../adapter/http/game/world_request.go | 23 +++++ .../persistence/postgres/query/world.go | 19 +++-- ...initial.sql => 20241011174940_initial.sql} | 1 + .../postgres/sqlc/migrations/atlas.sum | 4 +- .../persistence/postgres/sqlc/query.sql | 7 +- .../postgres/sqlc/repository/models.go | 1 + .../postgres/sqlc/repository/query.sql.go | 65 ++++++++------- .../persistence/postgres/sqlc/schema.sql | 1 + .../chronicle/core/application/application.go | 4 +- .../command/add_world_character.go | 2 +- .../command/update_world_character.go | 5 +- .../core/application/query/get_game.go | 26 +++++- .../core/application/query/list_game.go | 18 ++-- .../chronicle/core/domain/world_character.go | 6 +- internal/chronicle/core/port/world.go | 1 + internal/chronicle/port/persistence.go | 2 +- internal/chronicle/tools/http/game.http | 5 ++ 21 files changed, 183 insertions(+), 131 deletions(-) rename internal/chronicle/adapter/persistence/postgres/sqlc/migrations/{20241007183159_initial.sql => 20241011174940_initial.sql} (99%) diff --git a/internal/chronicle/adapter/http/character/character_request.go b/internal/chronicle/adapter/http/character/character_request.go index a3226f9..5c891a5 100644 --- a/internal/chronicle/adapter/http/character/character_request.go +++ b/internal/chronicle/adapter/http/character/character_request.go @@ -8,6 +8,15 @@ import ( "github.com/google/uuid" ) +func NewCharacterRequest(c domain.Character) CharacterRequest { + return CharacterRequest{ + ID: c.CharacterId.String(), + CharacterId: c.CharacterId.String(), + Name: c.Name, + Description: c.Description, + } +} + type CharacterRequest struct { ID string `jsonapi:"primary,characters"` CharacterId string `jsonapi:"attr,characterId"` diff --git a/internal/chronicle/adapter/http/game/game_request.go b/internal/chronicle/adapter/http/game/game_request.go index 2a4830e..1a27ed6 100644 --- a/internal/chronicle/adapter/http/game/game_request.go +++ b/internal/chronicle/adapter/http/game/game_request.go @@ -8,6 +8,22 @@ import ( "github.com/google/uuid" ) +func NewGameRequest(g domain.Game) GameRequest { + worlds := make([]*WorldRequest, len(g.Worlds)) + for x, world := range g.Worlds { + worldRquest := NewWorldRequest(world) + worlds[x] = &worldRquest + } + + return GameRequest{ + ID: g.GameId.String(), + GameId: g.GameId.String(), + Name: g.Name, + Type: g.Type, + Worlds: worlds, + } +} + type GameRequest struct { ID string `jsonapi:"primary,games"` GameId string `jsonapi:"attr,gameId"` diff --git a/internal/chronicle/adapter/http/game/location_request.go b/internal/chronicle/adapter/http/game/location_request.go index 036d15e..e6ee7cb 100644 --- a/internal/chronicle/adapter/http/game/location_request.go +++ b/internal/chronicle/adapter/http/game/location_request.go @@ -8,6 +8,22 @@ import ( "github.com/google/uuid" ) +func NewLocationRequest(l domain.Location) LocationRequest { + paths := make([]string, len(l.Path)) + for x, path := range l.Path { + paths[x] = path.String() + } + + return LocationRequest{ + ID: l.LocationId.String(), + LocationId: l.LocationId.String(), + WorldId: l.WorldId.String(), + Name: l.Name, + Type: l.Type, + Path: paths, + } +} + type LocationRequest struct { ID string `jsonapi:"primary,locations"` LocationId string `jsonapi:"attr,locationId"` diff --git a/internal/chronicle/adapter/http/game/server.go b/internal/chronicle/adapter/http/game/server.go index cec0c69..c56182b 100644 --- a/internal/chronicle/adapter/http/game/server.go +++ b/internal/chronicle/adapter/http/game/server.go @@ -3,7 +3,6 @@ package game import ( "net/http" - "github.com/SomethingSexy/chronicle/internal/chronicle/adapter/http/character" corePort "github.com/SomethingSexy/chronicle/internal/chronicle/core/port" "github.com/SomethingSexy/chronicle/internal/chronicle/port" "github.com/SomethingSexy/chronicle/internal/common" @@ -76,23 +75,8 @@ func (h GameHttpServer) ListGames(w http.ResponseWriter, r *http.Request) { responses := make([]*GameRequest, len(games)) for i, game := range games { - worlds := make([]*WorldRequest, len(game.Worlds)) - - for x, world := range game.Worlds { - worlds[x] = &WorldRequest{ - ID: world.WorldId.String(), - WorldId: world.WorldId.String(), - GameId: world.GameId.String(), - Name: world.Name, - } - } - responses[i] = &GameRequest{ - ID: game.GameId.String(), - GameId: game.GameId.String(), - Name: game.Name, - Type: game.Type, - Worlds: worlds, - } + gameRequest := NewGameRequest((game)) + responses[i] = &gameRequest } w.WriteHeader(http.StatusOK) @@ -115,16 +99,11 @@ func (h GameHttpServer) GetGame(w http.ResponseWriter, r *http.Request) { return } - response := &GameRequest{ - ID: game.GameId.String(), - GameId: game.GameId.String(), - Name: game.Name, - Type: game.Type, - } + gameRequest := NewGameRequest((game)) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", jsonapi.MediaType) - if err := jsonapi.MarshalPayload(w, response); err != nil { + if err := jsonapi.MarshalPayload(w, &gameRequest); err != nil { render.Render(w, r, common.ErrInvalidRequest(err)) return } @@ -161,45 +140,11 @@ func (h GameHttpServer) GetWorld(w http.ResponseWriter, r *http.Request) { return } - locations := make([]*LocationRequest, len(world.Locations)) - for i, location := range world.Locations { - paths := make([]string, len(location.Path)) - for x, path := range location.Path { - paths[x] = path.String() - } - - locations[i] = &LocationRequest{ - ID: location.LocationId.String(), - LocationId: location.LocationId.String(), - WorldId: location.WorldId.String(), - Name: location.Name, - Type: location.Type, - Path: paths, - } - } - - characters := make([]*character.CharacterRequest, len(world.Characters)) - for i, c := range world.Characters { - characters[i] = &character.CharacterRequest{ - ID: c.CharacterId.String(), - CharacterId: c.CharacterId.String(), - Name: c.Name, - Description: c.Description, - } - } - - response := &WorldRequest{ - ID: world.WorldId.String(), - WorldId: world.WorldId.String(), - GameId: world.GameId.String(), - Name: world.Name, - Locations: locations, - Characters: characters, - } + worldRquest := NewWorldRequest(world) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", jsonapi.MediaType) - if err := jsonapi.MarshalPayload(w, response); err != nil { + if err := jsonapi.MarshalPayload(w, &worldRquest); err != nil { render.Render(w, r, common.ErrInvalidRequest(err)) return } @@ -237,21 +182,9 @@ func (h GameHttpServer) GetLocations(w http.ResponseWriter, r *http.Request) { } responses := make([]*LocationRequest, len(locations)) - for i, location := range locations { - paths := make([]string, len(location.Path)) - for x, path := range location.Path { - paths[x] = path.String() - } - - responses[i] = &LocationRequest{ - ID: location.LocationId.String(), - LocationId: location.LocationId.String(), - WorldId: location.WorldId.String(), - Name: location.Name, - Type: location.Type, - Path: paths, - } + locationRequest := NewLocationRequest(location) + responses[i] = &locationRequest } w.WriteHeader(http.StatusOK) diff --git a/internal/chronicle/adapter/http/game/world_request.go b/internal/chronicle/adapter/http/game/world_request.go index 8c8ed52..22dd28d 100644 --- a/internal/chronicle/adapter/http/game/world_request.go +++ b/internal/chronicle/adapter/http/game/world_request.go @@ -9,6 +9,29 @@ import ( "github.com/google/uuid" ) +func NewWorldRequest(w domain.World) WorldRequest { + locations := make([]*LocationRequest, len(w.Locations)) + for i, location := range w.Locations { + locationRequest := NewLocationRequest(location) + locations[i] = &locationRequest + } + + characters := make([]*character.CharacterRequest, len(w.Characters)) + for i, c := range w.Characters { + characterRequest := character.NewCharacterRequest(c) + characters[i] = &characterRequest + } + + return WorldRequest{ + ID: w.WorldId.String(), + WorldId: w.WorldId.String(), + GameId: w.GameId.String(), + Name: w.Name, + Locations: locations, + Characters: characters, + } +} + type WorldRequest struct { ID string `jsonapi:"primary,worlds"` WorldId string `jsonapi:"attr,worldId"` diff --git a/internal/chronicle/adapter/persistence/postgres/query/world.go b/internal/chronicle/adapter/persistence/postgres/query/world.go index 2ff3b2c..ebc6aca 100644 --- a/internal/chronicle/adapter/persistence/postgres/query/world.go +++ b/internal/chronicle/adapter/persistence/postgres/query/world.go @@ -148,13 +148,13 @@ func (g WorldQuery) ListLocations(ctx context.Context, gameId uuid.UUID, worldId return locations, nil } -func (g WorldQuery) AddCharacterToGameWorld(ctx context.Context, worldId uuid.UUID, characterId uuid.UUID) error { +func (g WorldQuery) UpsertCharacterToGameWorld(ctx context.Context, worldId uuid.UUID, characterId uuid.UUID, character *domain.WorldCharacter) error { world, err := g.Queries.GetWorldFromUuid(ctx, worldId) if err != nil { return err } - character, err := g.Queries.GetCharacterFromUuid(ctx, characterId) + existingCharacter, err := g.Queries.GetCharacterFromUuid(ctx, characterId) if err != nil { return err } @@ -164,15 +164,24 @@ func (g WorldQuery) AddCharacterToGameWorld(ctx context.Context, worldId uuid.UU Valid: true, } - return g.Queries.AddCharacterToGameWorld(ctx, repository.AddCharacterToGameWorldParams{ + requestArgs := repository.UpsertCharacterToGameWorldParams{ // Just generating this now for future use but since we are using a unique // index for worldId and characterId, this is probably too important WorldCharacterID: uuid.New(), WorldID: world.ID, - CharacterID: character.ID, + CharacterID: existingCharacter.ID, UpdatedAt: ts, CreatedAt: ts, - }) + } + + if character != nil { + requestArgs.CharacterType = pgtype.Text{ + Valid: true, + String: character.Type.String(), + } + } + + return g.Queries.UpsertCharacterToGameWorld(ctx, requestArgs) } func (g WorldQuery) ListCharacters(ctx context.Context, gameId uuid.UUID, worldId uuid.UUID) ([]domain.Character, error) { diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241007183159_initial.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241011174940_initial.sql similarity index 99% rename from internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241007183159_initial.sql rename to internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241011174940_initial.sql index 5dae06e..ea81561 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241007183159_initial.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20241011174940_initial.sql @@ -64,6 +64,7 @@ CREATE TABLE "public"."world_character" ( "world_character_id" uuid NOT NULL, "character_id" bigserial NOT NULL, "world_id" bigserial NOT NULL, + "character_type" text NULL, "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id"), diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum index bfcdf5f..925f004 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum @@ -1,2 +1,2 @@ -h1:WV1bqxlgwnWG5/Vps8ZW+YtymgqUc5m/cgcjW6MNXPQ= -20241007183159_initial.sql h1:BZjBs/hNodmJ6DTudwr7agmc5fqwtRnYdxwnOr3CEuE= +h1:Co8gnvkgqPsXbjuDhROpfKEbZiOuDkysI8ubk167I18= +20241011174940_initial.sql h1:AauSR5nSnNnn1pcPjAlq/M/bjDS5lESaNHBJkVJ+v4A= diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql index 28bf547..d796a84 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql @@ -110,13 +110,14 @@ WHERE id = $1 LIMIT 1; SELECT * FROM character WHERE character.character_id = $1 LIMIT 1; --- name: AddCharacterToGameWorld :exec +-- name: UpsertCharacterToGameWorld :exec INSERT INTO world_character ( - world_character_id, world_id, character_id, created_at, updated_at + world_character_id, world_id, character_id, character_type, created_at, updated_at ) VALUES ( - $1, $2, $3, $4, $5 + $1, $2, $3, $4, $5, $6 ) ON CONFLICT (world_id, character_id) DO UPDATE SET + character_type = EXCLUDED.character_type, updated_at = EXCLUDED.updated_at; -- name: GetWorldCharacters :many diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go index df57c77..4ec7f47 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go @@ -53,6 +53,7 @@ type WorldCharacter struct { WorldCharacterID uuid.UUID CharacterID int64 WorldID int64 + CharacterType pgtype.Text CreatedAt pgtype.Timestamptz UpdatedAt pgtype.Timestamptz } diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go index 19aa08e..b1f9979 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go @@ -12,35 +12,6 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) -const addCharacterToGameWorld = `-- name: AddCharacterToGameWorld :exec -INSERT INTO world_character ( - world_character_id, world_id, character_id, created_at, updated_at -) VALUES ( - $1, $2, $3, $4, $5 -) -ON CONFLICT (world_id, character_id) DO UPDATE SET - updated_at = EXCLUDED.updated_at -` - -type AddCharacterToGameWorldParams struct { - WorldCharacterID uuid.UUID - WorldID int64 - CharacterID int64 - CreatedAt pgtype.Timestamptz - UpdatedAt pgtype.Timestamptz -} - -func (q *Queries) AddCharacterToGameWorld(ctx context.Context, arg AddCharacterToGameWorldParams) error { - _, err := q.db.Exec(ctx, addCharacterToGameWorld, - arg.WorldCharacterID, - arg.WorldID, - arg.CharacterID, - arg.CreatedAt, - arg.UpdatedAt, - ) - return err -} - const createCharacter = `-- name: CreateCharacter :one INSERT INTO character ( character_id, name, description, created_at, updated_at @@ -384,7 +355,7 @@ func (q *Queries) GetWorld(ctx context.Context, id int64) (World, error) { } const getWorldCharacters = `-- name: GetWorldCharacters :many -SELECT character.id, character.character_id, character.name, description, character.created_at, character.updated_at, world.id, world.world_id, game_id, world.name, world.created_at, world.updated_at, world_character.id, world_character_id, world_character.character_id, world_character.world_id, world_character.created_at, world_character.updated_at FROM character +SELECT character.id, character.character_id, character.name, description, character.created_at, character.updated_at, world.id, world.world_id, game_id, world.name, world.created_at, world.updated_at, world_character.id, world_character_id, world_character.character_id, world_character.world_id, character_type, world_character.created_at, world_character.updated_at FROM character JOIN world ON world.world_id = $1 JOIN world_character ON world_character.world_id = world.id ` @@ -406,6 +377,7 @@ type GetWorldCharactersRow struct { WorldCharacterID uuid.UUID CharacterID_2 int64 WorldID_2 int64 + CharacterType pgtype.Text CreatedAt_3 pgtype.Timestamptz UpdatedAt_3 pgtype.Timestamptz } @@ -436,6 +408,7 @@ func (q *Queries) GetWorldCharacters(ctx context.Context, worldID uuid.UUID) ([] &i.WorldCharacterID, &i.CharacterID_2, &i.WorldID_2, + &i.CharacterType, &i.CreatedAt_3, &i.UpdatedAt_3, ); err != nil { @@ -651,3 +624,35 @@ func (q *Queries) UpdateWorld(ctx context.Context, arg UpdateWorldParams) error _, err := q.db.Exec(ctx, updateWorld, arg.WorldID, arg.Name) return err } + +const upsertCharacterToGameWorld = `-- name: UpsertCharacterToGameWorld :exec +INSERT INTO world_character ( + world_character_id, world_id, character_id, character_type, created_at, updated_at +) VALUES ( + $1, $2, $3, $4, $5, $6 +) +ON CONFLICT (world_id, character_id) DO UPDATE SET + character_type = EXCLUDED.character_type, + updated_at = EXCLUDED.updated_at +` + +type UpsertCharacterToGameWorldParams struct { + WorldCharacterID uuid.UUID + WorldID int64 + CharacterID int64 + CharacterType pgtype.Text + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} + +func (q *Queries) UpsertCharacterToGameWorld(ctx context.Context, arg UpsertCharacterToGameWorldParams) error { + _, err := q.db.Exec(ctx, upsertCharacterToGameWorld, + arg.WorldCharacterID, + arg.WorldID, + arg.CharacterID, + arg.CharacterType, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql index 741da01..41a681b 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql @@ -54,6 +54,7 @@ CREATE TABLE world_character ( world_character_id uuid UNIQUE NOT NULL, character_id BIGSERIAL NOT NULL REFERENCES character(id), world_id BIGSERIAL NOT NULL REFERENCES world(id), + character_type text, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); diff --git a/internal/chronicle/core/application/application.go b/internal/chronicle/core/application/application.go index eaf7941..ec6c043 100644 --- a/internal/chronicle/core/application/application.go +++ b/internal/chronicle/core/application/application.go @@ -19,8 +19,8 @@ func NewApplication(persistence port.Persistence) port.ChronicleApplication { } gameQueries := port.GameQueries{ - ListGames: query.NewListGamesHandler(persistence.Game), - GetGame: query.NewGetGameHandler(persistence.Game), + ListGames: query.NewListGamesHandler(persistence), + GetGame: query.NewGetGameHandler(persistence), ListLocations: query.NewListLocationsHandler(persistence.World), GetWorld: query.NewGetWorldHandler(persistence.World), } diff --git a/internal/chronicle/core/application/command/add_world_character.go b/internal/chronicle/core/application/command/add_world_character.go index 4e6615d..60702ec 100644 --- a/internal/chronicle/core/application/command/add_world_character.go +++ b/internal/chronicle/core/application/command/add_world_character.go @@ -23,5 +23,5 @@ type addWorldCharacterHandler struct { func (c addWorldCharacterHandler) Handle(ctx context.Context, cmd corePort.AddWorldCharacter) error { log.Printf("Adding character %s to world %s", cmd.CharacterId, cmd.WorldId) - return c.Persistence.AddCharacterToGameWorld(ctx, cmd.WorldId, cmd.CharacterId) + return c.Persistence.UpsertCharacterToGameWorld(ctx, cmd.WorldId, cmd.CharacterId, nil) } diff --git a/internal/chronicle/core/application/command/update_world_character.go b/internal/chronicle/core/application/command/update_world_character.go index 0d914ac..2e526b3 100644 --- a/internal/chronicle/core/application/command/update_world_character.go +++ b/internal/chronicle/core/application/command/update_world_character.go @@ -4,6 +4,7 @@ import ( "context" "log" + "github.com/SomethingSexy/chronicle/internal/chronicle/core/domain" corePort "github.com/SomethingSexy/chronicle/internal/chronicle/core/port" "github.com/SomethingSexy/chronicle/internal/chronicle/port" "github.com/SomethingSexy/chronicle/internal/common" @@ -23,5 +24,7 @@ type updateWorldCharacterHandler struct { func (c updateWorldCharacterHandler) Handle(ctx context.Context, cmd corePort.UpdateWorldCharacter) error { log.Printf("Patching character %s to world %s", cmd.CharacterId, cmd.WorldId) - return c.Persistence.AddCharacterToGameWorld(ctx, cmd.WorldId, cmd.CharacterId) + return c.Persistence.UpsertCharacterToGameWorld(ctx, cmd.WorldId, cmd.CharacterId, &domain.WorldCharacter{ + Type: cmd.WorldCharacter.Type, + }) } diff --git a/internal/chronicle/core/application/query/get_game.go b/internal/chronicle/core/application/query/get_game.go index 3667329..9a0ccc7 100644 --- a/internal/chronicle/core/application/query/get_game.go +++ b/internal/chronicle/core/application/query/get_game.go @@ -8,16 +8,36 @@ import ( "github.com/SomethingSexy/chronicle/internal/chronicle/port" ) -func NewGetGameHandler(persistence port.GamePersistence) gamePort.GetGameHandler { +func NewGetGameHandler(persistence port.Persistence) gamePort.GetGameHandler { return getGameHandler{ Persistence: persistence, } } type getGameHandler struct { - Persistence port.GamePersistence + Persistence port.Persistence } func (h getGameHandler) Handle(ctx context.Context, q gamePort.GetGameQuery) (domain.Game, error) { - return h.Persistence.GetGame(ctx, q.GameId) + game, err := h.Persistence.Game.GetGame(ctx, q.GameId) + if err != nil { + return domain.Game{}, err + } + + worlds, err := h.Persistence.Game.GetGameWorlds(ctx, game.GameId) + if err != nil { + return domain.Game{}, err + } + + for x := 0; x < len(worlds); x++ { + characters, err := h.Persistence.World.ListCharacters(ctx, worlds[x].GameId, worlds[x].WorldId) + if err != nil { + return domain.Game{}, err + } + worlds[x].Characters = characters + } + + game.Worlds = worlds + + return game, nil } diff --git a/internal/chronicle/core/application/query/list_game.go b/internal/chronicle/core/application/query/list_game.go index f7f01ba..0e24e1b 100644 --- a/internal/chronicle/core/application/query/list_game.go +++ b/internal/chronicle/core/application/query/list_game.go @@ -8,31 +8,39 @@ import ( "github.com/SomethingSexy/chronicle/internal/chronicle/port" ) -func NewListGamesHandler(persistence port.GamePersistence) gamePort.ListGamesHandler { +func NewListGamesHandler(persistence port.Persistence) gamePort.ListGamesHandler { return listGamesHandler{ Persistence: persistence, } } type listGamesHandler struct { - Persistence port.GamePersistence + Persistence port.Persistence } func (h listGamesHandler) Handle(ctx context.Context, _ gamePort.AllGamesQuery) ([]domain.Game, error) { // Fetching these separately for now, when necessary we could make these joins at the lower level // For now, this gives me more power to move this logic around as needed - games, err := h.Persistence.ListGames(ctx) + games, err := h.Persistence.Game.ListGames(ctx) if err != nil { return nil, err } for i := 0; i < len(games); i++ { - world, err := h.Persistence.GetGameWorlds(ctx, games[i].GameId) + worlds, err := h.Persistence.Game.GetGameWorlds(ctx, games[i].GameId) if err != nil { return nil, err } - games[i].Worlds = world + for x := 0; x < len(worlds); x++ { + characters, err := h.Persistence.World.ListCharacters(ctx, worlds[x].GameId, worlds[x].WorldId) + if err != nil { + return nil, err + } + worlds[x].Characters = characters + } + + games[i].Worlds = worlds } return games, nil diff --git a/internal/chronicle/core/domain/world_character.go b/internal/chronicle/core/domain/world_character.go index 671be41..de20df2 100644 --- a/internal/chronicle/core/domain/world_character.go +++ b/internal/chronicle/core/domain/world_character.go @@ -2,9 +2,9 @@ package domain func NewCharacterType(t string) CharacterType { switch t { - case "NPC": + case "npc": return NPC - case "PC": + case "pc": return PC } @@ -19,7 +19,7 @@ const ( ) func (t CharacterType) String() string { - return [...]string{"NPC", "PC"}[t-1] + return [...]string{"npc", "pc"}[t-1] } // Represents a character that has been added to a world diff --git a/internal/chronicle/core/port/world.go b/internal/chronicle/core/port/world.go index 7497348..dfa7025 100644 --- a/internal/chronicle/core/port/world.go +++ b/internal/chronicle/core/port/world.go @@ -28,3 +28,4 @@ type UpdateWorldCharacter struct { CharacterId uuid.UUID WorldCharacter domain.WorldCharacter } +type UpdateWorldCharacterHandler common.CommandHandler[UpdateWorldCharacter] \ No newline at end of file diff --git a/internal/chronicle/port/persistence.go b/internal/chronicle/port/persistence.go index 1f15ea9..2764333 100644 --- a/internal/chronicle/port/persistence.go +++ b/internal/chronicle/port/persistence.go @@ -35,5 +35,5 @@ type WorldPersistence interface { ListLocations(ctx context.Context, gameId uuid.UUID, worldId uuid.UUID) ([]domain.Location, error) ListCharacters(ctx context.Context, gameId uuid.UUID, worldId uuid.UUID) ([]domain.Character, error) - AddCharacterToGameWorld(ctx context.Context, worldId uuid.UUID, characterId uuid.UUID) error + UpsertCharacterToGameWorld(ctx context.Context, worldId uuid.UUID, characterId uuid.UUID, character *domain.WorldCharacter) error } diff --git a/internal/chronicle/tools/http/game.http b/internal/chronicle/tools/http/game.http index e8a9553..315816b 100644 --- a/internal/chronicle/tools/http/game.http +++ b/internal/chronicle/tools/http/game.http @@ -23,6 +23,11 @@ Content-Type: application/vnd.api+json ### +# @name get_game +GET http://localhost:3000/games/{{gameId}} +Content-Type: application/vnd.api+json + +### # @name create_world POST http://localhost:3000/games/{{gameId}}/worlds