feat: implement battle replay module with database migrations, repository, and CRUD service endpoints
All checks were successful
Build and Release / release (push) Successful in 1m32s
All checks were successful
Build and Release / release (push) Successful in 1m32s
This commit is contained in:
8902
FinalProject.drawio
Normal file
8902
FinalProject.drawio
Normal file
File diff suppressed because it is too large
Load Diff
@@ -98,6 +98,7 @@ func (s *FiberServer) SetupServer(
|
|||||||
usageRepo := repositories.NewUsageRepository(redis)
|
usageRepo := repositories.NewUsageRepository(redis)
|
||||||
statisticRepo := repositories.NewStatisticRepository(poolPg, redis)
|
statisticRepo := repositories.NewStatisticRepository(poolPg, redis)
|
||||||
chatRepo := repositories.NewChatRepository(poolPg, redis)
|
chatRepo := repositories.NewChatRepository(poolPg, redis)
|
||||||
|
battleReplayRepo := repositories.NewBattleReplayRepository(poolPg, redis)
|
||||||
|
|
||||||
// service setup
|
// service setup
|
||||||
authService := services.NewAuthService(userRepo, roleRepo, tokenRepo, redis, poolPg)
|
authService := services.NewAuthService(userRepo, roleRepo, tokenRepo, redis, poolPg)
|
||||||
@@ -115,10 +116,11 @@ func (s *FiberServer) SetupServer(
|
|||||||
submissionService := services.NewSubmissionService(
|
submissionService := services.NewSubmissionService(
|
||||||
submissionRepo, projectRepo, commitRepo,
|
submissionRepo, projectRepo, commitRepo,
|
||||||
userRepo, wikiRepo, geometryRepo, entityRepo,
|
userRepo, wikiRepo, geometryRepo, entityRepo,
|
||||||
raguRepo, raguUtils, poolPg, redis,
|
battleReplayRepo, raguRepo, raguUtils, poolPg, redis,
|
||||||
)
|
)
|
||||||
chatbotService := services.NewChatbotService(raguRepo, usageRepo, chatRepo, raguUtils)
|
chatbotService := services.NewChatbotService(raguRepo, usageRepo, chatRepo, raguUtils)
|
||||||
statisticService := services.NewStatisticService(statisticRepo)
|
statisticService := services.NewStatisticService(statisticRepo)
|
||||||
|
battleReplayService := services.NewBattleReplayService(battleReplayRepo)
|
||||||
|
|
||||||
// controller setup
|
// controller setup
|
||||||
authController := controllers.NewAuthController(authService, oauth)
|
authController := controllers.NewAuthController(authService, oauth)
|
||||||
@@ -136,6 +138,7 @@ func (s *FiberServer) SetupServer(
|
|||||||
submissionController := controllers.NewSubmissionController(submissionService)
|
submissionController := controllers.NewSubmissionController(submissionService)
|
||||||
chatbotController := controllers.NewChatbotController(chatbotService)
|
chatbotController := controllers.NewChatbotController(chatbotService)
|
||||||
statisticController := controllers.NewStatisticController(statisticService)
|
statisticController := controllers.NewStatisticController(statisticService)
|
||||||
|
battleReplayController := controllers.NewBattleReplayController(battleReplayService)
|
||||||
|
|
||||||
// route setup
|
// route setup
|
||||||
routes.AuthRoutes(s.App, authController, userRepo)
|
routes.AuthRoutes(s.App, authController, userRepo)
|
||||||
@@ -152,5 +155,6 @@ func (s *FiberServer) SetupServer(
|
|||||||
routes.SubmissionRoutes(s.App, submissionController, userRepo)
|
routes.SubmissionRoutes(s.App, submissionController, userRepo)
|
||||||
routes.ChatbotRoutes(s.App, chatbotController, userRepo)
|
routes.ChatbotRoutes(s.App, chatbotController, userRepo)
|
||||||
routes.StatisticRoutes(s.App, statisticController, userRepo)
|
routes.StatisticRoutes(s.App, statisticController, userRepo)
|
||||||
|
routes.BattleReplayRoutes(s.App, battleReplayController)
|
||||||
routes.NotFoundRoute(s.App)
|
routes.NotFoundRoute(s.App)
|
||||||
}
|
}
|
||||||
|
|||||||
1
db/migrations/000017_battle_replays.down.sql
Normal file
1
db/migrations/000017_battle_replays.down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE IF EXISTS battle_replays;
|
||||||
28
db/migrations/000017_battle_replays.up.sql
Normal file
28
db/migrations/000017_battle_replays.up.sql
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS battle_replays (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
|
geometry_id UUID NOT NULL REFERENCES geometries(id) ON DELETE CASCADE,
|
||||||
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
target_geometry_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||||
|
detail JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||||
|
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_battle_replays_geometry_id ON battle_replays(geometry_id)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
|
CREATE INDEX idx_battle_replays_project_id ON battle_replays(project_id)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
|
CREATE INDEX idx_battle_replays_target_geometry_ids ON battle_replays USING GIN (target_geometry_ids)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
|
CREATE INDEX idx_battle_replays_updated_at ON battle_replays(updated_at DESC)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS trigger_battle_replays_updated_at ON battle_replays;
|
||||||
|
CREATE TRIGGER trigger_battle_replays_updated_at
|
||||||
|
BEFORE UPDATE ON battle_replays
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_updated_at();
|
||||||
49
db/query/battle_replay.sql
Normal file
49
db/query/battle_replay.sql
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
-- name: CreateBattleReplay :one
|
||||||
|
INSERT INTO battle_replays (
|
||||||
|
id, geometry_id, project_id, target_geometry_ids, detail
|
||||||
|
) VALUES (
|
||||||
|
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3, $4
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetBattleReplayById :one
|
||||||
|
SELECT *
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE id = $1 AND is_deleted = false;
|
||||||
|
|
||||||
|
-- name: GetBattleReplaysByIDs :many
|
||||||
|
SELECT * FROM battle_replays WHERE id = ANY($1::uuid[]) AND is_deleted = false;
|
||||||
|
|
||||||
|
-- name: GetBattleReplaysByGeometryId :many
|
||||||
|
SELECT *
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE geometry_id = $1 AND is_deleted = false;
|
||||||
|
|
||||||
|
-- name: GetBattleReplaysByGeometryIDs :many
|
||||||
|
SELECT *
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE geometry_id = ANY($1::uuid[]) AND is_deleted = false;
|
||||||
|
|
||||||
|
-- name: GetBattleReplaysByProjectId :many
|
||||||
|
SELECT *
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE project_id = $1 AND is_deleted = false;
|
||||||
|
|
||||||
|
-- name: UpdateBattleReplay :one
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET
|
||||||
|
geometry_id = COALESCE(sqlc.narg('geometry_id'), geometry_id),
|
||||||
|
target_geometry_ids = COALESCE(sqlc.narg('target_geometry_ids'), target_geometry_ids),
|
||||||
|
detail = COALESCE(sqlc.narg('detail'), detail)
|
||||||
|
WHERE id = sqlc.arg('id') AND is_deleted = false
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteBattleReplay :exec
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET is_deleted = true
|
||||||
|
WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: DeleteBattleReplaysByIDs :exec
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET is_deleted = true
|
||||||
|
WHERE id = ANY($1::uuid[]);
|
||||||
@@ -243,3 +243,14 @@ CREATE TABLE IF NOT EXISTS chatbot_histories (
|
|||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS battle_replays (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
|
geometry_id UUID NOT NULL REFERENCES geometries(id) ON DELETE CASCADE,
|
||||||
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
target_geometry_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||||
|
detail JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||||
|
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
|||||||
109
docs/docs.go
109
docs/docs.go
@@ -399,6 +399,82 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/battle-replays/geometry/{geometryId}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get all battle replays associated with a specific geometry",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"BattleReplays"
|
||||||
|
],
|
||||||
|
"summary": "Get battle replays by geometry ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Geometry ID",
|
||||||
|
"name": "geometryId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/battle-replays/{id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific battle replay",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"BattleReplays"
|
||||||
|
],
|
||||||
|
"summary": "Get battle replay by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Battle Replay ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/chatbot/chat": {
|
"/chatbot/chat": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -4241,6 +4317,33 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"history-api_internal_dtos_request.BattleReplaySnapshot": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"geometry_id",
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"detail": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"geometry_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_geometry_ids": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -4329,6 +4432,12 @@ const docTemplate = `{
|
|||||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"replays": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_request.BattleReplaySnapshot"
|
||||||
|
}
|
||||||
|
},
|
||||||
"wikis": {
|
"wikis": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -392,6 +392,82 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/battle-replays/geometry/{geometryId}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get all battle replays associated with a specific geometry",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"BattleReplays"
|
||||||
|
],
|
||||||
|
"summary": "Get battle replays by geometry ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Geometry ID",
|
||||||
|
"name": "geometryId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/battle-replays/{id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific battle replay",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"BattleReplays"
|
||||||
|
],
|
||||||
|
"summary": "Get battle replay by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Battle Replay ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/chatbot/chat": {
|
"/chatbot/chat": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -4234,6 +4310,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"history-api_internal_dtos_request.BattleReplaySnapshot": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"geometry_id",
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"detail": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"geometry_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_geometry_ids": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
"history-api_internal_dtos_request.ChangeOwnerDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -4322,6 +4425,12 @@
|
|||||||
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
"$ref": "#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"replays": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_request.BattleReplaySnapshot"
|
||||||
|
}
|
||||||
|
},
|
||||||
"wikis": {
|
"wikis": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -29,6 +29,24 @@ definitions:
|
|||||||
- min_lat
|
- min_lat
|
||||||
- min_lng
|
- min_lng
|
||||||
type: object
|
type: object
|
||||||
|
history-api_internal_dtos_request.BattleReplaySnapshot:
|
||||||
|
properties:
|
||||||
|
detail:
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
geometry_id:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
target_geometry_ids:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- geometry_id
|
||||||
|
- id
|
||||||
|
type: object
|
||||||
history-api_internal_dtos_request.ChangeOwnerDto:
|
history-api_internal_dtos_request.ChangeOwnerDto:
|
||||||
properties:
|
properties:
|
||||||
new_owner_id:
|
new_owner_id:
|
||||||
@@ -88,6 +106,10 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot'
|
$ref: '#/definitions/history-api_internal_dtos_request.GeometryEntitySnapshot'
|
||||||
type: array
|
type: array
|
||||||
|
replays:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_request.BattleReplaySnapshot'
|
||||||
|
type: array
|
||||||
wikis:
|
wikis:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/history-api_internal_dtos_request.WikiSnapshot'
|
$ref: '#/definitions/history-api_internal_dtos_request.WikiSnapshot'
|
||||||
@@ -947,6 +969,56 @@ paths:
|
|||||||
summary: Verify a security token
|
summary: Verify a security token
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- Auth
|
||||||
|
/battle-replays/{id}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get detailed information about a specific battle replay
|
||||||
|
parameters:
|
||||||
|
- description: Battle Replay ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Get battle replay by ID
|
||||||
|
tags:
|
||||||
|
- BattleReplays
|
||||||
|
/battle-replays/geometry/{geometryId}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get all battle replays associated with a specific geometry
|
||||||
|
parameters:
|
||||||
|
- description: Geometry ID
|
||||||
|
in: path
|
||||||
|
name: geometryId
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Get battle replays by geometry ID
|
||||||
|
tags:
|
||||||
|
- BattleReplays
|
||||||
/chatbot/chat:
|
/chatbot/chat:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|||||||
72
internal/controllers/battleReplayController.go
Normal file
72
internal/controllers/battleReplayController.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"history-api/internal/dtos/response"
|
||||||
|
"history-api/internal/services"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BattleReplayController struct {
|
||||||
|
service services.BattleReplayService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBattleReplayController(svc services.BattleReplayService) *BattleReplayController {
|
||||||
|
return &BattleReplayController{service: svc}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBattleReplayById handles fetching a single battle replay by ID.
|
||||||
|
// @Summary Get battle replay by ID
|
||||||
|
// @Description Get detailed information about a specific battle replay
|
||||||
|
// @Tags BattleReplays
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Battle Replay ID"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 404 {object} response.CommonResponse
|
||||||
|
// @Router /battle-replays/{id} [get]
|
||||||
|
func (h *BattleReplayController) GetBattleReplayById(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
id := c.Params("id")
|
||||||
|
res, err := h.service.GetByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBattleReplaysByGeometryId handles fetching battle replays by geometry ID.
|
||||||
|
// @Summary Get battle replays by geometry ID
|
||||||
|
// @Description Get all battle replays associated with a specific geometry
|
||||||
|
// @Tags BattleReplays
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param geometryId path string true "Geometry ID"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 400 {object} response.CommonResponse
|
||||||
|
// @Router /battle-replays/geometry/{geometryId} [get]
|
||||||
|
func (h *BattleReplayController) GetBattleReplaysByGeometryId(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
geometryID := c.Params("geometryId")
|
||||||
|
res, err := h.service.GetByGeometryID(ctx, geometryID)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -9,6 +9,14 @@ type CommitSnapshot struct {
|
|||||||
Wikis []*WikiSnapshot `json:"wikis,omitempty" validate:"omitempty,dive"`
|
Wikis []*WikiSnapshot `json:"wikis,omitempty" validate:"omitempty,dive"`
|
||||||
GeometryEntity []*GeometryEntitySnapshot `json:"geometry_entity,omitempty" validate:"omitempty,dive"`
|
GeometryEntity []*GeometryEntitySnapshot `json:"geometry_entity,omitempty" validate:"omitempty,dive"`
|
||||||
EntityWiki []*EntityWikiLinkSnapshot `json:"entity_wiki,omitempty" validate:"omitempty,dive"`
|
EntityWiki []*EntityWikiLinkSnapshot `json:"entity_wiki,omitempty" validate:"omitempty,dive"`
|
||||||
|
Replays []*BattleReplaySnapshot `json:"replays,omitempty" validate:"omitempty,dive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BattleReplaySnapshot struct {
|
||||||
|
ID string `json:"id" validate:"required,uuidv7"`
|
||||||
|
GeometryID string `json:"geometry_id" validate:"required,uuidv7"`
|
||||||
|
TargetGeometryIDs []string `json:"target_geometry_ids,omitempty" validate:"omitempty,dive,uuidv7"`
|
||||||
|
Detail json.RawMessage `json:"detail,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FeatureCollection struct {
|
type FeatureCollection struct {
|
||||||
|
|||||||
17
internal/dtos/response/battle_replay.go
Normal file
17
internal/dtos/response/battle_replay.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BattleReplayResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
GeometryID string `json:"geometry_id"`
|
||||||
|
ProjectID string `json:"project_id"`
|
||||||
|
TargetGeometryIDs json.RawMessage `json:"target_geometry_ids,omitempty"`
|
||||||
|
Detail json.RawMessage `json:"detail,omitempty"`
|
||||||
|
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||||
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
|
}
|
||||||
272
internal/gen/sqlc/battle_replay.sql.go
Normal file
272
internal/gen/sqlc/battle_replay.sql.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.30.0
|
||||||
|
// source: battle_replay.sql
|
||||||
|
|
||||||
|
package sqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createBattleReplay = `-- name: CreateBattleReplay :one
|
||||||
|
INSERT INTO battle_replays (
|
||||||
|
id, geometry_id, project_id, target_geometry_ids, detail
|
||||||
|
) VALUES (
|
||||||
|
COALESCE($5::uuid, uuidv7()), $1, $2, $3, $4
|
||||||
|
)
|
||||||
|
RETURNING id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateBattleReplayParams struct {
|
||||||
|
GeometryID pgtype.UUID `json:"geometry_id"`
|
||||||
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
|
TargetGeometryIds json.RawMessage `json:"target_geometry_ids"`
|
||||||
|
Detail json.RawMessage `json:"detail"`
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateBattleReplay(ctx context.Context, arg CreateBattleReplayParams) (BattleReplay, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createBattleReplay,
|
||||||
|
arg.GeometryID,
|
||||||
|
arg.ProjectID,
|
||||||
|
arg.TargetGeometryIds,
|
||||||
|
arg.Detail,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
var i BattleReplay
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteBattleReplay = `-- name: DeleteBattleReplay :exec
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET is_deleted = true
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteBattleReplay(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteBattleReplay, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteBattleReplaysByIDs = `-- name: DeleteBattleReplaysByIDs :exec
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET is_deleted = true
|
||||||
|
WHERE id = ANY($1::uuid[])
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteBattleReplaysByIDs(ctx context.Context, dollar_1 []pgtype.UUID) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteBattleReplaysByIDs, dollar_1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBattleReplayById = `-- name: GetBattleReplayById :one
|
||||||
|
SELECT id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE id = $1 AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBattleReplayById(ctx context.Context, id pgtype.UUID) (BattleReplay, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getBattleReplayById, id)
|
||||||
|
var i BattleReplay
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBattleReplaysByGeometryIDs = `-- name: GetBattleReplaysByGeometryIDs :many
|
||||||
|
SELECT id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE geometry_id = ANY($1::uuid[]) AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBattleReplaysByGeometryIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]BattleReplay, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getBattleReplaysByGeometryIDs, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []BattleReplay{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i BattleReplay
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBattleReplaysByGeometryId = `-- name: GetBattleReplaysByGeometryId :many
|
||||||
|
SELECT id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE geometry_id = $1 AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBattleReplaysByGeometryId(ctx context.Context, geometryID pgtype.UUID) ([]BattleReplay, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getBattleReplaysByGeometryId, geometryID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []BattleReplay{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i BattleReplay
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBattleReplaysByIDs = `-- name: GetBattleReplaysByIDs :many
|
||||||
|
SELECT id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at FROM battle_replays WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBattleReplaysByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]BattleReplay, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getBattleReplaysByIDs, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []BattleReplay{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i BattleReplay
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBattleReplaysByProjectId = `-- name: GetBattleReplaysByProjectId :many
|
||||||
|
SELECT id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
FROM battle_replays
|
||||||
|
WHERE project_id = $1 AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetBattleReplaysByProjectId(ctx context.Context, projectID pgtype.UUID) ([]BattleReplay, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getBattleReplaysByProjectId, projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
items := []BattleReplay{}
|
||||||
|
for rows.Next() {
|
||||||
|
var i BattleReplay
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateBattleReplay = `-- name: UpdateBattleReplay :one
|
||||||
|
UPDATE battle_replays
|
||||||
|
SET
|
||||||
|
geometry_id = COALESCE($1, geometry_id),
|
||||||
|
target_geometry_ids = COALESCE($2, target_geometry_ids),
|
||||||
|
detail = COALESCE($3, detail)
|
||||||
|
WHERE id = $4 AND is_deleted = false
|
||||||
|
RETURNING id, geometry_id, project_id, target_geometry_ids, detail, is_deleted, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateBattleReplayParams struct {
|
||||||
|
GeometryID pgtype.UUID `json:"geometry_id"`
|
||||||
|
TargetGeometryIds []byte `json:"target_geometry_ids"`
|
||||||
|
Detail []byte `json:"detail"`
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateBattleReplay(ctx context.Context, arg UpdateBattleReplayParams) (BattleReplay, error) {
|
||||||
|
row := q.db.QueryRow(ctx, updateBattleReplay,
|
||||||
|
arg.GeometryID,
|
||||||
|
arg.TargetGeometryIds,
|
||||||
|
arg.Detail,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
var i BattleReplay
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GeometryID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.TargetGeometryIds,
|
||||||
|
&i.Detail,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
@@ -11,6 +11,17 @@ import (
|
|||||||
"github.com/pgvector/pgvector-go"
|
"github.com/pgvector/pgvector-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type BattleReplay struct {
|
||||||
|
ID pgtype.UUID `json:"id"`
|
||||||
|
GeometryID pgtype.UUID `json:"geometry_id"`
|
||||||
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
|
TargetGeometryIds json.RawMessage `json:"target_geometry_ids"`
|
||||||
|
Detail json.RawMessage `json:"detail"`
|
||||||
|
IsDeleted bool `json:"is_deleted"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type ChatbotHistory struct {
|
type ChatbotHistory struct {
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
UserID pgtype.UUID `json:"user_id"`
|
UserID pgtype.UUID `json:"user_id"`
|
||||||
|
|||||||
48
internal/models/battle_replay.go
Normal file
48
internal/models/battle_replay.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"history-api/internal/dtos/response"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BattleReplayEntity struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
GeometryID string `json:"geometry_id"`
|
||||||
|
ProjectID string `json:"project_id"`
|
||||||
|
TargetGeometryIDs json.RawMessage `json:"target_geometry_ids"`
|
||||||
|
Detail json.RawMessage `json:"detail"`
|
||||||
|
IsDeleted bool `json:"is_deleted"`
|
||||||
|
CreatedAt *time.Time `json:"created_at"`
|
||||||
|
UpdatedAt *time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BattleReplayEntity) ToResponse() *response.BattleReplayResponse {
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &response.BattleReplayResponse{
|
||||||
|
ID: b.ID,
|
||||||
|
GeometryID: b.GeometryID,
|
||||||
|
ProjectID: b.ProjectID,
|
||||||
|
TargetGeometryIDs: b.TargetGeometryIDs,
|
||||||
|
Detail: b.Detail,
|
||||||
|
IsDeleted: b.IsDeleted,
|
||||||
|
CreatedAt: b.CreatedAt,
|
||||||
|
UpdatedAt: b.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BattleReplaysEntityToResponse(bs []*BattleReplayEntity) []*response.BattleReplayResponse {
|
||||||
|
out := make([]*response.BattleReplayResponse, 0)
|
||||||
|
if bs == nil {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
for _, b := range bs {
|
||||||
|
if b == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, b.ToResponse())
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
290
internal/repositories/battleReplayRepository.go
Normal file
290
internal/repositories/battleReplayRepository.go
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
|
||||||
|
"history-api/internal/gen/sqlc"
|
||||||
|
"history-api/internal/models"
|
||||||
|
"history-api/pkg/cache"
|
||||||
|
"history-api/pkg/constants"
|
||||||
|
"history-api/pkg/convert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BattleReplayRepository interface {
|
||||||
|
GetByID(ctx context.Context, id pgtype.UUID) (*models.BattleReplayEntity, error)
|
||||||
|
GetByIDs(ctx context.Context, ids []string) ([]*models.BattleReplayEntity, error)
|
||||||
|
GetByGeometryID(ctx context.Context, geometryID pgtype.UUID) ([]*models.BattleReplayEntity, error)
|
||||||
|
GetByGeometryIDs(ctx context.Context, geometryIDs []string) ([]*models.BattleReplayEntity, error)
|
||||||
|
Create(ctx context.Context, params sqlc.CreateBattleReplayParams) (*models.BattleReplayEntity, error)
|
||||||
|
Update(ctx context.Context, params sqlc.UpdateBattleReplayParams) (*models.BattleReplayEntity, error)
|
||||||
|
Delete(ctx context.Context, id pgtype.UUID) error
|
||||||
|
DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error
|
||||||
|
GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.BattleReplayEntity, error)
|
||||||
|
WithTx(tx pgx.Tx) BattleReplayRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
type battleReplayRepository struct {
|
||||||
|
q *sqlc.Queries
|
||||||
|
c cache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBattleReplayRepository(db sqlc.DBTX, c cache.Cache) BattleReplayRepository {
|
||||||
|
return &battleReplayRepository{
|
||||||
|
q: sqlc.New(db),
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) WithTx(tx pgx.Tx) BattleReplayRepository {
|
||||||
|
return &battleReplayRepository{
|
||||||
|
q: r.q.WithTx(tx),
|
||||||
|
c: r.c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) rowToEntity(row sqlc.BattleReplay) *models.BattleReplayEntity {
|
||||||
|
return &models.BattleReplayEntity{
|
||||||
|
ID: convert.UUIDToString(row.ID),
|
||||||
|
GeometryID: convert.UUIDToString(row.GeometryID),
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
|
TargetGeometryIDs: row.TargetGeometryIds,
|
||||||
|
Detail: row.Detail,
|
||||||
|
IsDeleted: row.IsDeleted,
|
||||||
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) getByIDsWithFallback(ctx context.Context, ids []string) ([]*models.BattleReplayEntity, error) {
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return []*models.BattleReplayEntity{}, nil
|
||||||
|
}
|
||||||
|
keys := make([]string, len(ids))
|
||||||
|
for i, id := range ids {
|
||||||
|
keys[i] = fmt.Sprintf("battle_replay:id:%s", id)
|
||||||
|
}
|
||||||
|
raws := r.c.MGet(ctx, keys...)
|
||||||
|
|
||||||
|
var items []*models.BattleReplayEntity
|
||||||
|
missingToCache := make(map[string]any)
|
||||||
|
|
||||||
|
var missingPgIds []pgtype.UUID
|
||||||
|
for i, b := range raws {
|
||||||
|
if len(b) == 0 {
|
||||||
|
pgId := pgtype.UUID{}
|
||||||
|
err := pgId.Scan(ids[i])
|
||||||
|
if err == nil {
|
||||||
|
missingPgIds = append(missingPgIds, pgId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbMap := make(map[string]*models.BattleReplayEntity)
|
||||||
|
if len(missingPgIds) > 0 {
|
||||||
|
dbRows, err := r.q.GetBattleReplaysByIDs(ctx, missingPgIds)
|
||||||
|
if err == nil {
|
||||||
|
for _, row := range dbRows {
|
||||||
|
item := r.rowToEntity(row)
|
||||||
|
dbMap[item.ID] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, b := range raws {
|
||||||
|
if len(b) > 0 {
|
||||||
|
var u models.BattleReplayEntity
|
||||||
|
if err := json.Unmarshal(b, &u); err == nil {
|
||||||
|
items = append(items, &u)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if item, ok := dbMap[ids[i]]; ok {
|
||||||
|
items = append(items, item)
|
||||||
|
missingToCache[keys[i]] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missingToCache) > 0 {
|
||||||
|
_ = r.c.MSet(ctx, missingToCache, constants.NormalCacheDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) GetByIDs(ctx context.Context, ids []string) ([]*models.BattleReplayEntity, error) {
|
||||||
|
return r.getByIDsWithFallback(ctx, ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models.BattleReplayEntity, error) {
|
||||||
|
cacheId := fmt.Sprintf("battle_replay:id:%s", convert.UUIDToString(id))
|
||||||
|
var item models.BattleReplayEntity
|
||||||
|
err := r.c.Get(ctx, cacheId, &item)
|
||||||
|
if err == nil {
|
||||||
|
_ = r.c.Set(ctx, cacheId, item, constants.NormalCacheDuration)
|
||||||
|
return &item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
row, err := r.q.GetBattleReplayById(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entity := r.rowToEntity(row)
|
||||||
|
_ = r.c.Set(ctx, cacheId, entity, constants.NormalCacheDuration)
|
||||||
|
|
||||||
|
return entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) GetByGeometryID(ctx context.Context, geometryID pgtype.UUID) ([]*models.BattleReplayEntity, error) {
|
||||||
|
cacheKey := fmt.Sprintf("battle_replay:geometry:%s", convert.UUIDToString(geometryID))
|
||||||
|
var cachedIDs []string
|
||||||
|
if err := r.c.Get(ctx, cacheKey, &cachedIDs); err == nil && len(cachedIDs) > 0 {
|
||||||
|
return r.getByIDsWithFallback(ctx, cachedIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.q.GetBattleReplaysByGeometryId(ctx, geometryID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []*models.BattleReplayEntity
|
||||||
|
var ids []string
|
||||||
|
itemToCache := make(map[string]any)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
item := r.rowToEntity(row)
|
||||||
|
ids = append(ids, item.ID)
|
||||||
|
items = append(items, item)
|
||||||
|
itemToCache[fmt.Sprintf("battle_replay:id:%s", item.ID)] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(itemToCache) > 0 {
|
||||||
|
_ = r.c.MSet(ctx, itemToCache, constants.NormalCacheDuration)
|
||||||
|
}
|
||||||
|
if len(ids) > 0 {
|
||||||
|
_ = r.c.Set(ctx, cacheKey, ids, constants.ListCacheDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) GetByGeometryIDs(ctx context.Context, geometryIDs []string) ([]*models.BattleReplayEntity, error) {
|
||||||
|
if len(geometryIDs) == 0 {
|
||||||
|
return []*models.BattleReplayEntity{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pgIds []pgtype.UUID
|
||||||
|
for _, id := range geometryIDs {
|
||||||
|
pgId := pgtype.UUID{}
|
||||||
|
if err := pgId.Scan(id); err == nil {
|
||||||
|
pgIds = append(pgIds, pgId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.q.GetBattleReplaysByGeometryIDs(ctx, pgIds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []*models.BattleReplayEntity
|
||||||
|
itemToCache := make(map[string]any)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
item := r.rowToEntity(row)
|
||||||
|
items = append(items, item)
|
||||||
|
itemToCache[fmt.Sprintf("battle_replay:id:%s", item.ID)] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(itemToCache) > 0 {
|
||||||
|
_ = r.c.MSet(ctx, itemToCache, constants.NormalCacheDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) GetByProjectID(ctx context.Context, projectID pgtype.UUID) ([]*models.BattleReplayEntity, error) {
|
||||||
|
cacheKey := fmt.Sprintf("battle_replay:project:%s", convert.UUIDToString(projectID))
|
||||||
|
var cachedIDs []string
|
||||||
|
if err := r.c.Get(ctx, cacheKey, &cachedIDs); err == nil && len(cachedIDs) > 0 {
|
||||||
|
return r.getByIDsWithFallback(ctx, cachedIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := r.q.GetBattleReplaysByProjectId(ctx, projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []*models.BattleReplayEntity
|
||||||
|
var ids []string
|
||||||
|
itemToCache := make(map[string]any)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
item := r.rowToEntity(row)
|
||||||
|
ids = append(ids, item.ID)
|
||||||
|
items = append(items, item)
|
||||||
|
itemToCache[fmt.Sprintf("battle_replay:id:%s", item.ID)] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(itemToCache) > 0 {
|
||||||
|
_ = r.c.MSet(ctx, itemToCache, constants.NormalCacheDuration)
|
||||||
|
}
|
||||||
|
if len(ids) > 0 {
|
||||||
|
_ = r.c.Set(ctx, cacheKey, ids, constants.ListCacheDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) Create(ctx context.Context, params sqlc.CreateBattleReplayParams) (*models.BattleReplayEntity, error) {
|
||||||
|
row, err := r.q.CreateBattleReplay(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entity := r.rowToEntity(row)
|
||||||
|
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("battle_replay:project:%s", entity.ProjectID))
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("battle_replay:geometry:%s", entity.GeometryID))
|
||||||
|
|
||||||
|
return entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) Update(ctx context.Context, params sqlc.UpdateBattleReplayParams) (*models.BattleReplayEntity, error) {
|
||||||
|
row, err := r.q.UpdateBattleReplay(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entity := r.rowToEntity(row)
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("battle_replay:id:%s", entity.ID))
|
||||||
|
return entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) Delete(ctx context.Context, id pgtype.UUID) error {
|
||||||
|
err := r.q.DeleteBattleReplay(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("battle_replay:id:%s", convert.UUIDToString(id)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *battleReplayRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) error {
|
||||||
|
err := r.q.DeleteBattleReplaysByIDs(ctx, ids)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(ids) > 0 {
|
||||||
|
keys := make([]string, len(ids))
|
||||||
|
for i, id := range ids {
|
||||||
|
keys[i] = fmt.Sprintf("battle_replay:id:%s", convert.UUIDToString(id))
|
||||||
|
}
|
||||||
|
_ = r.c.Del(ctx, keys...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
13
internal/routes/battleReplayRoute.go
Normal file
13
internal/routes/battleReplayRoute.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"history-api/internal/controllers"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BattleReplayRoutes(router fiber.Router, battleReplayController *controllers.BattleReplayController) {
|
||||||
|
br := router.Group("/battle-replays")
|
||||||
|
br.Get("/geometry/:geometryId", battleReplayController.GetBattleReplaysByGeometryId)
|
||||||
|
br.Get("/:id", battleReplayController.GetBattleReplayById)
|
||||||
|
}
|
||||||
54
internal/services/battleReplayService.go
Normal file
54
internal/services/battleReplayService.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"history-api/internal/dtos/response"
|
||||||
|
"history-api/internal/models"
|
||||||
|
"history-api/internal/repositories"
|
||||||
|
"history-api/pkg/convert"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BattleReplayService interface {
|
||||||
|
GetByID(ctx context.Context, id string) (*response.BattleReplayResponse, *fiber.Error)
|
||||||
|
GetByGeometryID(ctx context.Context, geometryID string) ([]*response.BattleReplayResponse, *fiber.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type battleReplayService struct {
|
||||||
|
battleReplayRepo repositories.BattleReplayRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBattleReplayService(battleReplayRepo repositories.BattleReplayRepository) BattleReplayService {
|
||||||
|
return &battleReplayService{
|
||||||
|
battleReplayRepo: battleReplayRepo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *battleReplayService) GetByID(ctx context.Context, id string) (*response.BattleReplayResponse, *fiber.Error) {
|
||||||
|
replayUUID, err := convert.StringToUUID(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid battle replay ID format")
|
||||||
|
}
|
||||||
|
|
||||||
|
replay, err := s.battleReplayRepo.GetByID(ctx, replayUUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Battle replay not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return replay.ToResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *battleReplayService) GetByGeometryID(ctx context.Context, geometryID string) ([]*response.BattleReplayResponse, *fiber.Error) {
|
||||||
|
geomUUID, err := convert.StringToUUID(geometryID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid geometry ID format")
|
||||||
|
}
|
||||||
|
|
||||||
|
replays, err := s.battleReplayRepo.GetByGeometryID(ctx, geomUUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get battle replays")
|
||||||
|
}
|
||||||
|
|
||||||
|
return models.BattleReplaysEntityToResponse(replays), nil
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ type submissionService struct {
|
|||||||
wikiRepo repositories.WikiRepository
|
wikiRepo repositories.WikiRepository
|
||||||
geometryRepo repositories.GeometryRepository
|
geometryRepo repositories.GeometryRepository
|
||||||
entityRepo repositories.EntityRepository
|
entityRepo repositories.EntityRepository
|
||||||
|
battleReplayRepo repositories.BattleReplayRepository
|
||||||
ragRepo repositories.RagRepository
|
ragRepo repositories.RagRepository
|
||||||
ragUtils *ai.RagUtils
|
ragUtils *ai.RagUtils
|
||||||
db *pgxpool.Pool
|
db *pgxpool.Pool
|
||||||
@@ -53,6 +54,7 @@ func NewSubmissionService(
|
|||||||
wikiRepo repositories.WikiRepository,
|
wikiRepo repositories.WikiRepository,
|
||||||
geometryRepo repositories.GeometryRepository,
|
geometryRepo repositories.GeometryRepository,
|
||||||
entityRepo repositories.EntityRepository,
|
entityRepo repositories.EntityRepository,
|
||||||
|
battleReplayRepo repositories.BattleReplayRepository,
|
||||||
ragRepo repositories.RagRepository,
|
ragRepo repositories.RagRepository,
|
||||||
ragUtils *ai.RagUtils,
|
ragUtils *ai.RagUtils,
|
||||||
db *pgxpool.Pool,
|
db *pgxpool.Pool,
|
||||||
@@ -66,6 +68,7 @@ func NewSubmissionService(
|
|||||||
wikiRepo: wikiRepo,
|
wikiRepo: wikiRepo,
|
||||||
geometryRepo: geometryRepo,
|
geometryRepo: geometryRepo,
|
||||||
entityRepo: entityRepo,
|
entityRepo: entityRepo,
|
||||||
|
battleReplayRepo: battleReplayRepo,
|
||||||
ragRepo: ragRepo,
|
ragRepo: ragRepo,
|
||||||
ragUtils: ragUtils,
|
ragUtils: ragUtils,
|
||||||
db: db,
|
db: db,
|
||||||
@@ -187,6 +190,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
entityRepo := s.entityRepo.WithTx(tx)
|
entityRepo := s.entityRepo.WithTx(tx)
|
||||||
geometryRepo := s.geometryRepo.WithTx(tx)
|
geometryRepo := s.geometryRepo.WithTx(tx)
|
||||||
wikiRepo := s.wikiRepo.WithTx(tx)
|
wikiRepo := s.wikiRepo.WithTx(tx)
|
||||||
|
battleReplayRepo := s.battleReplayRepo.WithTx(tx)
|
||||||
|
|
||||||
submissionUUID, err := convert.StringToUUID(submissionID)
|
submissionUUID, err := convert.StringToUUID(submissionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -229,6 +233,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
listDeleteEntities := make([]pgtype.UUID, 0)
|
listDeleteEntities := make([]pgtype.UUID, 0)
|
||||||
listDeleteWikis := make([]pgtype.UUID, 0)
|
listDeleteWikis := make([]pgtype.UUID, 0)
|
||||||
listDeleteGeometries := make([]pgtype.UUID, 0)
|
listDeleteGeometries := make([]pgtype.UUID, 0)
|
||||||
|
listDeleteBattleReplays := make([]pgtype.UUID, 0)
|
||||||
var snapshotData request.CommitSnapshot
|
var snapshotData request.CommitSnapshot
|
||||||
err = json.Unmarshal(commit.SnapshotJson, &snapshotData)
|
err = json.Unmarshal(commit.SnapshotJson, &snapshotData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -242,17 +247,22 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
}
|
}
|
||||||
currentEntity, err := s.entityRepo.GetByProjectID(ctx, projectUUID)
|
currentEntity, err := s.entityRepo.GetByProjectID(ctx, projectUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Entity not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Entity not found: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
currentGeometry, err := s.geometryRepo.GetByProjectID(ctx, projectUUID)
|
currentGeometry, err := s.geometryRepo.GetByProjectID(ctx, projectUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Geometry not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Geometry not found: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWiki, err := s.wikiRepo.GetByProjectID(ctx, projectUUID)
|
currentWiki, err := s.wikiRepo.GetByProjectID(ctx, projectUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Wiki not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Wiki not found: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBattleReplay, err := s.battleReplayRepo.GetByProjectID(ctx, projectUUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Battle replay not found: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
persistItemIDs := make(map[string]struct{})
|
persistItemIDs := make(map[string]struct{})
|
||||||
@@ -265,6 +275,9 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
for _, item := range snapshotData.Wikis {
|
for _, item := range snapshotData.Wikis {
|
||||||
persistItemIDs[item.ID] = struct{}{}
|
persistItemIDs[item.ID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
for _, item := range snapshotData.Replays {
|
||||||
|
persistItemIDs[item.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
persistCurrentItemIDs := make(map[string]struct{})
|
persistCurrentItemIDs := make(map[string]struct{})
|
||||||
for _, item := range currentEntity {
|
for _, item := range currentEntity {
|
||||||
@@ -276,6 +289,9 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
for _, item := range currentWiki {
|
for _, item := range currentWiki {
|
||||||
persistCurrentItemIDs[item.ID] = struct{}{}
|
persistCurrentItemIDs[item.ID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
for _, item := range currentBattleReplay {
|
||||||
|
persistCurrentItemIDs[item.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
for _, e := range currentEntity {
|
for _, e := range currentEntity {
|
||||||
if _, ok := persistItemIDs[e.ID]; !ok {
|
if _, ok := persistItemIDs[e.ID]; !ok {
|
||||||
@@ -310,6 +326,17 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, br := range currentBattleReplay {
|
||||||
|
if _, ok := persistItemIDs[br.ID]; !ok {
|
||||||
|
itemUUID, err := convert.StringToUUID(br.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid battle replay ID")
|
||||||
|
}
|
||||||
|
listDeleteBattleReplays = append(listDeleteBattleReplays, itemUUID)
|
||||||
|
delete(persistCurrentItemIDs, br.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(listDeleteEntities) > 0 {
|
if len(listDeleteEntities) > 0 {
|
||||||
if err = entityRepo.DeleteByIDs(ctx, listDeleteEntities); err != nil {
|
if err = entityRepo.DeleteByIDs(ctx, listDeleteEntities); err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete entities")
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete entities")
|
||||||
@@ -328,6 +355,12 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(listDeleteBattleReplays) > 0 {
|
||||||
|
if err = battleReplayRepo.DeleteByIDs(ctx, listDeleteBattleReplays); err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete battle replays")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
refEntityIDs := []string{}
|
refEntityIDs := []string{}
|
||||||
for _, e := range snapshotData.Entities {
|
for _, e := range snapshotData.Entities {
|
||||||
if e.Source == "ref" {
|
if e.Source == "ref" {
|
||||||
@@ -570,6 +603,46 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
}
|
}
|
||||||
snapshotData.Wikis = newWikis
|
snapshotData.Wikis = newWikis
|
||||||
|
|
||||||
|
for _, replay := range snapshotData.Replays {
|
||||||
|
replayUUID, err := convert.StringToUUID(replay.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid battle replay ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
geomUUID, err := convert.StringToUUID(replay.GeometryID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Invalid geometry ID in battle replay")
|
||||||
|
}
|
||||||
|
|
||||||
|
targetIDs, err := json.Marshal(replay.TargetGeometryIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to marshal target geometry IDs")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := persistCurrentItemIDs[replay.ID]; ok {
|
||||||
|
_, err := battleReplayRepo.Update(ctx, sqlc.UpdateBattleReplayParams{
|
||||||
|
ID: replayUUID,
|
||||||
|
GeometryID: geomUUID,
|
||||||
|
TargetGeometryIds: targetIDs,
|
||||||
|
Detail: replay.Detail,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update battle replay: "+err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := battleReplayRepo.Create(ctx, sqlc.CreateBattleReplayParams{
|
||||||
|
ID: replayUUID,
|
||||||
|
GeometryID: geomUUID,
|
||||||
|
ProjectID: projectUUID,
|
||||||
|
TargetGeometryIds: targetIDs,
|
||||||
|
Detail: replay.Detail,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create battle replay: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = geometryRepo.DeleteEntityGeometriesByProjectID(ctx, projectUUID)
|
err = geometryRepo.DeleteEntityGeometriesByProjectID(ctx, projectUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete geometry entity: "+err.Error())
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to delete geometry entity: "+err.Error())
|
||||||
|
|||||||
Reference in New Issue
Block a user