From f2116b417e24df2336fbce2dd4eb6864458d702b Mon Sep 17 00:00:00 2001 From: Tyler J Cvetan Date: Tue, 20 Aug 2024 20:31:01 +0000 Subject: [PATCH] feat: work on listing games, start world and location --- README.md | 4 + .../adapter/http/game/game_request.go | 1 + .../adapter/http/game/game_server.go | 31 ++++ internal/chronicle/adapter/http/http.go | 2 +- .../persistence/postgres/query/game.go | 37 +++- ...initial.sql => 20240820200446_initial.sql} | 7 + .../postgres/sqlc/migrations/atlas.sum | 4 +- .../persistence/postgres/sqlc/query.sql | 41 ++++- .../postgres/sqlc/repository/models.go | 10 +- .../postgres/sqlc/repository/query.sql.go | 158 ++++++++++++++++-- .../persistence/postgres/sqlc/schema.sql | 8 +- .../persistence/postgres/sqlc/sqlc.yml | 5 + .../chronicle/core/application/application.go | 6 + .../core/application/command/create_game.go | 3 +- .../core/application/query/list_game.go | 23 +++ internal/chronicle/core/port/game.go | 4 + internal/chronicle/port/chronicle.go | 1 + internal/chronicle/port/service.go | 1 + internal/chronicle/service/application.go | 2 +- .../chronicle/tools/http/create_game.http | 8 +- internal/common/query.go | 7 + 21 files changed, 327 insertions(+), 36 deletions(-) rename internal/chronicle/adapter/persistence/postgres/sqlc/migrations/{20240818215306_initial.sql => 20240820200446_initial.sql} (80%) create mode 100644 internal/chronicle/core/application/query/list_game.go create mode 100644 internal/common/query.go diff --git a/README.md b/README.md index 45ccd84..b5004ab 100644 --- a/README.md +++ b/README.md @@ -65,3 +65,7 @@ atlas migrate apply \ --dir "file://migrations" \ --baseline "20240731025606" ``` + +Using the free version of Atlas, we need to manually add extensions. + +Right now we are adding them to the root migration (probably should make this a separate first migration). diff --git a/internal/chronicle/adapter/http/game/game_request.go b/internal/chronicle/adapter/http/game/game_request.go index 6e26aa9..122ea39 100644 --- a/internal/chronicle/adapter/http/game/game_request.go +++ b/internal/chronicle/adapter/http/game/game_request.go @@ -9,6 +9,7 @@ import ( ) type GameRequest struct { + ID string `jsonapi:"primary,games"` GameId string `jsonapi:"attr,gameId"` Name string `jsonapi:"attr,name"` Type string `jsonapi:"attr,type"` diff --git a/internal/chronicle/adapter/http/game/game_server.go b/internal/chronicle/adapter/http/game/game_server.go index ff9889a..ce555ba 100644 --- a/internal/chronicle/adapter/http/game/game_server.go +++ b/internal/chronicle/adapter/http/game/game_server.go @@ -8,6 +8,7 @@ import ( "github.com/SomethingSexy/chronicle/internal/common" "github.com/go-chi/chi/v5" "github.com/go-chi/render" + "github.com/google/jsonapi" ) func NewGameHttpServer(commands port.ChronicleCommands, queries port.GameQueries) GameHttpServer { @@ -25,6 +26,7 @@ type GameHttpServer struct { func (h GameHttpServer) Routes() chi.Router { r := chi.NewRouter() r.Post("/", h.CreateGame) + r.Get("/", h.ListGames) return r } @@ -45,3 +47,32 @@ func (h GameHttpServer) CreateGame(w http.ResponseWriter, r *http.Request) { render.Status(r, http.StatusCreated) // render.Render(w, r, NewGameResponse(article)) } + +func (h GameHttpServer) ListGames(w http.ResponseWriter, r *http.Request) { + games, err := h.queries.ListGames.Handle(r.Context(), corePort.AllGamesQuery{}) + if err != nil { + render.Render(w, r, common.ErrInvalidRequest(err)) + return + } + + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", jsonapi.MediaType) + + responses := make([]*GameRequest, len(games)) + + for i, game := range games { + responses[i] = &GameRequest{ + ID: game.GameId.String(), + GameId: game.GameId.String(), + Name: game.Name, + Type: game.Type, + } + } + + if err := jsonapi.MarshalPayload(w, responses); err != nil { + render.Render(w, r, common.ErrInvalidRequest(err)) + return + } + // render.Status(r, http.StatusCreated) + // render.Render(w, r, NewGameResponse(article)) +} diff --git a/internal/chronicle/adapter/http/http.go b/internal/chronicle/adapter/http/http.go index 3465143..820ee2a 100644 --- a/internal/chronicle/adapter/http/http.go +++ b/internal/chronicle/adapter/http/http.go @@ -30,7 +30,7 @@ func (h HttpServer) Start() { render.Decode = DefaultDecoder // TODO: Given the application, this should mount all of the route handlers - r.Mount("/game", h.app.Routes()[0]) + r.Mount("/games", h.app.Routes()[0]) http.ListenAndServe(":3000", r) } diff --git a/internal/chronicle/adapter/persistence/postgres/query/game.go b/internal/chronicle/adapter/persistence/postgres/query/game.go index 9a067c1..cf14480 100644 --- a/internal/chronicle/adapter/persistence/postgres/query/game.go +++ b/internal/chronicle/adapter/persistence/postgres/query/game.go @@ -5,7 +5,6 @@ import ( "github.com/SomethingSexy/chronicle/internal/chronicle/adapter/persistence/postgres/sqlc/repository" "github.com/SomethingSexy/chronicle/internal/chronicle/core/domain" - "github.com/jackc/pgx/v5/pgtype" ) func NewGameQuery(queries *repository.Queries) GameQuery { @@ -19,16 +18,12 @@ type GameQuery struct { Queries *repository.Queries } +// Create a game func (g GameQuery) CreateGame(ctx context.Context, game domain.Game) (domain.Game, error) { - // s := fmt.Sprintf("%x-%x-%x-%x-%x", myUUID.Bytes[0:4], myUUID.Bytes[4:6], myUUID.Bytes[6:8], myUUID.Bytes[8:10], myUUID.Bytes[10:16]) - args := repository.CreateGameParams{ - GameID: pgtype.UUID{ - Bytes: game.GameId, - Valid: true, - }, - Name: game.Name, - Type: game.Type, + GameID: game.GameId, + Name: game.Name, + Type: game.Type, } response, err := g.Queries.CreateGame(ctx, args) @@ -41,3 +36,27 @@ func (g GameQuery) CreateGame(ctx context.Context, game domain.Game) (domain.Gam Type: response.Type, }, nil } + +// List all available games. +// TODO: +// - Limit games by user who created them +// - Limit games if they are marked private +// - Allow admin to see all games +func (g GameQuery) ListGames(ctx context.Context) ([]domain.Game, error) { + response, err := g.Queries.ListGames(ctx) + if err != nil { + return nil, err + } + + games := make([]domain.Game, len(response)) + + for i, game := range response { + games[i] = domain.Game{ + Name: game.Name, + Type: game.Type, + GameId: game.GameID, + } + } + + return games, nil +} diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240818215306_initial.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240820200446_initial.sql similarity index 80% rename from internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240818215306_initial.sql rename to internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240820200446_initial.sql index 3a2124e..733f126 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240818215306_initial.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/20240820200446_initial.sql @@ -1,3 +1,5 @@ +CREATE EXTENSION "ltree"; + -- Create "game" table CREATE TABLE "public"."game" ( "id" bigserial NOT NULL, @@ -12,10 +14,13 @@ CREATE TABLE "public"."world" ( "id" bigserial NOT NULL, "world_id" uuid NOT NULL, "game_id" bigserial NOT NULL, + "name" text NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "world_world_id_key" UNIQUE ("world_id"), CONSTRAINT "world_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "public"."game" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION ); +-- Create index "world_game_id" to table: "world" +CREATE INDEX "world_game_id" ON "public"."world" ("game_id"); -- Create "location" table CREATE TABLE "public"."location" ( "id" bigserial NOT NULL, @@ -30,3 +35,5 @@ CREATE TABLE "public"."location" ( ); -- Create index "location_path_idx" to table: "location" CREATE INDEX "location_path_idx" ON "public"."location" USING gist ("path"); +-- Create index "location_world_id" to table: "location" +CREATE INDEX "location_world_id" ON "public"."location" ("world_id"); diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum b/internal/chronicle/adapter/persistence/postgres/sqlc/migrations/atlas.sum index 57962d6..4e8e9b5 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:92SiNSQUSUJ2MaDX0pAvt0LDqO9sw13Fl2hVm2Nkjck= -20240818215306_initial.sql h1:rs/Idnz34OnOmdLKzVOUs15THtfcW+3H5auFWBqVc+s= +h1:e7Whf5lPTyJ5gZaclj0NLm1BA25BpU/S/uuWiNUeGFs= +20240820200446_initial.sql h1:FINnqTjzKlGS/n7twb3x1BGaGGqC/f/ztU7N/RNOQcU= diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql index e83f6d0..c3c5a60 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/query.sql @@ -2,6 +2,10 @@ SELECT * FROM game WHERE id = $1 LIMIT 1; +-- name: GetGameFromUuid :one +SELECT * FROM game +WHERE game_id = $1 LIMIT 1; + -- name: ListGames :many SELECT * FROM game ORDER BY name; @@ -12,7 +16,7 @@ INSERT INTO game ( ) VALUES ( $1, $2, $3 ) -ON CONFLICT (game_id) DO UPDATE SET +ON CONFLICT (game_id) DO UPDATE SET name = EXCLUDED.name, type = EXCLUDED.type RETURNING *; @@ -21,8 +25,39 @@ RETURNING *; UPDATE game set name = $2, type = $3 -WHERE id = $1; +WHERE game_id = $1; -- name: DeleteGame :exec DELETE FROM game -WHERE id = $1; \ No newline at end of file +WHERE game_id = $1; + +-- name: GetWorld :one +SELECT * FROM world +WHERE id = $1 LIMIT 1; + +-- name: GetWorldFromUuid :one +SELECT * FROM world +WHERE world_id = $1 LIMIT 1; + +-- name: ListWorlds :many +SELECT * FROM world +ORDER BY name; + +-- name: CreateWorld :one +INSERT INTO world ( + world_id, game_id, name +) VALUES ( + $1, $2, $3 +) +ON CONFLICT (world_id) DO UPDATE SET + name = EXCLUDED.name +RETURNING *; + +-- name: UpdateWorld :exec +UPDATE world + set name = $2 +WHERE world_id = $1; + +-- name: DeleteWorld :exec +DELETE FROM world +WHERE world_id = $1; \ No newline at end of file diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go index 8849446..254b229 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/models.go @@ -5,19 +5,20 @@ package repository import ( + "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) type Game struct { ID int64 - GameID pgtype.UUID + GameID uuid.UUID Name string Type string } type Location struct { - Ud int64 - LocationID pgtype.UUID + ID int64 + LocationID uuid.UUID WorldID int64 Type string Name string @@ -26,6 +27,7 @@ type Location struct { type World struct { ID int64 - WorldID pgtype.UUID + WorldID uuid.UUID GameID int64 + Name string } 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 ded60f5..658d8e7 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/repository/query.sql.go @@ -8,7 +8,7 @@ package repository import ( "context" - "github.com/jackc/pgx/v5/pgtype" + "github.com/google/uuid" ) const createGame = `-- name: CreateGame :one @@ -17,14 +17,14 @@ INSERT INTO game ( ) VALUES ( $1, $2, $3 ) -ON CONFLICT (game_id) DO UPDATE SET +ON CONFLICT (game_id) DO UPDATE SET name = EXCLUDED.name, type = EXCLUDED.type RETURNING id, game_id, name, type ` type CreateGameParams struct { - GameID pgtype.UUID + GameID uuid.UUID Name string Type string } @@ -41,13 +41,52 @@ func (q *Queries) CreateGame(ctx context.Context, arg CreateGameParams) (Game, e return i, err } +const createWorld = `-- name: CreateWorld :one +INSERT INTO world ( + world_id, game_id, name +) VALUES ( + $1, $2, $3 +) +ON CONFLICT (world_id) DO UPDATE SET + name = EXCLUDED.name +RETURNING id, world_id, game_id, name +` + +type CreateWorldParams struct { + WorldID uuid.UUID + GameID int64 + Name string +} + +func (q *Queries) CreateWorld(ctx context.Context, arg CreateWorldParams) (World, error) { + row := q.db.QueryRow(ctx, createWorld, arg.WorldID, arg.GameID, arg.Name) + var i World + err := row.Scan( + &i.ID, + &i.WorldID, + &i.GameID, + &i.Name, + ) + return i, err +} + const deleteGame = `-- name: DeleteGame :exec DELETE FROM game -WHERE id = $1 +WHERE game_id = $1 ` -func (q *Queries) DeleteGame(ctx context.Context, id int64) error { - _, err := q.db.Exec(ctx, deleteGame, id) +func (q *Queries) DeleteGame(ctx context.Context, gameID uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteGame, gameID) + return err +} + +const deleteWorld = `-- name: DeleteWorld :exec +DELETE FROM world +WHERE world_id = $1 +` + +func (q *Queries) DeleteWorld(ctx context.Context, worldID uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteWorld, worldID) return err } @@ -68,6 +107,57 @@ func (q *Queries) GetGame(ctx context.Context, id int64) (Game, error) { return i, err } +const getGameFromUuid = `-- name: GetGameFromUuid :one +SELECT id, game_id, name, type FROM game +WHERE game_id = $1 LIMIT 1 +` + +func (q *Queries) GetGameFromUuid(ctx context.Context, gameID uuid.UUID) (Game, error) { + row := q.db.QueryRow(ctx, getGameFromUuid, gameID) + var i Game + err := row.Scan( + &i.ID, + &i.GameID, + &i.Name, + &i.Type, + ) + return i, err +} + +const getWorld = `-- name: GetWorld :one +SELECT id, world_id, game_id, name FROM world +WHERE id = $1 LIMIT 1 +` + +func (q *Queries) GetWorld(ctx context.Context, id int64) (World, error) { + row := q.db.QueryRow(ctx, getWorld, id) + var i World + err := row.Scan( + &i.ID, + &i.WorldID, + &i.GameID, + &i.Name, + ) + return i, err +} + +const getWorldFromUuid = `-- name: GetWorldFromUuid :one +SELECT id, world_id, game_id, name FROM world +WHERE world_id = $1 LIMIT 1 +` + +func (q *Queries) GetWorldFromUuid(ctx context.Context, worldID uuid.UUID) (World, error) { + row := q.db.QueryRow(ctx, getWorldFromUuid, worldID) + var i World + err := row.Scan( + &i.ID, + &i.WorldID, + &i.GameID, + &i.Name, + ) + return i, err +} + const listGames = `-- name: ListGames :many SELECT id, game_id, name, type FROM game ORDER BY name @@ -98,20 +188,66 @@ func (q *Queries) ListGames(ctx context.Context) ([]Game, error) { return items, nil } +const listWorlds = `-- name: ListWorlds :many +SELECT id, world_id, game_id, name FROM world +ORDER BY name +` + +func (q *Queries) ListWorlds(ctx context.Context) ([]World, error) { + rows, err := q.db.Query(ctx, listWorlds) + if err != nil { + return nil, err + } + defer rows.Close() + var items []World + for rows.Next() { + var i World + if err := rows.Scan( + &i.ID, + &i.WorldID, + &i.GameID, + &i.Name, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const updateGame = `-- name: UpdateGame :exec UPDATE game set name = $2, type = $3 -WHERE id = $1 +WHERE game_id = $1 ` type UpdateGameParams struct { - ID int64 - Name string - Type string + GameID uuid.UUID + Name string + Type string } func (q *Queries) UpdateGame(ctx context.Context, arg UpdateGameParams) error { - _, err := q.db.Exec(ctx, updateGame, arg.ID, arg.Name, arg.Type) + _, err := q.db.Exec(ctx, updateGame, arg.GameID, arg.Name, arg.Type) + return err +} + +const updateWorld = `-- name: UpdateWorld :exec +UPDATE world + set name = $2 +WHERE world_id = $1 +` + +type UpdateWorldParams struct { + WorldID uuid.UUID + Name string +} + +func (q *Queries) UpdateWorld(ctx context.Context, arg UpdateWorldParams) error { + _, err := q.db.Exec(ctx, updateWorld, arg.WorldID, arg.Name) return err } diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql b/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql index 4ab7059..42da06d 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/schema.sql @@ -13,16 +13,20 @@ CREATE TABLE game ( CREATE TABLE world ( id BIGSERIAL PRIMARY KEY, world_id uuid UNIQUE NOT NULL, - game_id BIGSERIAL NOT NULL REFERENCES game(id) + game_id BIGSERIAL NOT NULL REFERENCES game(id), + name text NOT NULL ); +create index world_game_id on world(game_id); + CREATE TABLE location ( id BIGSERIAL PRIMARY KEY, location_id uuid UNIQUE NOT NULL, - world_ID BIGSERIAL NOT NULL REFERENCES world(id), + world_id BIGSERIAL NOT NULL REFERENCES world(id), type text NOT NULL, name text NOT NULL, path ltree ); +create index location_world_id on location(world_id); create index location_path_idx on location using gist (path); \ No newline at end of file diff --git a/internal/chronicle/adapter/persistence/postgres/sqlc/sqlc.yml b/internal/chronicle/adapter/persistence/postgres/sqlc/sqlc.yml index 1601c9e..2784c66 100644 --- a/internal/chronicle/adapter/persistence/postgres/sqlc/sqlc.yml +++ b/internal/chronicle/adapter/persistence/postgres/sqlc/sqlc.yml @@ -8,3 +8,8 @@ sql: package: "repository" out: "repository" sql_package: "pgx/v5" + overrides: + - db_type: "uuid" + go_type: + import: "github.com/google/uuid" + type: "UUID" diff --git a/internal/chronicle/core/application/application.go b/internal/chronicle/core/application/application.go index 4b20da7..e001896 100644 --- a/internal/chronicle/core/application/application.go +++ b/internal/chronicle/core/application/application.go @@ -2,6 +2,7 @@ package application import ( "github.com/SomethingSexy/chronicle/internal/chronicle/core/application/command" + "github.com/SomethingSexy/chronicle/internal/chronicle/core/application/query" "github.com/SomethingSexy/chronicle/internal/chronicle/port" ) @@ -10,8 +11,13 @@ func NewApplication(persistence port.ChronicleQueries) port.ChronicleApplication CreateGame: command.NewCreateGameCommand(persistence), } + queries := port.GameQueries{ + ListGames: query.NewListGamesHandler(persistence), + } + return port.ChronicleApplication{ Commands: commands, + Queries: queries, Persistence: persistence, } } diff --git a/internal/chronicle/core/application/command/create_game.go b/internal/chronicle/core/application/command/create_game.go index 00da67e..d81a26e 100644 --- a/internal/chronicle/core/application/command/create_game.go +++ b/internal/chronicle/core/application/command/create_game.go @@ -10,7 +10,6 @@ import ( ) func NewCreateGameCommand(persistence port.ChronicleQueries) common.CommandHandler[gamePort.CreateGame] { - return createGameHandler{ Persistence: persistence, } @@ -21,7 +20,7 @@ type createGameHandler struct { } func (c createGameHandler) Handle(ctx context.Context, cmd gamePort.CreateGame) error { - log.Printf("Create game %s", cmd.Game.Name) + log.Printf("Creating game %s with id %s", cmd.Game.Name, cmd.Game.GameId) _, err := c.Persistence.CreateGame(ctx, cmd.Game) if err != nil { return err diff --git a/internal/chronicle/core/application/query/list_game.go b/internal/chronicle/core/application/query/list_game.go new file mode 100644 index 0000000..dd78548 --- /dev/null +++ b/internal/chronicle/core/application/query/list_game.go @@ -0,0 +1,23 @@ +package query + +import ( + "context" + + "github.com/SomethingSexy/chronicle/internal/chronicle/core/domain" + gamePort "github.com/SomethingSexy/chronicle/internal/chronicle/core/port" + "github.com/SomethingSexy/chronicle/internal/chronicle/port" +) + +func NewListGamesHandler(persistence port.ChronicleQueries) gamePort.ListGamesHandler { + return listGamesHandler{ + Persistence: persistence, + } +} + +type listGamesHandler struct { + Persistence port.ChronicleQueries +} + +func (h listGamesHandler) Handle(ctx context.Context, _ gamePort.AllGamesQuery) ([]domain.Game, error) { + return h.Persistence.ListGames(ctx) +} diff --git a/internal/chronicle/core/port/game.go b/internal/chronicle/core/port/game.go index 3098e57..08546d0 100644 --- a/internal/chronicle/core/port/game.go +++ b/internal/chronicle/core/port/game.go @@ -10,3 +10,7 @@ type CreateGame struct { } type CreateGameHander common.CommandHandler[CreateGame] + +type AllGamesQuery struct { +} +type ListGamesHandler common.QueryHandler[AllGamesQuery, []domain.Game] diff --git a/internal/chronicle/port/chronicle.go b/internal/chronicle/port/chronicle.go index e58db6f..93b79e9 100644 --- a/internal/chronicle/port/chronicle.go +++ b/internal/chronicle/port/chronicle.go @@ -9,4 +9,5 @@ import ( // TODO: Probably a better name for this type ChronicleQueries interface { CreateGame(ctx context.Context, game domain.Game) (domain.Game, error) + ListGames(ctx context.Context) ([]domain.Game, error) } diff --git a/internal/chronicle/port/service.go b/internal/chronicle/port/service.go index 1196707..4aca15e 100644 --- a/internal/chronicle/port/service.go +++ b/internal/chronicle/port/service.go @@ -15,4 +15,5 @@ type ChronicleCommands struct { } type GameQueries struct { + ListGames corePort.ListGamesHandler } diff --git a/internal/chronicle/service/application.go b/internal/chronicle/service/application.go index 944bafe..3c8ca22 100644 --- a/internal/chronicle/service/application.go +++ b/internal/chronicle/service/application.go @@ -45,7 +45,7 @@ type ChronicleService struct { } func (c ChronicleService) Routes() []chi.Router { - gameHttpServer := game.NewGameHttpServer(c.ChronicleApplication.Commands, port.GameQueries{}) + gameHttpServer := game.NewGameHttpServer(c.ChronicleApplication.Commands, c.ChronicleApplication.Queries) routes := gameHttpServer.Routes() return []chi.Router{routes} } diff --git a/internal/chronicle/tools/http/create_game.http b/internal/chronicle/tools/http/create_game.http index fb989f6..98b1852 100644 --- a/internal/chronicle/tools/http/create_game.http +++ b/internal/chronicle/tools/http/create_game.http @@ -1,5 +1,5 @@ # @name create -POST http://localhost:3000/game +POST http://localhost:3000/games Content-Type: application/vnd.api+json { @@ -13,4 +13,10 @@ Content-Type: application/vnd.api+json } } +### + +# @name list +GET http://localhost:3000/games +Content-Type: application/vnd.api+json + ### \ No newline at end of file diff --git a/internal/common/query.go b/internal/common/query.go new file mode 100644 index 0000000..0745863 --- /dev/null +++ b/internal/common/query.go @@ -0,0 +1,7 @@ +package common + +import "context" + +type QueryHandler[Q any, R any] interface { + Handle(ctx context.Context, q Q) (R, error) +}