From 5c0fb849b9ad2a8ff8ef25ec35f68bc368e04aba Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 14 Oct 2024 22:17:07 +0900 Subject: [PATCH 1/5] wip: implement, integration test fails --- .tbls.yml | 28 +- docs/swagger/traPortfolio.v1.yaml | 121 ++++--- integration_tests/handler/contest_test.go | 114 +++--- integration_tests/handler/project_test.go | 30 +- internal/domain/contest.go | 4 +- internal/domain/group.go | 2 +- internal/domain/project.go | 2 +- internal/handler/contest.go | 22 +- internal/handler/contest_test.go | 76 ++-- internal/handler/group.go | 6 +- internal/handler/group_test.go | 4 +- internal/handler/project.go | 10 +- internal/handler/project_test.go | 17 +- internal/handler/schema/schema_gen.go | 54 +-- internal/handler/schema/validator.go | 30 +- internal/handler/testutil_test.go | 27 +- internal/infrastructure/migration/current.go | 5 + internal/infrastructure/migration/v3.go | 221 ++++++++++++ .../infrastructure/repository/contest_impl.go | 338 +++++++++++++++--- .../infrastructure/repository/contest_test.go | 4 +- .../infrastructure/repository/group_impl.go | 21 +- .../infrastructure/repository/main_test.go | 6 +- .../repository/model/contests.go | 24 +- .../infrastructure/repository/model/groups.go | 11 +- .../repository/model/project.go | 11 +- .../infrastructure/repository/project_impl.go | 156 +++++++- .../infrastructure/repository/project_test.go | 2 +- internal/pkgs/mockdata/handler.go | 84 ++++- internal/pkgs/mockdata/model.go | 120 ++++++- internal/pkgs/random/random.go | 9 + internal/pkgs/random/repository.go | 16 +- .../usecases/repository/contest_repository.go | 8 +- .../mock_project_repository.go | 28 +- .../usecases/repository/project_repository.go | 4 +- 34 files changed, 1282 insertions(+), 333 deletions(-) create mode 100644 internal/infrastructure/migration/v3.go diff --git a/.tbls.yml b/.tbls.yml index 2aa934f5..feab8703 100644 --- a/.tbls.yml +++ b/.tbls.yml @@ -36,11 +36,16 @@ comments: id: コンテストUUID name: コンテスト名 description: コンテスト説明 - link: コンテスト情報のリンク since: 期間始まり until: 期間終わり created_at: コンテスト作成日時 updated_at: コンテスト更新日時 + - table: contest_links + tableComment: コンテストのリンク関係テーブル + columnComments: + contest_id: コンテストUUID + order: 表示順のインデックス + link: コンテスト情報のリンク - table: contest_teams tableComment: コンテスト参加チームテーブル columnComments: @@ -49,7 +54,6 @@ comments: name: チーム名 description: チーム情報 result: 順位などの結果 - link: コンテストチームの詳細が載っているページへのリンク created_at: コンテストチーム作成日時 updated_at: コンテストチーム更新日時 - table: contest_team_user_belongings @@ -59,6 +63,12 @@ comments: user_id: ユーザーUUID created_at: 関係テーブル作成日時 updated_at: 関係テーブル更新日時 + - table: contest_team_links + tableComment: コンテストチームのリンク関係テーブル + columnComments: + team_id: コンテストチームUUID + order: 表示順のインデックス + link: コンテストチームの詳細が載っているページへのリンク - table: migrations tableComment: gormigrate用のデータベースバージョンテーブル - table: accounts @@ -76,7 +86,6 @@ comments: id: プロジェクトUUID name: プロジェクト名 description: プロジェクト説明 - link: プロジェクト情報のリンク since_year: プロジェクト開始年 since_semester: プロジェクト開始学期(0:前期 1:後期) until_year: プロジェクト終了年 @@ -98,6 +107,12 @@ comments: since_semester: プロジェクト所属開始学期(0:前期 1:後期) until_year: プロジェクト所属終了年 until_semester: プロジェクト所属終了学期(0:前期 1:後期) + - table: project_links + tableComment: プロジェクトのリンク関係テーブル + columnComments: + project_id: プロジェクトUUID + order: 表示順のインデックス + link: プロジェクト情報のリンク # - table: achievements_members # tableComments: 実績メンバーテーブル # columnComments: @@ -108,7 +123,6 @@ comments: columnComments: group_id: グループUUID name: グループ名 - link: グループのリンク description: グループの説明文 created_at: グループ作成日時 updated_at: グループ更新日時 @@ -130,3 +144,9 @@ comments: group_id: グループUUID created_at: 関係テーブル作成日時 updated_at: 関係テーブル更新日時 + - table: group_links + tableComment: グループのリンク関係テーブル + columnComments: + group_id: グループUUID + order: 表示順のインデックス + link: グループのリンク diff --git a/docs/swagger/traPortfolio.v1.yaml b/docs/swagger/traPortfolio.v1.yaml index d8457692..8ab5120b 100644 --- a/docs/swagger/traPortfolio.v1.yaml +++ b/docs/swagger/traPortfolio.v1.yaml @@ -924,10 +924,11 @@ components: - $ref: "#/components/schemas/Project" - type: object properties: - link: - type: string - format: uri - description: プロジェクトの詳細が載っているページへのリンク + links: + type: array + description: プロジェクトのリンク集 + items: + $ref: "#/components/schemas/ProjectLink" description: type: string description: プロジェクト説明 @@ -937,7 +938,7 @@ components: items: $ref: "#/components/schemas/ProjectMember" required: - - link + - links - description - members ProjectMember: @@ -952,6 +953,11 @@ components: $ref: "#/components/schemas/YearWithSemesterDuration" required: - duration + ProjectLink: + title: ProjectLink + type: string + format: uri + description: プロジェクトの詳細が載っているページへのリンク Event: type: object description: イベント情報 @@ -1056,10 +1062,11 @@ components: - $ref: "#/components/schemas/Group" - type: object properties: - link: - type: string - format: uri - description: 班の詳細が載っているページへのリンク + links: + type: array + description: 班のリンク集 + items: + $ref: "#/components/schemas/GroupLink" admin: type: array description: 班管理者 @@ -1074,7 +1081,7 @@ components: type: string description: 班説明 required: - - link + - links - admin - members - description @@ -1090,6 +1097,11 @@ components: $ref: "#/components/schemas/YearWithSemesterDuration" required: - duration + GroupLink: + title: GroupLink + type: string + format: uri + description: 班の詳細が載っているページへのリンク Contest: title: Contest type: object @@ -1133,10 +1145,11 @@ components: - $ref: "#/components/schemas/Contest" - type: object properties: - link: - type: string - format: uri - description: コンテストの詳細が載っているページへのリンク + links: + type: array + description: コンテストのリンク集 + items: + $ref: "#/components/schemas/ContestLink" description: type: string description: コンテストの説明 @@ -1146,9 +1159,14 @@ components: items: $ref: "#/components/schemas/ContestTeam" required: - - link + - links - description - teams + ContestLink: + title: ContestLink + type: string + format: uri + description: コンテストの詳細が載っているページへのリンク ContestTeamWithoutMembers: title: ContestTeamWithoutMembers type: object @@ -1192,10 +1210,11 @@ components: - $ref: "#/components/schemas/ContestTeam" - type: object properties: - link: - type: string - format: uri - description: コンテストチームの詳細が載っているページへのリンク + links: + type: array + description: コンテストチームのリンク集 + items: + $ref: "#/components/schemas/ContestTeamLink" description: type: string description: チーム情報 @@ -1205,8 +1224,13 @@ components: items: $ref: "#/components/schemas/User" required: - - link + - links - description + ContestTeamLink: + title: ContestTeamLink + type: string + format: uri + description: コンテストチームの詳細が載っているページへのリンク PrPermitted: title: PrPermitted type: boolean @@ -1353,10 +1377,11 @@ components: minLength: 1 maxLength: 30 description: プロジェクト名 - link: - type: string - format: uri - description: プロジェクトの詳細が載っているページへのリンク + links: + type: array + description: プロジェクトのリンク集 + items: + $ref: "#/components/schemas/ProjectLink" description: type: string description: プロジェクト説明 @@ -1364,6 +1389,7 @@ components: $ref: "#/components/schemas/YearWithSemesterDuration" required: - name + - links - description - duration EditProjectRequest: @@ -1376,10 +1402,11 @@ components: minLength: 1 maxLength: 30 description: プロジェクト名 - link: - type: string - format: uri - description: プロジェクトの詳細が載っているページへのリンク + links: + type: array + description: プロジェクトのリンク集 + items: + $ref: "#/components/schemas/ProjectLink" description: type: string description: プロジェクト説明 @@ -1404,10 +1431,11 @@ components: name: type: string description: コンテスト名 - link: - type: string - format: uri - description: コンテストの詳細が載っているページへのリンク + links: + type: array + description: コンテストのリンク集 + items: + $ref: "#/components/schemas/ContestLink" description: type: string description: コンテスト説明 @@ -1416,6 +1444,7 @@ components: $ref: "#/components/schemas/Duration" required: - name + - links - description - duration EditContestRequest: @@ -1426,10 +1455,11 @@ components: name: type: string description: コンテスト名 - link: - type: string - format: uri - description: コンテストの詳細が載っているページへのリンク + links: + type: array + description: コンテストのリンク集 + items: + $ref: "#/components/schemas/ContestLink" description: type: string description: コンテスト説明 @@ -1444,10 +1474,11 @@ components: name: type: string description: チーム名 - link: - type: string - format: uri - description: コンテストチームの説明が載っているページへのリンク + links: + type: array + description: コンテストチームのリンク集 + items: + $ref: "#/components/schemas/ContestTeamLink" description: type: string description: チーム情報 @@ -1456,6 +1487,7 @@ components: description: 順位などの結果 required: - name + - links - description EditContestTeamRequest: title: EditContestTeamRequest @@ -1465,10 +1497,11 @@ components: name: type: string description: チーム名 - link: - type: string - format: uri - description: コンテストチームの説明が載っているページへのリンク + links: + type: array + description: コンテストチームのリンク集 + items: + $ref: "#/components/schemas/ContestTeamLink" description: type: string description: チーム情報 diff --git a/integration_tests/handler/contest_test.go b/integration_tests/handler/contest_test.go index fb3a134c..6b615f2e 100644 --- a/integration_tests/handler/contest_test.go +++ b/integration_tests/handler/contest_test.go @@ -79,7 +79,7 @@ func TestGetContest(t *testing.T) { func TestCreateContest(t *testing.T) { var ( name = random.AlphaNumeric() - link = random.RandURLString() + links = random.Array(random.RandURLString, 1, 3) description = random.AlphaNumeric() since, until = random.SinceAndUntil() tooLongString = strings.Repeat("a", 260) @@ -87,7 +87,7 @@ func TestCreateContest(t *testing.T) { justCountName = strings.Repeat("亜", 32) tooLongName = strings.Repeat("亜", 33) tooLongDescriptionKanji = strings.Repeat("亜", 257) - invalidURL = "invalid url" + invalidURL = []string{"invalid url"} ) t.Parallel() @@ -104,8 +104,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: name, + Links: links, + Name: name, }, schema.ContestDetail{ Description: description, @@ -114,7 +114,7 @@ func TestCreateContest(t *testing.T) { Until: &until, }, Id: uuid.Nil, - Link: link, + Links: links, Name: name, Teams: []schema.ContestTeam{}, }, @@ -127,8 +127,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: justCountName, + Links: links, + Name: justCountName, }, schema.ContestDetail{ Description: justCountDescription, @@ -137,7 +137,7 @@ func TestCreateContest(t *testing.T) { Until: &until, }, Id: uuid.Nil, - Link: link, + Links: links, Name: justCountName, Teams: []schema.ContestTeam{}, }, @@ -150,8 +150,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: name, + Links: links, + Name: name, }, httpError(t, "Bad Request: validate error: description: the length must be between 1 and 256."), }, @@ -163,8 +163,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: name, + Links: links, + Name: name, }, httpError(t, "Bad Request: validate error: description: the length must be between 1 and 256."), }, @@ -176,10 +176,10 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &invalidURL, - Name: name, + Links: invalidURL, + Name: name, }, - httpError(t, "Bad Request: validate error: link: must be a valid URL."), + httpError(t, "Bad Request: validate error: links: (0: must be a valid URL.)."), }, "400 invalid Name": { http.StatusBadRequest, @@ -189,8 +189,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: tooLongString, + Links: links, + Name: tooLongString, }, httpError(t, "Bad Request: validate error: name: the length must be between 1 and 32."), }, @@ -202,8 +202,8 @@ func TestCreateContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: tooLongName, + Links: links, + Name: tooLongName, }, httpError(t, "Bad Request: validate error: name: the length must be between 1 and 32."), }, @@ -215,8 +215,8 @@ func TestCreateContest(t *testing.T) { Since: until, Until: &since, }, - Link: &link, - Name: name, + Links: links, + Name: name, }, httpError(t, "Bad Request: validate error: duration: must be a valid date."), }, @@ -243,14 +243,14 @@ func TestEditContest(t *testing.T) { var ( description = random.AlphaNumeric() since, until = random.SinceAndUntil() - link = random.RandURLString() + links = random.Array(random.RandURLString, 1, 3) name = random.AlphaNumeric() tooLongString = strings.Repeat("a", 260) justCountDescription = strings.Repeat("亜", 256) justCountName = strings.Repeat("亜", 32) tooLongName = strings.Repeat("亜", 33) tooLongDescriptionKanji = strings.Repeat("亜", 257) - invalidURL = "invalid url" + invalidURL = []string{"invalid url"} ) t.Parallel() @@ -269,8 +269,8 @@ func TestEditContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: &name, + Links: &links, + Name: &name, }, nil, }, @@ -283,8 +283,8 @@ func TestEditContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: &justCountName, + Links: &links, + Name: &justCountName, }, nil, }, @@ -320,9 +320,9 @@ func TestEditContest(t *testing.T) { http.StatusBadRequest, mockdata.ContestID1(), schema.EditContestRequest{ - Link: &invalidURL, + Links: &invalidURL, }, - httpError(t, "Bad Request: validate error: link: must be a valid URL."), + httpError(t, "Bad Request: validate error: 0: must be a valid URL."), }, "400 invalid Name": { http.StatusBadRequest, @@ -360,8 +360,8 @@ func TestEditContest(t *testing.T) { Since: since, Until: &until, }, - Link: &link, - Name: &name, + Links: &links, + Name: &name, }, httpError(t, "Not Found: not found"), }, @@ -390,12 +390,13 @@ func TestEditContest(t *testing.T) { if tt.reqBody.Duration != nil { contest.Duration = *tt.reqBody.Duration } - if tt.reqBody.Link != nil { - contest.Link = *tt.reqBody.Link - } if tt.reqBody.Name != nil { contest.Name = *tt.reqBody.Name } + if tt.reqBody.Links != nil { + contest.Links = *tt.reqBody.Links + } + res = doRequest(t, e, http.MethodGet, e.URL(api.Contest.GetContest, tt.contestID), nil) assertResponse(t, http.StatusOK, contest, res) } else { @@ -482,7 +483,7 @@ func TestGetContestTeams(t *testing.T) { func TestAddContestTeam(t *testing.T) { var ( description = random.AlphaNumeric() - link = random.RandURLString() + links = random.Array(random.RandURLString, 1, 3) name = random.AlphaNumeric() result = random.AlphaNumeric() tooLongString = strings.Repeat("a", 260) @@ -492,7 +493,7 @@ func TestAddContestTeam(t *testing.T) { tooLongName = strings.Repeat("亜", 33) tooLongDescriptionKanji = strings.Repeat("亜", 257) tooLongResultKanji = strings.Repeat("亜", 33) - invalidURL = "invalid url" + invalidURL = []string{"invalid url"} ) t.Parallel() @@ -507,7 +508,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: description, - Link: &link, + Links: links, Name: name, Result: &result, }, @@ -522,7 +523,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: justCountDescription, - Link: &link, + Links: links, Name: justCountName, Result: &justCountResult, }, @@ -537,7 +538,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: tooLongString, - Link: &link, + Links: links, Name: name, Result: &result, }, @@ -548,7 +549,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: tooLongDescriptionKanji, - Link: &link, + Links: links, Name: name, Result: &result, }, @@ -559,18 +560,18 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: description, - Link: &invalidURL, + Links: invalidURL, Name: name, Result: &result, }, - httpError(t, "Bad Request: validate error: link: must be a valid URL."), + httpError(t, "Bad Request: validate error: links: (0: must be a valid URL.)."), }, "400 invalid Name": { http.StatusBadRequest, mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: description, - Link: &link, + Links: links, Name: tooLongString, Result: &result, }, @@ -581,7 +582,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: description, - Link: &link, + Links: links, Name: tooLongName, Result: &result, }, @@ -592,7 +593,7 @@ func TestAddContestTeam(t *testing.T) { mockdata.ContestID1(), schema.AddContestTeamRequest{ Description: description, - Link: &link, + Links: links, Name: name, Result: &tooLongResultKanji, }, @@ -603,7 +604,7 @@ func TestAddContestTeam(t *testing.T) { random.UUID(), schema.AddContestTeamRequest{ Description: description, - Link: &link, + Links: links, Name: name, Result: &result, }, @@ -631,7 +632,7 @@ func TestAddContestTeam(t *testing.T) { func TestEditContestTeam(t *testing.T) { var ( description = random.AlphaNumeric() - link = random.RandURLString() + links = random.Array(random.RandURLString, 1, 3) name = random.AlphaNumeric() result = random.AlphaNumeric() tooLongString = strings.Repeat("a", 260) @@ -641,7 +642,7 @@ func TestEditContestTeam(t *testing.T) { tooLongName = strings.Repeat("亜", 33) tooLongDescriptionKanji = strings.Repeat("亜", 257) tooLongResultKanji = strings.Repeat("亜", 33) - invalidURL = "invalid url" + invalidURL = []string{"invalid url"} ) t.Parallel() @@ -658,7 +659,7 @@ func TestEditContestTeam(t *testing.T) { mockdata.ContestTeamID1(), schema.EditContestTeamRequest{ Description: &description, - Link: &link, + Links: &links, Name: &name, Result: &result, }, @@ -670,7 +671,7 @@ func TestEditContestTeam(t *testing.T) { mockdata.ContestTeamID2(), schema.EditContestTeamRequest{ Description: &justCountDescription, - Link: &link, + Links: &links, Name: &justCountName, Result: &justCountResult, }, @@ -720,9 +721,9 @@ func TestEditContestTeam(t *testing.T) { mockdata.ContestID1(), mockdata.ContestTeamID1(), schema.EditContestTeamRequest{ - Link: &invalidURL, + Links: &invalidURL, }, - httpError(t, "Bad Request: validate error: link: must be a valid URL."), + httpError(t, "Bad Request: validate error: 0: must be a valid URL."), }, "400 invalid Name": { http.StatusBadRequest, @@ -766,7 +767,7 @@ func TestEditContestTeam(t *testing.T) { random.UUID(), schema.EditContestTeamRequest{ Description: &description, - Link: &link, + Links: &links, Name: &name, Result: &result, }, @@ -794,15 +795,16 @@ func TestEditContestTeam(t *testing.T) { if tt.reqBody.Description != nil { contestTeam.Description = *tt.reqBody.Description } - if tt.reqBody.Link != nil { - contestTeam.Link = *tt.reqBody.Link - } if tt.reqBody.Name != nil { contestTeam.Name = *tt.reqBody.Name } if tt.reqBody.Result != nil { contestTeam.Result = *tt.reqBody.Result } + if tt.reqBody.Links != nil { + contestTeam.Links = *tt.reqBody.Links + } + res = doRequest(t, e, http.MethodGet, e.URL(api.Contest.GetContestTeam, tt.contestID, tt.teamID), nil) assertResponse(t, http.StatusOK, contestTeam, res) } else { diff --git a/integration_tests/handler/project_test.go b/integration_tests/handler/project_test.go index b4f47645..a22f0e24 100644 --- a/integration_tests/handler/project_test.go +++ b/integration_tests/handler/project_test.go @@ -78,8 +78,8 @@ func TestGetProject(t *testing.T) { func TestCreateProject(t *testing.T) { var ( name = random.AlphaNumeric() - link = random.RandURLString() - invalidLink = "invalid link" + links = random.Array(random.RandURLString, 1, 3) + invalidLink = []string{"invalid link"} description = random.AlphaNumeric() justCountName = strings.Repeat("亜", 32) justCountDescription = strings.Repeat("亜", 256) @@ -99,7 +99,7 @@ func TestCreateProject(t *testing.T) { http.StatusCreated, schema.CreateProjectRequest{ Name: name, - Link: &link, + Links: links, Description: description, Duration: duration, }, @@ -113,7 +113,7 @@ func TestCreateProject(t *testing.T) { http.StatusCreated, schema.CreateProjectRequest{ Name: justCountName, - Link: &link, + Links: links, Description: justCountDescription, Duration: duration, }, @@ -127,17 +127,17 @@ func TestCreateProject(t *testing.T) { http.StatusBadRequest, schema.CreateProjectRequest{ Name: name, - Link: &invalidLink, + Links: invalidLink, Description: description, Duration: duration, }, - httpError(t, "Bad Request: validate error: link: must be a valid URL."), + httpError(t, "Bad Request: validate error: links: (0: must be a valid URL.)."), }, "400 too long description": { http.StatusBadRequest, schema.CreateProjectRequest{ Name: name, - Link: &link, + Links: links, Description: tooLongDescriptionKanji, Duration: duration, }, @@ -147,7 +147,7 @@ func TestCreateProject(t *testing.T) { http.StatusBadRequest, schema.CreateProjectRequest{ Name: tooLongName, - Link: &link, + Links: links, Description: description, Duration: duration, }, @@ -156,7 +156,7 @@ func TestCreateProject(t *testing.T) { "400 empty name": { http.StatusBadRequest, schema.CreateProjectRequest{ - Link: &link, + Links: links, Description: description, Duration: duration, }, @@ -166,7 +166,7 @@ func TestCreateProject(t *testing.T) { http.StatusBadRequest, schema.CreateProjectRequest{ Name: name, - Link: &link, + Links: links, Duration: duration, }, httpError(t, "Bad Request: validate error: description: cannot be blank."), @@ -175,7 +175,7 @@ func TestCreateProject(t *testing.T) { http.StatusBadRequest, schema.CreateProjectRequest{ Name: name, - Link: &link, + Links: links, Description: description, }, httpError(t, "Bad Request: argument error"), @@ -184,7 +184,7 @@ func TestCreateProject(t *testing.T) { http.StatusBadRequest, schema.CreateProjectRequest{ Name: conflictedProject.Name, - Link: &link, + Links: links, Description: description, }, httpError(t, "Bad Request: argument error"), @@ -212,7 +212,7 @@ func TestCreateProject(t *testing.T) { func TestEditProject(t *testing.T) { var ( name = random.AlphaNumeric() - link = random.RandURLString() + links = random.Array(random.RandURLString, 1, 3) description = random.AlphaNumeric() justCountName = strings.Repeat("亜", 32) justCountDescription = strings.Repeat("亜", 256) @@ -233,7 +233,7 @@ func TestEditProject(t *testing.T) { mockdata.ProjectID1(), schema.EditProjectRequest{ Name: &name, - Link: &link, + Links: &links, Description: &description, Duration: &duration, }, @@ -244,7 +244,7 @@ func TestEditProject(t *testing.T) { mockdata.ProjectID1(), schema.EditProjectRequest{ Name: &justCountName, - Link: &link, + Links: &links, Description: &justCountDescription, Duration: &duration, }, diff --git a/internal/domain/contest.go b/internal/domain/contest.go index 00d017ca..3dfac0f9 100644 --- a/internal/domain/contest.go +++ b/internal/domain/contest.go @@ -15,7 +15,7 @@ type Contest struct { type ContestDetail struct { Contest - Link string + Links []string Description string ContestTeams []*ContestTeam } @@ -34,6 +34,6 @@ type ContestTeam struct { type ContestTeamDetail struct { ContestTeam - Link string + Links []string Description string } diff --git a/internal/domain/group.go b/internal/domain/group.go index d6b427de..1c58ce23 100644 --- a/internal/domain/group.go +++ b/internal/domain/group.go @@ -12,7 +12,7 @@ type Group struct { type GroupDetail struct { ID uuid.UUID Name string - Link string + Links []string Admin []*User Members []*UserWithDuration Description string diff --git a/internal/domain/project.go b/internal/domain/project.go index abfb5976..18fbae28 100644 --- a/internal/domain/project.go +++ b/internal/domain/project.go @@ -13,6 +13,6 @@ type Project struct { type ProjectDetail struct { Project Description string - Link string + Links []string Members []*UserWithDuration } diff --git a/internal/handler/contest.go b/internal/handler/contest.go index 64dec461..7b42e238 100644 --- a/internal/handler/contest.go +++ b/internal/handler/contest.go @@ -71,7 +71,7 @@ func (h *ContestHandler) GetContest(c echo.Context) error { res := newContestDetail( newContest(contest.ID, contest.Name, contest.TimeStart, contest.TimeEnd), - contest.Link, + contest.Links, contest.Description, teams, ) @@ -89,7 +89,7 @@ func (h *ContestHandler) CreateContest(c echo.Context) error { createReq := repository.CreateContestArgs{ Name: req.Name, Description: req.Description, - Link: optional.FromPtr(req.Link), + Links: req.Links, Since: req.Duration.Since, Until: optional.FromPtr(req.Duration.Until), } @@ -100,7 +100,7 @@ func (h *ContestHandler) CreateContest(c echo.Context) error { return err } - res := newContestDetail(newContest(contest.ID, contest.Name, contest.TimeStart, contest.TimeEnd), contest.Link, contest.Description, []schema.ContestTeam{}) + res := newContestDetail(newContest(contest.ID, contest.Name, contest.TimeStart, contest.TimeEnd), contest.Links, contest.Description, []schema.ContestTeam{}) return c.JSON(http.StatusCreated, res) } @@ -120,7 +120,7 @@ func (h *ContestHandler) EditContest(c echo.Context) error { patchReq := repository.UpdateContestArgs{ Name: optional.FromPtr(req.Name), Description: optional.FromPtr(req.Description), - Link: optional.FromPtr(req.Link), + Links: optional.FromPtr(req.Links), } if req.Duration != nil { patchReq.Since = optional.FromPtr(&req.Duration.Since) @@ -210,7 +210,7 @@ func (h *ContestHandler) GetContestTeam(c echo.Context) error { res := newContestTeamDetail( newContestTeam(contestTeam.ID, contestTeam.Name, contestTeam.Result, members), - contestTeam.Link, + contestTeam.Links, contestTeam.Description, ) @@ -232,7 +232,7 @@ func (h *ContestHandler) AddContestTeam(c echo.Context) error { args := repository.CreateContestTeamArgs{ Name: req.Name, Result: optional.FromPtr(req.Result), - Link: optional.FromPtr(req.Link), + Links: req.Links, Description: req.Description, } @@ -268,7 +268,7 @@ func (h *ContestHandler) EditContestTeam(c echo.Context) error { args := repository.UpdateContestTeamArgs{ Name: optional.FromPtr(req.Name), Result: optional.FromPtr(req.Result), - Link: optional.FromPtr(req.Link), + Links: optional.FromPtr(req.Links), Description: optional.FromPtr(req.Description), } @@ -365,12 +365,12 @@ func newContest(id uuid.UUID, name string, since time.Time, until time.Time) sch } } -func newContestDetail(contest schema.Contest, link string, description string, teams []schema.ContestTeam) schema.ContestDetail { +func newContestDetail(contest schema.Contest, links []string, description string, teams []schema.ContestTeam) schema.ContestDetail { return schema.ContestDetail{ Description: description, Duration: contest.Duration, Id: contest.Id, - Link: link, + Links: links, Name: contest.Name, Teams: teams, } @@ -393,11 +393,11 @@ func newContestTeamWithoutMembers(id uuid.UUID, name string, result string) sche } } -func newContestTeamDetail(team schema.ContestTeam, link string, description string) schema.ContestTeamDetail { +func newContestTeamDetail(team schema.ContestTeam, links []string, description string) schema.ContestTeamDetail { return schema.ContestTeamDetail{ Description: description, Id: team.Id, - Link: link, + Links: links, Members: team.Members, Name: team.Name, Result: team.Result, diff --git a/internal/handler/contest_test.go b/internal/handler/contest_test.go index bdc5fda3..3d8a7e6c 100644 --- a/internal/handler/contest_test.go +++ b/internal/handler/contest_test.go @@ -120,7 +120,7 @@ func makeContest(t *testing.T) (*domain.ContestDetail, *schema.ContestDetail) { TimeStart: since, TimeEnd: until, }, - Link: random.RandURLString(), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), ContestTeams: []*domain.ContestTeam{ { @@ -175,7 +175,7 @@ func makeContest(t *testing.T) (*domain.ContestDetail, *schema.ContestDetail) { Until: &d.TimeEnd, }, Id: d.ID, - Link: d.Link, + Links: d.Links, Name: d.Name, Teams: teams, } @@ -238,7 +238,7 @@ func TestContestHandler_GetContest(t *testing.T) { } } -func makeCreateContestRequest(t *testing.T, description string, since time.Time, until time.Time, name string, link string) *schema.CreateContestRequest { +func makeCreateContestRequest(t *testing.T, description string, since time.Time, until time.Time, name string, links []string) *schema.CreateContestRequest { t.Helper() return &schema.CreateContestRequest{ Description: description, @@ -246,8 +246,8 @@ func makeCreateContestRequest(t *testing.T, description string, since time.Time, Since: since, Until: &until, }, - Name: name, - Link: &link, + Name: name, + Links: links, } } @@ -268,12 +268,12 @@ func TestContestHandler_CreateContest(t *testing.T) { since, until, random.AlphaNumeric(), - random.RandURLString(), + random.Array(random.RandURLString, 1, 3), ) args := repository.CreateContestArgs{ Name: reqBody.Name, Description: reqBody.Description, - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, Since: reqBody.Duration.Since, Until: optional.FromPtr(reqBody.Duration.Until), } @@ -284,7 +284,7 @@ func TestContestHandler_CreateContest(t *testing.T) { TimeStart: args.Since, TimeEnd: args.Until.ValueOrZero(), }, - Link: args.Link.ValueOrZero(), + Links: args.Links, Description: args.Description, ContestTeams: []*domain.ContestTeam{}, } @@ -312,7 +312,7 @@ func TestContestHandler_CreateContest(t *testing.T) { since, until, random.AlphaNumeric(), - random.AlphaNumeric(), + random.Array(random.AlphaNumeric, 1, 3), ) path = "/api/v1/contests" return reqBody, nil, nil, path @@ -329,12 +329,12 @@ func TestContestHandler_CreateContest(t *testing.T) { since, until, random.AlphaNumeric(), - random.RandURLString(), + random.Array(random.RandURLString, 1, 3), ) args := repository.CreateContestArgs{ Name: reqBody.Name, Description: reqBody.Description, - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, Since: reqBody.Duration.Since, Until: optional.FromPtr(reqBody.Duration.Until), } @@ -372,12 +372,12 @@ func TestContestHandler_PatchContest(t *testing.T) { setup: func(mr MockRepository) (*schema.EditContestRequest, string) { contestID := random.UUID() name := random.AlphaNumeric() - link := random.RandURLString() + links := random.Array(random.RandURLString, 1, 3) description := random.AlphaNumeric() since, until := random.SinceAndUntil() reqBody := &schema.EditContestRequest{ Name: &name, - Link: &link, + Links: &links, Description: &description, Duration: &schema.Duration{ Since: since, @@ -387,7 +387,7 @@ func TestContestHandler_PatchContest(t *testing.T) { args := repository.UpdateContestArgs{ Name: optional.FromPtr(reqBody.Name), Description: optional.FromPtr(reqBody.Description), - Link: optional.FromPtr(reqBody.Link), + Links: optional.FromPtr(reqBody.Links), Since: optional.FromPtr(&reqBody.Duration.Since), Until: optional.FromPtr(reqBody.Duration.Until), } @@ -422,9 +422,9 @@ func TestContestHandler_PatchContest(t *testing.T) { name: "BadRequest: invalid link", setup: func(_ MockRepository) (*schema.EditContestRequest, string) { contestID := random.UUID() - link := random.AlphaNumeric() + links := random.Array(random.AlphaNumeric, 1, 3) reqBody := &schema.EditContestRequest{ - Link: &link, + Links: &links, } path := fmt.Sprintf("/api/v1/contests/%s", contestID) return reqBody, path @@ -628,7 +628,7 @@ func TestContestHandler_GetContestTeam(t *testing.T) { domain.NewUser(random.UUID(), random.AlphaNumeric(), random.AlphaNumeric(), random.Bool()), }, }, - Link: random.AlphaNumeric(), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), } members := make([]schema.User, 0, len(repoContestTeamDetail.Members)) @@ -643,7 +643,7 @@ func TestContestHandler_GetContestTeam(t *testing.T) { hres := schema.ContestTeamDetail{ Description: repoContestTeamDetail.Description, Id: repoContestTeamDetail.ID, - Link: repoContestTeamDetail.Link, + Links: repoContestTeamDetail.Links, Members: members, Name: repoContestTeamDetail.Name, Result: repoContestTeamDetail.Result, @@ -711,14 +711,14 @@ func TestContestHandler_AddContestTeam(t *testing.T) { teamID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } args := repository.CreateContestTeamArgs{ Name: reqBody.Name, Result: optional.FromPtr(reqBody.Result), - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, Description: reqBody.Description, } want := domain.ContestTeamDetail{ @@ -731,7 +731,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { }, Members: make([]*domain.User, 0), }, - Link: args.Link.ValueOrZero(), + Links: args.Links, Description: args.Description, } expectedResBody := schema.ContestTeam{ @@ -750,7 +750,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { setup: func(_ MockRepository) (*schema.AddContestTeamRequest, schema.ContestTeam, string) { reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } @@ -764,7 +764,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ // Name: random.AlphaNumeric(), // missing - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } @@ -778,7 +778,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: strings.Repeat("a", 257), Result: ptr(t, random.AlphaNumeric()), } @@ -792,7 +792,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.AlphaNumeric()), + Links: random.Array(random.AlphaNumeric, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } @@ -806,7 +806,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: strings.Repeat("a", 33), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } @@ -820,7 +820,7 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, strings.Repeat("a", 33)), } @@ -834,14 +834,14 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } args := repository.CreateContestTeamArgs{ Name: reqBody.Name, Result: optional.FromPtr(reqBody.Result), - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, Description: reqBody.Description, } mr.contest.EXPECT().CreateContestTeam(anyCtx{}, contestID, &args).Return(nil, repository.ErrNotFound) @@ -855,14 +855,14 @@ func TestContestHandler_AddContestTeam(t *testing.T) { contestID := random.UUID() reqBody := &schema.AddContestTeamRequest{ Name: random.AlphaNumeric(), - Link: ptr(t, random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), Result: ptr(t, random.AlphaNumeric()), } args := repository.CreateContestTeamArgs{ Name: reqBody.Name, Result: optional.FromPtr(reqBody.Result), - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, Description: reqBody.Description, } mr.contest.EXPECT().CreateContestTeam(anyCtx{}, contestID, &args).Return(nil, repository.ErrAlreadyExists) @@ -902,13 +902,13 @@ func TestContestHandler_PatchContestTeam(t *testing.T) { teamID := random.UUID() reqBody := &schema.EditContestTeamRequest{ Name: ptr(t, random.AlphaNumeric()), - Link: ptr(t, random.RandURLString()), + Links: ptr(t, random.Array(random.RandURLString, 1, 3)), Result: ptr(t, random.AlphaNumeric()), Description: ptr(t, random.AlphaNumeric()), } args := repository.UpdateContestTeamArgs{ Name: optional.FromPtr(reqBody.Name), - Link: optional.FromPtr(reqBody.Link), + Links: optional.FromPtr(reqBody.Links), Result: optional.FromPtr(reqBody.Result), Description: optional.FromPtr(reqBody.Description), } @@ -922,7 +922,7 @@ func TestContestHandler_PatchContestTeam(t *testing.T) { setup: func(_ MockRepository) (*schema.EditContestTeamRequest, string) { reqBody := &schema.EditContestTeamRequest{ Name: ptr(t, random.AlphaNumeric()), - Link: ptr(t, random.RandURLString()), + Links: ptr(t, random.Array(random.RandURLString, 1, 3)), Result: ptr(t, random.AlphaNumeric()), Description: ptr(t, random.AlphaNumeric()), } @@ -935,7 +935,7 @@ func TestContestHandler_PatchContestTeam(t *testing.T) { setup: func(_ MockRepository) (*schema.EditContestTeamRequest, string) { reqBody := &schema.EditContestTeamRequest{ Name: ptr(t, random.AlphaNumeric()), - Link: ptr(t, random.RandURLString()), + Links: ptr(t, random.Array(random.RandURLString, 1, 3)), Result: ptr(t, random.AlphaNumeric()), Description: ptr(t, random.AlphaNumeric()), } @@ -971,7 +971,7 @@ func TestContestHandler_PatchContestTeam(t *testing.T) { name: "BadRequest: Invalid request body: invalid link", setup: func(_ MockRepository) (*schema.EditContestTeamRequest, string) { reqBody := &schema.EditContestTeamRequest{ - Link: ptr(t, random.AlphaNumeric()), + Links: ptr(t, random.Array(random.AlphaNumeric, 1, 3)), } return reqBody, fmt.Sprintf("/api/v1/contests/%s/teams/%s", random.UUID(), random.UUID()) }, @@ -984,13 +984,13 @@ func TestContestHandler_PatchContestTeam(t *testing.T) { teamID := random.UUID() reqBody := &schema.EditContestTeamRequest{ Name: ptr(t, random.AlphaNumeric()), - Link: ptr(t, random.RandURLString()), + Links: ptr(t, random.Array(random.RandURLString, 1, 3)), Result: ptr(t, random.AlphaNumeric()), Description: ptr(t, random.AlphaNumeric()), } args := repository.UpdateContestTeamArgs{ Name: optional.FromPtr(reqBody.Name), - Link: optional.FromPtr(reqBody.Link), + Links: optional.FromPtr(reqBody.Links), Result: optional.FromPtr(reqBody.Result), Description: optional.FromPtr(reqBody.Description), } diff --git a/internal/handler/group.go b/internal/handler/group.go index 22564276..d6243f4d 100644 --- a/internal/handler/group.go +++ b/internal/handler/group.go @@ -98,7 +98,7 @@ func formatGetGroup(group *domain.GroupDetail) schema.GroupDetail { newGroup(group.ID, group.Name), group.Description, adminRes, - group.Link, + group.Links, groupRes, ) @@ -114,12 +114,12 @@ func newGroupMember(user schema.User, Duration schema.YearWithSemesterDuration) } } -func newGroupDetail(group schema.Group, desc string, admin []schema.User, link string, members []schema.GroupMember) schema.GroupDetail { +func newGroupDetail(group schema.Group, desc string, admin []schema.User, links []string, members []schema.GroupMember) schema.GroupDetail { return schema.GroupDetail{ Description: desc, Id: group.Id, Admin: admin, - Link: link, + Links: links, Members: members, Name: group.Name, } diff --git a/internal/handler/group_test.go b/internal/handler/group_test.go index eebb2543..dafb856a 100644 --- a/internal/handler/group_test.go +++ b/internal/handler/group_test.go @@ -142,7 +142,7 @@ func TestGroupHandler_GetGroup(t *testing.T) { rgroup := domain.GroupDetail{ ID: random.UUID(), Name: random.AlphaNumeric(), - Link: random.AlphaNumeric(), + Links: random.Array(random.RandURLString, 1, 3), Admin: rgroupAdmins, Members: rgroupMembers, Description: random.AlphaNumeric(), @@ -152,7 +152,7 @@ func TestGroupHandler_GetGroup(t *testing.T) { Description: rgroup.Description, Id: rgroup.ID, Admin: hgroupAdmins, - Link: rgroup.Link, + Links: rgroup.Links, Members: hgroupMembers, Name: rgroup.Name, } diff --git a/internal/handler/project.go b/internal/handler/project.go index 52a78a84..51006c75 100644 --- a/internal/handler/project.go +++ b/internal/handler/project.go @@ -59,7 +59,7 @@ func (h *ProjectHandler) GetProject(c echo.Context) error { return c.JSON(http.StatusOK, newProjectDetail( newProject(project.ID, project.Name, schema.ConvertDuration(project.Duration)), project.Description, - project.Link, + project.Links, members, )) } @@ -74,7 +74,7 @@ func (h *ProjectHandler) CreateProject(c echo.Context) error { createReq := repository.CreateProjectArgs{ Name: req.Name, Description: req.Description, - Link: optional.FromPtr(req.Link), + Links: req.Links, SinceYear: req.Duration.Since.Year, SinceSemester: int(req.Duration.Since.Semester), } @@ -116,7 +116,7 @@ func (h *ProjectHandler) EditProject(c echo.Context) error { patchReq := repository.UpdateProjectArgs{ Name: optional.FromPtr(req.Name), Description: optional.FromPtr(req.Description), - Link: optional.FromPtr(req.Link), + Links: optional.FromPtr(req.Links), } if d := req.Duration; d != nil { @@ -269,11 +269,11 @@ func newProject(id uuid.UUID, name string, duration schema.YearWithSemesterDurat } } -func newProjectDetail(project schema.Project, description string, link string, members []schema.ProjectMember) schema.ProjectDetail { +func newProjectDetail(project schema.Project, description string, links []string, members []schema.ProjectMember) schema.ProjectDetail { return schema.ProjectDetail{ Description: description, Duration: project.Duration, - Link: link, + Links: links, Id: project.Id, Members: members, Name: project.Name, diff --git a/internal/handler/project_test.go b/internal/handler/project_test.go index 99fe2ae1..5310d1d5 100644 --- a/internal/handler/project_test.go +++ b/internal/handler/project_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/traPtitech/traPortfolio/internal/handler/schema" - "github.com/traPtitech/traPortfolio/internal/pkgs/optional" "github.com/traPtitech/traPortfolio/internal/usecases/repository" "github.com/gofrs/uuid" @@ -33,7 +32,7 @@ func setupProjectMock(t *testing.T) (MockRepository, API) { return mr, api } -func makeCreateProjectRequest(t *testing.T, description string, since schema.YearWithSemester, until *schema.YearWithSemester, name string, link string) *schema.CreateProjectRequest { +func makeCreateProjectRequest(t *testing.T, description string, since schema.YearWithSemester, until *schema.YearWithSemester, name string, links []string) *schema.CreateProjectRequest { t.Helper() return &schema.CreateProjectRequest{ Description: description, @@ -41,8 +40,8 @@ func makeCreateProjectRequest(t *testing.T, description string, since schema.Yea Since: since, Until: until, }, - Name: name, - Link: &link, + Name: name, + Links: links, } } @@ -131,7 +130,7 @@ func TestProjectHandler_GetProject(t *testing.T) { Duration: duration, }, Description: random.AlphaNumeric(), - Link: random.RandURLString(), + Links: random.Array(random.RandURLString, 1, 3), Members: []*domain.UserWithDuration{ { User: *domain.NewUser(random.UUID(), random.AlphaNumeric(), random.AlphaNumeric(), random.Bool()), @@ -153,7 +152,7 @@ func TestProjectHandler_GetProject(t *testing.T) { Description: repo.Description, Duration: schema.ConvertDuration(repo.Duration), Id: repo.ID, - Link: repo.Link, + Links: repo.Links, Members: members, Name: repo.Name, } @@ -232,12 +231,12 @@ func TestProjectHandler_CreateProject(t *testing.T) { schema.ConvertDuration(duration).Since, schema.ConvertDuration(duration).Until, random.AlphaNumeric(), - random.RandURLString(), + random.Array(random.RandURLString, 1, 3), ) args := repository.CreateProjectArgs{ Name: reqBody.Name, Description: reqBody.Description, - Link: optional.FromPtr(reqBody.Link), + Links: reqBody.Links, SinceYear: reqBody.Duration.Since.Year, SinceSemester: int(reqBody.Duration.Since.Semester), UntilYear: reqBody.Duration.Until.Year, @@ -255,7 +254,7 @@ func TestProjectHandler_CreateProject(t *testing.T) { ), }, Description: args.Description, - Link: args.Link.ValueOrZero(), + Links: args.Links, Members: nil, } expectedResBody = schema.Project{ diff --git a/internal/handler/schema/schema_gen.go b/internal/handler/schema/schema_gen.go index 742bee89..b88a65bb 100644 --- a/internal/handler/schema/schema_gen.go +++ b/internal/handler/schema/schema_gen.go @@ -1,6 +1,6 @@ // Package schema provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. package schema import ( @@ -63,8 +63,8 @@ type AddContestTeamRequest struct { // Description チーム情報 Description string `json:"description"` - // Link コンテストチームの説明が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links コンテストチームのリンク集 + Links []ContestTeamLink `json:"links"` // Name チーム名 Name string `json:"name"` @@ -96,8 +96,8 @@ type ContestDetail struct { // Id コンテストuuid Id uuid.UUID `json:"id"` - // Link コンテストの詳細が載っているページへのリンク - Link string `json:"link"` + // Links コンテストのリンク集 + Links []ContestLink `json:"links"` // Name コンテスト名 Name string `json:"name"` @@ -106,6 +106,9 @@ type ContestDetail struct { Teams []ContestTeam `json:"teams"` } +// ContestLink コンテストの詳細が載っているページへのリンク +type ContestLink = string + // ContestTeam defines model for ContestTeam. type ContestTeam struct { // Id コンテストチームuuid @@ -129,8 +132,8 @@ type ContestTeamDetail struct { // Id コンテストチームuuid Id uuid.UUID `json:"id"` - // Link コンテストチームの詳細が載っているページへのリンク - Link string `json:"link"` + // Links コンテストチームのリンク集 + Links []ContestTeamLink `json:"links"` // Members チームメンバーのUUID Members []User `json:"members"` @@ -142,6 +145,9 @@ type ContestTeamDetail struct { Result string `json:"result"` } +// ContestTeamLink コンテストチームの詳細が載っているページへのリンク +type ContestTeamLink = string + // ContestTeamWithoutMembers コンテストチーム情報(チームメンバーなし) type ContestTeamWithoutMembers struct { // Id コンテストチームuuid @@ -162,8 +168,8 @@ type CreateContestRequest struct { // Duration イベントやコンテストなどの存続期間 Duration Duration `json:"duration"` - // Link コンテストの詳細が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links コンテストのリンク集 + Links []ContestLink `json:"links"` // Name コンテスト名 Name string `json:"name"` @@ -179,8 +185,8 @@ type CreateProjectRequest struct { // untilがなかった場合存続中 Duration YearWithSemesterDuration `json:"duration"` - // Link プロジェクトの詳細が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links プロジェクトのリンク集 + Links []ProjectLink `json:"links"` // Name プロジェクト名 Name string `json:"name"` @@ -204,8 +210,8 @@ type EditContestRequest struct { // Duration イベントやコンテストなどの存続期間 Duration *Duration `json:"duration,omitempty"` - // Link コンテストの詳細が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links コンテストのリンク集 + Links *[]ContestLink `json:"links,omitempty"` // Name コンテスト名 Name *string `json:"name,omitempty"` @@ -222,8 +228,8 @@ type EditContestTeamRequest struct { // Description チーム情報 Description *string `json:"description,omitempty"` - // Link コンテストチームの説明が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links コンテストチームのリンク集 + Links *[]ContestTeamLink `json:"links,omitempty"` // Name チーム名 Name *string `json:"name,omitempty"` @@ -256,8 +262,8 @@ type EditProjectRequest struct { // untilがなかった場合存続中 Duration *YearWithSemesterDuration `json:"duration,omitempty"` - // Link プロジェクトの詳細が載っているページへのリンク - Link *string `json:"link,omitempty"` + // Links プロジェクトのリンク集 + Links *[]ProjectLink `json:"links,omitempty"` // Name プロジェクト名 Name *string `json:"name,omitempty"` @@ -360,8 +366,8 @@ type GroupDetail struct { // Id 班uuid Id uuid.UUID `json:"id"` - // Link 班の詳細が載っているページへのリンク - Link string `json:"link"` + // Links 班のリンク集 + Links []GroupLink `json:"links"` // Members 班メンバー Members []GroupMember `json:"members"` @@ -370,6 +376,9 @@ type GroupDetail struct { Name string `json:"name"` } +// GroupLink 班の詳細が載っているページへのリンク +type GroupLink = string + // GroupMember defines model for GroupMember. type GroupMember struct { // Duration 班やプロジェクトの期間 @@ -426,8 +435,8 @@ type ProjectDetail struct { // Id プロジェクトuuid Id uuid.UUID `json:"id"` - // Link プロジェクトの詳細が載っているページへのリンク - Link string `json:"link"` + // Links プロジェクトのリンク集 + Links []ProjectLink `json:"links"` // Members プロジェクトメンバー Members []ProjectMember `json:"members"` @@ -436,6 +445,9 @@ type ProjectDetail struct { Name string `json:"name"` } +// ProjectLink プロジェクトの詳細が載っているページへのリンク +type ProjectLink = string + // ProjectMember defines model for ProjectMember. type ProjectMember struct { // Duration 班やプロジェクトの期間 diff --git a/internal/handler/schema/validator.go b/internal/handler/schema/validator.go index b50497cc..cff885b4 100644 --- a/internal/handler/schema/validator.go +++ b/internal/handler/schema/validator.go @@ -45,7 +45,7 @@ func (r AddAccountRequest) Validate() error { func (r AddContestTeamRequest) Validate() error { return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.Required, vdRuleDescriptionLength), - vd.Field(&r.Link, is.URL), + vd.Field(&r.Links, vd.Required, vd.Each(is.URL)), vd.Field(&r.Name, vd.Required, vdRuleNameLength), vd.Field(&r.Result, vdRuleResultLength), ) @@ -61,7 +61,7 @@ func (r CreateContestRequest) Validate() error { return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.Required, vdRuleDescriptionLength), vd.Field(&r.Duration, vd.Required), - vd.Field(&r.Link, is.URL), + vd.Field(&r.Links, vd.Required, vd.Each(is.URL)), vd.Field(&r.Name, vd.Required, vdRuleNameLength), ) } @@ -70,7 +70,7 @@ func (r CreateProjectRequest) Validate() error { return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.Required, vdRuleDescriptionLength), vd.Field(&r.Duration, vd.Required), - vd.Field(&r.Link, is.URL), + vd.Field(&r.Links, vd.Required, vd.Each(is.URL)), vd.Field(&r.Name, vd.Required, vdRuleNameLength), ) } @@ -85,18 +85,30 @@ func (r EditUserAccountRequest) Validate() error { } func (r EditContestRequest) Validate() error { + // vd.ValidateStructはフィールドをポインタでしか受け付けないため、vd.Eachルールでポインタのフィールドをうまく解釈できない + // vd.Field(&r.Links, vd.Each(is.URL)) ルールと等価 + if r.Links != nil { + if err := vd.Validate(*r.Links, vd.Each(is.URL)); err != nil { + return err + } + } return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.NilOrNotEmpty, vdRuleDescriptionLength), vd.Field(&r.Duration, vd.NilOrNotEmpty), - vd.Field(&r.Link, is.URL), vd.Field(&r.Name, vd.NilOrNotEmpty, vdRuleNameLength), ) } func (r EditContestTeamRequest) Validate() error { + // vd.ValidateStructはフィールドをポインタでしか受け付けないため、vd.Eachルールでポインタのフィールドをうまく解釈できない + // vd.Field(&r.Links, vd.Each(is.URL)) ルールと等価 + if r.Links != nil { + if err := vd.Validate(*r.Links, vd.Each(is.URL)); err != nil { + return err + } + } return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.NilOrNotEmpty, vdRuleDescriptionLength), - vd.Field(&r.Link, is.URL), vd.Field(&r.Name, vd.NilOrNotEmpty, vdRuleNameLength), vd.Field(&r.Result, vdRuleResultLength), ) @@ -115,10 +127,16 @@ func (r EditEventRequest) Validate() error { } func (r EditProjectRequest) Validate() error { + // vd.ValidateStructはフィールドをポインタでしか受け付けないため、vd.Eachルールでポインタのフィールドをうまく解釈できない + // vd.Field(&r.Links, vd.Each(is.URL)) ルールと等価 + if r.Links != nil { + if err := vd.Validate(*r.Links, vd.Each(is.URL)); err != nil { + return err + } + } return vd.ValidateStruct(&r, vd.Field(&r.Description, vd.NilOrNotEmpty, vdRuleDescriptionLength), vd.Field(&r.Duration, vd.NilOrNotEmpty), - vd.Field(&r.Link, is.URL), vd.Field(&r.Name, vd.NilOrNotEmpty, vdRuleNameLength), ) } diff --git a/internal/handler/testutil_test.go b/internal/handler/testutil_test.go index 98ce5295..cbd1bbd7 100644 --- a/internal/handler/testutil_test.go +++ b/internal/handler/testutil_test.go @@ -68,12 +68,37 @@ func responseDecode(t *testing.T, rec *httptest.ResponseRecorder, i interface{}) } // FIXME: 暫定対処 -func ptr(t *testing.T, s string) *string { +func ptr[T any](t *testing.T, s T) *T { t.Helper() return &s } +func MatchStringArray(a1 []string, a2 []string) bool { + c1 := make([]string, 0, len(a1)) + c2 := append([]string{}, a2...) + + for _, e1 := range a1 { + found := -1 + for i, e2 := range c2 { + if e1 == e2 { + found = i + break + } + } + + if found >= 0 { + shorten := len(c2) - 1 + c2[found] = c2[shorten] + c2 = c2[:shorten] + } else { + c1 = append(c1, e1) + } + } + + return len(c1) == 0 && len(c2) == 0 +} + type anyCtx struct{} func (anyCtx) Matches(v interface{}) bool { diff --git a/internal/infrastructure/migration/current.go b/internal/infrastructure/migration/current.go index 08e562fe..7411d534 100644 --- a/internal/infrastructure/migration/current.go +++ b/internal/infrastructure/migration/current.go @@ -10,6 +10,7 @@ func Migrations() []*gormigrate.Migration { return []*gormigrate.Migration{ v1(), v2(), // プロジェクト名とコンテスト名の重複禁止と文字数制限増加(32->128) + v3(), // contestTeam, group, projectの複数リンク対応 } } @@ -19,12 +20,16 @@ func AllTables() []interface{} { model.Account{}, model.Project{}, model.ProjectMember{}, + model.ProjectLink{}, model.EventLevelRelation{}, model.Contest{}, + model.ContestLink{}, model.ContestTeam{}, model.ContestTeamUserBelonging{}, + model.ContestTeamLink{}, model.Group{}, model.GroupUserBelonging{}, model.GroupUserAdmin{}, + model.GroupLink{}, } } diff --git a/internal/infrastructure/migration/v3.go b/internal/infrastructure/migration/v3.go new file mode 100644 index 00000000..59eefeec --- /dev/null +++ b/internal/infrastructure/migration/v3.go @@ -0,0 +1,221 @@ +// Package migration migrate current struct +package migration + +import ( + "time" + + "github.com/go-gormigrate/gormigrate/v2" + "github.com/gofrs/uuid" + "github.com/traPtitech/traPortfolio/internal/infrastructure/repository/model" + "gorm.io/gorm" +) + +// v3 contestTeam, group, projectの複数リンク対応 +func v3() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "3", + Migrate: func(db *gorm.DB) error { + if err := db.AutoMigrate(&v3ContestLink{}, &v3ContestTeamLink{}, &v3GroupLink{}, &v3ProjectLink{}); err != nil { + return err + } + + // contestのlinkをcontest_linksに移動 + { + contests := make([]*v3OldContest, 0) + if err := db.Find(&contests).Error; err != nil { + return err + } + + for _, contest := range contests { + contestLink := v3ContestLink{ + ID: contest.ID, + Order: 0, + Link: contest.Link, + } + if err := db.Create(&contestLink).Error; err != nil { + return err + } + } + + if err := db.Migrator().DropColumn(v3OldContest{}, "link"); err != nil { + return err + } + } + + // contest_teamsのlinkをcontest_team_linksに移動 + { + contestTeams := make([]*v3OldContestTeam, 0) + if err := db.Find(&contestTeams).Error; err != nil { + return err + } + + for _, contestTeam := range contestTeams { + teamLink := v3ContestTeamLink{ + ID: contestTeam.ID, + Order: 0, + Link: contestTeam.Link, + } + if err := db.Create(&teamLink).Error; err != nil { + return err + } + } + + if err := db.Migrator().DropColumn(v3OldContestTeam{}, "link"); err != nil { + return err + } + } + + // groupのlinkをgroup_linksに移動 + { + groups := make([]*v3OldGroup, 0) + if err := db.Find(&groups).Error; err != nil { + return err + } + + for _, group := range groups { + groupLink := v3GroupLink{ + ID: group.GroupID, + Order: 0, + Link: group.Link, + } + if err := db.Create(&groupLink).Error; err != nil { + return err + } + } + + if err := db.Migrator().DropColumn(v3OldGroup{}, "link"); err != nil { + return err + } + } + + // projectのlinkをgroup_linksに移動 + { + projects := make([]*v3OldProject, 0) + if err := db.Find(&projects).Error; err != nil { + return err + } + + for _, project := range projects { + projectLink := v3ProjectLink{ + ID: project.ID, + Order: 0, + Link: project.Link, + } + if err := db.Create(&projectLink).Error; err != nil { + return err + } + } + + if err := db.Migrator().DropColumn(v3OldProject{}, "link"); err != nil { + return err + } + } + + return db. + Table("portfolio"). + Error + }, + } +} + +type v3OldContest struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Name string `gorm:"type:varchar(128)"` + Description string `gorm:"type:text"` + Link string `gorm:"type:text"` + Since time.Time `gorm:"precision:6"` + Until time.Time `gorm:"precision:6"` + CreatedAt time.Time `gorm:"precision:6"` + UpdatedAt time.Time `gorm:"precision:6"` +} + +func (*v3OldContest) TableName() string { + return "contests" +} + +type v3ContestLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*v3ContestLink) TableName() string { + return "contest_links" +} + +type v3OldContestTeam struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + ContestID uuid.UUID `gorm:"type:char(36);not null"` + Name string `gorm:"type:varchar(128)"` + Description string `gorm:"type:text"` + Result string `gorm:"type:text"` + Link string `gorm:"type:text"` + CreatedAt time.Time `gorm:"precision:6"` + UpdatedAt time.Time `gorm:"precision:6"` + + Contest model.Contest `gorm:"foreignKey:ContestID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` +} + +func (*v3OldContestTeam) TableName() string { + return "contest_teams" +} + +type v3ContestTeamLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*v3ContestTeamLink) TableName() string { + return "contest_team_links" +} + +type v3OldGroup struct { + GroupID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Name string `gorm:"type:varchar(32)"` + Link string `gorm:"type:text"` + Description string `gorm:"type:text"` + CreatedAt time.Time `gorm:"precision:6"` + UpdatedAt time.Time `gorm:"precision:6"` +} + +func (*v3OldGroup) TableName() string { + return "groups" +} + +type v3GroupLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*v3GroupLink) TableName() string { + return "group_links" +} + +type v3OldProject struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Name string `gorm:"type:varchar(128)"` + Description string `gorm:"type:text"` + Link string `gorm:"type:text"` + SinceYear int `gorm:"type:smallint(4);not null"` + SinceSemester int `gorm:"type:tinyint(1);not null"` + UntilYear int `gorm:"type:smallint(4);not null"` + UntilSemester int `gorm:"type:tinyint(1);not null"` + CreatedAt time.Time `gorm:"precision:6"` + UpdatedAt time.Time `gorm:"precision:6"` +} + +func (*v3OldProject) TableName() string { + return "projects" +} + +type v3ProjectLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*v3ProjectLink) TableName() string { + return "project_links" +} diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 6971ce4f..c574179c 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -3,6 +3,7 @@ package repository import ( "context" "errors" + "sort" "github.com/gofrs/uuid" "github.com/traPtitech/traPortfolio/internal/domain" @@ -56,6 +57,24 @@ func (r *ContestRepository) getContest(ctx context.Context, contestID uuid.UUID) return nil, err } + contestLinks := make([]*model.ContestLink, 0) + if err := r.h. + WithContext(ctx). + Where(&model.ContestLink{ID: contestID}). + Find(&contestLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return nil, err + } + } else { + sort.Slice(contestLinks, func(i, j int) bool { return contestLinks[i].Order < contestLinks[j].Order }) + } + + links := make([]string, len(contestLinks)) + for i, link := range contestLinks { + links[i] = link.Link + } + res := &domain.ContestDetail{ Contest: domain.Contest{ ID: contest.ID, @@ -63,7 +82,7 @@ func (r *ContestRepository) getContest(ctx context.Context, contestID uuid.UUID) TimeStart: contest.Since, TimeEnd: contest.Until, }, - Link: contest.Link, + Links: links, Description: contest.Description, // Teams: } @@ -76,7 +95,6 @@ func (r *ContestRepository) CreateContest(ctx context.Context, args *repository. ID: uuid.Must(uuid.NewV4()), Name: args.Name, Description: args.Description, - Link: args.Link.ValueOrZero(), Since: args.Since, Until: args.Until.ValueOrZero(), } @@ -93,7 +111,25 @@ func (r *ContestRepository) CreateContest(ctx context.Context, args *repository. return nil, err } - err = r.h.WithContext(ctx).Create(contest).Error + err = r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx. + WithContext(ctx). + Create(contest). + Error; err != nil { + return err + } + + for i, link := range args.Links { + if err := tx. + WithContext(ctx). + Create(&model.ContestLink{ID: contest.ID, Order: i, Link: link}). + Error; err != nil { + return err + } + } + + return nil + }) if err != nil { return nil, err } @@ -107,6 +143,16 @@ func (r *ContestRepository) CreateContest(ctx context.Context, args *repository. } func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UUID, args *repository.UpdateContestArgs) error { + // コンテストの存在チェック + if err := r.h. + WithContext(ctx). + Where(&model.Contest{ID: contestID}). + First(&model.Contest{}). + Error; err != nil { + return err + } + + // リンク以外の変更確認 changes := map[string]interface{}{} if v, ok := args.Name.V(); ok { changes["name"] = v @@ -114,9 +160,6 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if v, ok := args.Description.V(); ok { changes["description"] = v } - if v, ok := args.Link.V(); ok { - changes["link"] = v - } if v, ok := args.Since.V(); ok { changes["since"] = v } @@ -124,34 +167,95 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU changes["until"] = v } - if len(changes) == 0 { - return nil - } + contestLinks := make([]*model.ContestLink, 0) + changeLinks := make(map[int]string, 0) + insertLinks := make(map[int]string, 0) + removeLinks := make([]int, 0) - var c model.Contest - err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { - if err := tx. + if afterLinks, ok := args.Links.V(); ok { + if err := r.h. WithContext(ctx). - Where(&model.Contest{ID: contestID}). - First(&model.Contest{}). + Where(&model.ContestLink{ID: contestID}). + Find(&contestLinks). Error; err != nil { - return err + if err != repository.ErrNotFound { + return err + } + } else { + sort.Slice(contestLinks, func(i, j int) bool { return contestLinks[i].Order < contestLinks[j].Order }) } - if err := tx. - WithContext(ctx). - Model(&model.Contest{ID: contestID}). - Updates(changes). - Error; err != nil { - return err + // リンクの増減を確認 + sizeBefore := len(contestLinks) + sizeAfter := len(afterLinks) + + for i := 0; i < min(sizeBefore, sizeAfter); i++ { + if contestLinks[i].Link != afterLinks[i] { + changeLinks[i] = afterLinks[i] + } } - if err := tx. - WithContext(ctx). - Where(&model.Contest{ID: contestID}). - First(&c). - Error; err != nil { - return err + if sizeBefore > sizeAfter { + for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = append(removeLinks, i) + } + } + + if sizeAfter > sizeBefore { + for i := sizeBefore; i < sizeAfter; i++ { + insertLinks[i] = afterLinks[i] + } + } + } + + err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + // リンク以外の変更 + if len(changes) != 0 { + if err := r.h. + WithContext(ctx). + Model(&model.Contest{ID: contestID}). + Updates(changes). + Error; err != nil { + return err + } + } + + // リンク変更 + if len(changeLinks) > 0 { + for i, link := range changeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ContestLink{ID: contestID, Order: i}). + Updates(&model.ContestLink{Link: link}). + Error; err != nil { + return err + } + } + } + + // リンク削除 + if len(removeLinks) != 0 { + for _, order := range removeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ContestLink{ID: contestID, Order: order}). + Delete(&model.ContestLink{}). + Error; err != nil { + return err + } + } + } + + // リンク作成 + if len(insertLinks) != 0 { + for i, insertLink := range insertLinks { + if err := tx. + WithContext(ctx). + Create(&model.ContestLink{ID: contestID, Order: i, Link: insertLink}). + Error; err != nil { + return err + } + } } return nil @@ -181,6 +285,14 @@ func (r *ContestRepository) DeleteContest(ctx context.Context, contestID uuid.UU return err } + if err := tx. + WithContext(ctx). + Where(&model.ContestLink{ID: contestID}). + Delete(&model.ContestLink{}). + Error; err != nil { + return err + } + return nil }) if err != nil { @@ -276,16 +388,30 @@ func (r *ContestRepository) GetContestTeam(ctx context.Context, contestID uuid.U } var belongings []*model.ContestTeamUserBelonging - err := r.h. + + if err := r.h. WithContext(ctx). Preload("User"). Where(&model.ContestTeamUserBelonging{TeamID: teamID}). Find(&belongings). - Error - if err != nil { + Error; err != nil { return nil, err } + teamLinks := make([]*model.ContestTeamLink, 0) + + if err := r.h. + WithContext(ctx). + Where(&model.ContestTeamLink{ID: teamID}). + Find(&teamLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return nil, err + } + } else { + sort.Slice(teamLinks, func(i, j int) bool { return teamLinks[i].Order < teamLinks[j].Order }) + } + realNameMap, err := external.GetRealNameMap(r.portal) if err != nil { return nil, err @@ -297,6 +423,11 @@ func (r *ContestRepository) GetContestTeam(ctx context.Context, contestID uuid.U members[i] = domain.NewUser(u.ID, u.Name, realNameMap[u.Name], u.Check) } + links := make([]string, len(teamLinks)) + for i, link := range teamLinks { + links[i] = link.Link + } + res := &domain.ContestTeamDetail{ ContestTeam: domain.ContestTeam{ ContestTeamWithoutMembers: domain.ContestTeamWithoutMembers{ @@ -307,7 +438,7 @@ func (r *ContestRepository) GetContestTeam(ctx context.Context, contestID uuid.U }, Members: members, }, - Link: team.Link, + Links: links, Description: team.Description, } return res, nil @@ -328,10 +459,27 @@ func (r *ContestRepository) CreateContestTeam(ctx context.Context, contestID uui Name: _contestTeam.Name, Description: _contestTeam.Description, Result: _contestTeam.Result.ValueOrZero(), - Link: _contestTeam.Link.ValueOrZero(), } - err := r.h.WithContext(ctx).Create(contestTeam).Error + err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx. + WithContext(ctx). + Create(contestTeam). + Error; err != nil { + return err + } + + for i, link := range _contestTeam.Links { + if err := tx. + WithContext(ctx). + Create(&model.ContestTeamLink{ID: contestTeam.ID, Order: i, Link: link}). + Error; err != nil { + return err + } + } + + return nil + }) if err != nil { return nil, err } @@ -346,13 +494,22 @@ func (r *ContestRepository) CreateContestTeam(ctx context.Context, contestID uui }, Members: make([]*domain.User, 0), }, - Link: contestTeam.Link, + Links: _contestTeam.Links, Description: contestTeam.Description, } return result, nil } func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.UUID, args *repository.UpdateContestTeamArgs) error { + // 存在チェック + if err := r.h. + WithContext(ctx). + Where(&model.ContestTeam{ID: teamID}). + First(&model.ContestTeam{}). + Error; err != nil { + return err + } + changes := map[string]interface{}{} if v, ok := args.Name.V(); ok { changes["name"] = v @@ -360,41 +517,100 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U if v, ok := args.Description.V(); ok { changes["description"] = v } - if v, ok := args.Link.V(); ok { - changes["link"] = v - } if v, ok := args.Result.V(); ok { changes["result"] = v } - if len(changes) == 0 { + teamLinks := make([]model.ContestTeamLink, 0) + changeLinks := make(map[int]string, 0) + insertLinks := make(map[int]string, 0) + removeLinks := make([]int, 0) + + if afterLinks, ok := args.Links.V(); ok { + if err := r.h. + WithContext(ctx). + Model(&model.ContestTeamLink{ID: teamID}). + Find(&teamLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return err + } + } else { + sort.Slice(teamLinks, func(i, j int) bool { return teamLinks[i].Order < teamLinks[j].Order }) + } + + sizeBefore := len(teamLinks) + sizeAfter := len(afterLinks) + + for i := 0; i < min(sizeBefore, sizeAfter); i++ { + if teamLinks[i].Link != afterLinks[i] { + changeLinks[i] = afterLinks[i] + } + } + + if sizeBefore > sizeAfter { + for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = append(removeLinks, i) + } + } + + if sizeAfter > sizeBefore { + for i := sizeBefore; i < sizeAfter; i++ { + insertLinks[i] = afterLinks[i] + } + } + } else if len(changes) == 0 { return nil } - var ct model.ContestTeam err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { - if err := tx. - WithContext(ctx). - Where(&model.ContestTeam{ID: teamID}). - First(&model.ContestTeam{}). - Error; err != nil { - return err + // 変更 + if len(changes) != 0 { + if err := tx. + WithContext(ctx). + Model(&model.ContestTeam{ID: teamID}). + Updates(changes). + Error; err != nil { + return err + } } - if err := tx. - WithContext(ctx). - Model(&model.ContestTeam{ID: teamID}). - Updates(changes). - Error; err != nil { - return err + // リンク変更 + if len(changeLinks) > 0 { + for i, link := range changeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ContestTeamLink{ID: teamID, Order: i}). + Updates(&model.ContestTeamLink{Link: link}). + Error; err != nil { + return err + } + } } - if err := tx. - WithContext(ctx). - Where(&model.ContestTeam{ID: teamID}). - First(&ct). - Error; err != nil { - return err + // リンク削除 + if len(removeLinks) != 0 { + for _, order := range removeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ContestTeamLink{ID: teamID, Order: order}). + Delete(&model.ContestTeamLink{}). + Error; err != nil { + return err + } + } + } + + // リンク作成 + if len(insertLinks) != 0 { + for i, insertLink := range insertLinks { + if err := tx. + WithContext(ctx). + Create(&model.ContestTeamLink{ID: teamID, Order: i, Link: insertLink}). + Error; err != nil { + return err + } + } } return nil @@ -424,6 +640,14 @@ func (r *ContestRepository) DeleteContestTeam(ctx context.Context, contestID uui return err } + if err := tx. + WithContext(ctx). + Where(&model.ContestTeamLink{ID: teamID}). + Delete(&model.ContestTeamLink{}). + Error; err != nil { + return err + } + return nil }); err != nil { return err diff --git a/internal/infrastructure/repository/contest_test.go b/internal/infrastructure/repository/contest_test.go index d1285e65..939959b9 100644 --- a/internal/infrastructure/repository/contest_test.go +++ b/internal/infrastructure/repository/contest_test.go @@ -114,7 +114,7 @@ func Test_UpdateContest(t *testing.T) { contest.Name = args.Name.ValueOr(contest.Name) contest.Description = args.Description.ValueOr(contest.Description) - contest.Link = args.Link.ValueOr(contest.Link) + contest.Links = args.Links.ValueOr(contest.Links) contest.TimeStart = args.Since.ValueOr(contest.TimeStart) contest.TimeEnd = args.Until.ValueOr(contest.TimeEnd) assert.Equal(t, contest, gotContest) @@ -254,7 +254,7 @@ func Test_UpdateContestTeam(t *testing.T) { team.Name = args.Name.ValueOr(team.Name) team.Result = args.Result.ValueOr(team.Result) - team.Link = args.Link.ValueOr(team.Link) + team.Links = args.Links.ValueOr(team.Links) team.Description = args.Description.ValueOr(team.Description) assert.Equal(t, team, gotTeam) }) diff --git a/internal/infrastructure/repository/group_impl.go b/internal/infrastructure/repository/group_impl.go index 09cd88c9..9e7535ba 100644 --- a/internal/infrastructure/repository/group_impl.go +++ b/internal/infrastructure/repository/group_impl.go @@ -2,6 +2,7 @@ package repository import ( "context" + "sort" "github.com/gofrs/uuid" "github.com/traPtitech/traPortfolio/internal/domain" @@ -54,6 +55,24 @@ func (r *GroupRepository) GetGroup(ctx context.Context, groupID uuid.UUID) (*dom return nil, err } + groupLinks := make([]model.GroupLink, 0) + if err := r.h. + WithContext(ctx). + Where(&model.GroupLink{ID: groupID}). + Find(&groupLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return nil, err + } + } else { + sort.Slice(groupLinks, func(i, j int) bool { return groupLinks[i].Order < groupLinks[j].Order }) + } + + links := make([]string, len(groupLinks)) + for i, link := range groupLinks { + links[i] = link.Link + } + // Name, RealNameはusecasesでPortalから取得する erMembers := make([]*domain.UserWithDuration, 0, len(users)) for _, v := range users { @@ -90,7 +109,7 @@ func (r *GroupRepository) GetGroup(ctx context.Context, groupID uuid.UUID) (*dom result := &domain.GroupDetail{ ID: groupID, Name: group.Name, - Link: group.Link, + Links: links, Admin: erAdmin, Members: erMembers, Description: group.Description, diff --git a/internal/infrastructure/repository/main_test.go b/internal/infrastructure/repository/main_test.go index 9110ae07..01135c7a 100644 --- a/internal/infrastructure/repository/main_test.go +++ b/internal/infrastructure/repository/main_test.go @@ -77,7 +77,7 @@ func mustMakeContest(t *testing.T, repo repository.ContestRepository, args *repo args = &repository.CreateContestArgs{ Name: random.AlphaNumeric(), Description: random.AlphaNumeric(), - Link: random.Optional(random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Since: since, Until: optional.New(until, random.Bool()), } @@ -95,7 +95,7 @@ func mustMakeContestTeam(t *testing.T, repo repository.ContestRepository, contes args = &repository.CreateContestTeamArgs{ Name: random.AlphaNumeric(), Result: random.Optional(random.AlphaNumeric()), - Link: random.Optional(random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), Description: random.AlphaNumeric(), } } @@ -166,7 +166,7 @@ func mustMakeProjectDetail(t *testing.T, repo repository.ProjectRepository, args args = &repository.CreateProjectArgs{ Name: random.AlphaNumeric(), Description: random.AlphaNumeric(), - Link: random.Optional(random.RandURLString()), + Links: random.Array(random.RandURLString, 1, 3), SinceYear: duration.Since.Year, SinceSemester: duration.Since.Semester, UntilYear: duration.Until.ValueOrZero().Year, diff --git a/internal/infrastructure/repository/model/contests.go b/internal/infrastructure/repository/model/contests.go index 2631e85e..0d4fe5c4 100644 --- a/internal/infrastructure/repository/model/contests.go +++ b/internal/infrastructure/repository/model/contests.go @@ -10,7 +10,6 @@ type Contest struct { ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` Name string `gorm:"type:varchar(128)"` Description string `gorm:"type:text"` - Link string `gorm:"type:text"` Since time.Time `gorm:"precision:6"` Until time.Time `gorm:"precision:6"` CreatedAt time.Time `gorm:"precision:6"` @@ -21,13 +20,24 @@ func (*Contest) TableName() string { return "contests" } +type ContestLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` + // 256件とかリンク追加されても困るし小さくした方がいいか…? + // Order uint8 `gorm:"type:tinyint(1);not null;primaryKey"` +} + +func (*ContestLink) TableName() string { + return "contest_links" +} + type ContestTeam struct { ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` ContestID uuid.UUID `gorm:"type:char(36);not null"` Name string `gorm:"type:varchar(128)"` Description string `gorm:"type:text"` Result string `gorm:"type:text"` - Link string `gorm:"type:text"` CreatedAt time.Time `gorm:"precision:6"` UpdatedAt time.Time `gorm:"precision:6"` @@ -51,3 +61,13 @@ type ContestTeamUserBelonging struct { func (*ContestTeamUserBelonging) TableName() string { return "contest_team_user_belongings" } + +type ContestTeamLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*ContestTeamLink) TableName() string { + return "contest_team_links" +} diff --git a/internal/infrastructure/repository/model/groups.go b/internal/infrastructure/repository/model/groups.go index 5dae3fa4..6e93e3da 100644 --- a/internal/infrastructure/repository/model/groups.go +++ b/internal/infrastructure/repository/model/groups.go @@ -9,7 +9,6 @@ import ( type Group struct { GroupID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` Name string `gorm:"type:varchar(32)"` - Link string `gorm:"type:text"` Description string `gorm:"type:text"` CreatedAt time.Time `gorm:"precision:6"` UpdatedAt time.Time `gorm:"precision:6"` @@ -49,3 +48,13 @@ type GroupUserAdmin struct { func (*GroupUserAdmin) TableName() string { return "group_user_admins" } + +type GroupLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*GroupLink) TableName() string { + return "group_links" +} diff --git a/internal/infrastructure/repository/model/project.go b/internal/infrastructure/repository/model/project.go index 9222ac08..dc758880 100644 --- a/internal/infrastructure/repository/model/project.go +++ b/internal/infrastructure/repository/model/project.go @@ -10,7 +10,6 @@ type Project struct { ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` Name string `gorm:"type:varchar(128)"` Description string `gorm:"type:text"` - Link string `gorm:"type:text"` SinceYear int `gorm:"type:smallint(4);not null"` SinceSemester int `gorm:"type:tinyint(1);not null"` UntilYear int `gorm:"type:smallint(4);not null"` @@ -40,3 +39,13 @@ type ProjectMember struct { func (*ProjectMember) TableName() string { return "project_members" } + +type ProjectLink struct { + ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` +} + +func (*ProjectLink) TableName() string { + return "project_links" +} diff --git a/internal/infrastructure/repository/project_impl.go b/internal/infrastructure/repository/project_impl.go index abd1ae8f..f7546031 100644 --- a/internal/infrastructure/repository/project_impl.go +++ b/internal/infrastructure/repository/project_impl.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "sort" "github.com/gofrs/uuid" "github.com/traPtitech/traPortfolio/internal/domain" @@ -52,16 +53,33 @@ func (r *ProjectRepository) GetProject(ctx context.Context, projectID uuid.UUID) } members := make([]*model.ProjectMember, 0) - err := r.h. + if err := r.h. WithContext(ctx). Preload("User"). Where(model.ProjectMember{ProjectID: projectID}). Find(&members). - Error - if err != nil { + Error; err != nil { return nil, err } + projectLinks := make([]model.ProjectLink, 0) + if err := r.h. + WithContext(ctx). + Where(&model.ProjectLink{ID: projectID}). + Find(&projectLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return nil, err + } + } else { + sort.Slice(projectLinks, func(i, j int) bool { return projectLinks[i].Order < projectLinks[j].Order }) + } + + links := make([]string, len(projectLinks)) + for i, link := range projectLinks { + links[i] = link.Link + } + realNameMap, err := external.GetRealNameMap(r.portal) if err != nil { return nil, err @@ -89,7 +107,7 @@ func (r *ProjectRepository) GetProject(ctx context.Context, projectID uuid.UUID) Duration: domain.NewYearWithSemesterDuration(project.SinceYear, project.SinceSemester, project.UntilYear, project.UntilSemester), }, Description: project.Description, - Link: project.Link, + Links: links, Members: m, } return res, nil @@ -105,7 +123,6 @@ func (r *ProjectRepository) CreateProject(ctx context.Context, args *repository. UntilYear: args.UntilYear, UntilSemester: args.UntilSemester, } - p.Link = args.Link.ValueOr(p.Link) // 既に同名のプロジェクトが存在するか err := r.h. @@ -119,7 +136,24 @@ func (r *ProjectRepository) CreateProject(ctx context.Context, args *repository. return nil, err } - err = r.h.WithContext(ctx).Create(&p).Error + err = r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx. + WithContext(ctx). + Create(&p). + Error; err != nil { + return err + } + + for i, link := range args.Links { + if err := tx. + WithContext(ctx). + Create(&model.ProjectLink{ID: p.ID, Order: i, Link: link}). + Error; err != nil { + return err + } + } + return nil + }) if err != nil { return nil, err } @@ -131,7 +165,7 @@ func (r *ProjectRepository) CreateProject(ctx context.Context, args *repository. Duration: domain.NewYearWithSemesterDuration(p.SinceYear, p.SinceSemester, p.UntilYear, p.UntilSemester), }, Description: p.Description, - Link: p.Link, + Links: args.Links, } return res, nil @@ -145,9 +179,6 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU if v, ok := args.Description.V(); ok { changes["description"] = v } - if v, ok := args.Link.V(); ok { - changes["link"] = v - } if sy, ok := args.SinceYear.V(); ok { if ss, ok := args.SinceSemester.V(); ok { changes["since_year"] = sy @@ -161,16 +192,107 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU } } - if len(changes) == 0 { + projectLinks := make([]model.ProjectLink, 0) + changeLinks := make(map[int]string, 0) + insertLinks := make(map[int]string, 0) + removeLinks := make([]int, 0) + + if afterLinks, ok := args.Links.V(); ok { + if err := r.h. + WithContext(ctx). + Where(&model.ProjectLink{ID: projectID}). + Find(&projectLinks). + Error; err != nil { + if err != repository.ErrNotFound { + return err + } + } else { + sort.Slice(projectLinks, func(i, j int) bool { return projectLinks[i].Order < projectLinks[j].Order }) + } + + links := make([]string, len(projectLinks)) + for i, link := range projectLinks { + links[i] = link.Link + } + + sizeBefore := len(projectLinks) + sizeAfter := len(afterLinks) + + for i := 0; i < min(sizeBefore, sizeAfter); i++ { + if projectLinks[i].Link != afterLinks[i] { + changeLinks[i] = afterLinks[i] + } + } + + if sizeBefore > sizeAfter { + for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = append(removeLinks, i) + } + } + + if sizeAfter > sizeBefore { + for i := sizeBefore; i < sizeAfter; i++ { + insertLinks[i] = afterLinks[i] + } + } + } else if len(changes) == 0 { return nil } - err := r.h. - WithContext(ctx). - Model(&model.Project{}). - Where(&model.Project{ID: projectID}). - Updates(changes). - Error + err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + // リンク以外の変更 + if len(changes) != 0 { + err := r.h. + WithContext(ctx). + Model(&model.Project{}). + Where(&model.Project{ID: projectID}). + Updates(changes). + Error + if err != nil { + return err + } + } + + // リンク変更 + if len(changeLinks) > 0 { + for i, link := range changeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ProjectLink{ID: projectID, Order: i}). + Updates(&model.ProjectLink{Link: link}). + Error; err != nil { + return err + } + } + } + + // リンク削除 + if len(removeLinks) != 0 { + for _, order := range removeLinks { + if err := tx. + WithContext(ctx). + Where(&model.ProjectLink{ID: projectID, Order: order}). + Delete(&model.ProjectLink{}). + Error; err != nil { + return err + } + } + } + + // リンク作成 + if len(insertLinks) != 0 { + for i, insertLink := range insertLinks { + if err := tx. + WithContext(ctx). + Create(&model.ProjectLink{ID: projectID, Order: i, Link: insertLink}). + Error; err != nil { + return err + } + } + } + + return nil + }) if err != nil { return err } diff --git a/internal/infrastructure/repository/project_test.go b/internal/infrastructure/repository/project_test.go index 64e95179..3fab9182 100644 --- a/internal/infrastructure/repository/project_test.go +++ b/internal/infrastructure/repository/project_test.go @@ -139,7 +139,7 @@ func TestProjectRepository_UpdateProject(t *testing.T) { project1.Name = arg1.Name.ValueOr(project1.Name) project1.Description = arg1.Description.ValueOr(project1.Description) - project1.Link = arg1.Link.ValueOr(project1.Link) + project1.Links = arg1.Links.ValueOr(project1.Links) if sy, ok := arg1.SinceYear.V(); ok { if ss, ok := arg1.SinceSemester.V(); ok { project1.Duration.Since.Year = int(sy) diff --git a/internal/pkgs/mockdata/handler.go b/internal/pkgs/mockdata/handler.go index a1db9237..cde709b2 100644 --- a/internal/pkgs/mockdata/handler.go +++ b/internal/pkgs/mockdata/handler.go @@ -30,6 +30,7 @@ var ( func CloneHandlerMockContestDetails() []schema.ContestDetail { var ( mContests = CloneMockContests() + hContestLinks = CloneHandlerMockContestLinksByID() hContestTeams = CloneMockContestTeams() hTeamMembersByID = CloneHandlerMockContestTeamMembersByID() mContestTeams = make([]schema.ContestTeam, len(hContestTeams)) @@ -50,6 +51,7 @@ func CloneHandlerMockContestDetails() []schema.ContestDetail { } for i, c := range mContests { + contestLinks := hContestLinks[c.ID] hContestDetails[i] = schema.ContestDetail{ Description: c.Description, Duration: schema.Duration{ @@ -57,7 +59,7 @@ func CloneHandlerMockContestDetails() []schema.ContestDetail { Until: &c.Until, }, Id: c.ID, - Link: c.Link, + Links: contestLinks, Name: c.Name, Teams: mContestTeams, } @@ -84,6 +86,24 @@ func CloneHandlerMockContests() []schema.Contest { return hContests } +func CloneHandlerMockContestLinksByID() map[uuid.UUID][]string { + var ( + hContests = CloneMockContests() + mockContestLinks = CloneMockContestLinks() + hContestLinks = make(map[uuid.UUID][]string, len(hContests)) + ) + + for _, c := range hContests { + hContestLinks[c.ID] = make([]string, 0) + } + + for _, link := range mockContestLinks { + hContestLinks[link.ID] = append(hContestLinks[link.ID], link.Link) + } + + return hContestLinks +} + func CloneHandlerMockContestTeamsByID() map[uuid.UUID][]schema.ContestTeam { var ( mContestTeams = CloneMockContestTeams() @@ -134,6 +154,24 @@ func CloneHandlerMockContestTeamMembersByID() map[uuid.UUID][]schema.User { return hContestMembers } +func CloneHandlerMockContestTeamLinksByID() map[uuid.UUID][]string { + var ( + hContestTeams = CloneMockContestTeams() + mockContestTeamLinks = CloneMockContestTeamLinks() + hContestTeamLinks = make(map[uuid.UUID][]string, len(hContestTeams)) + ) + + for _, c := range hContestTeams { + hContestTeamLinks[c.ID] = make([]string, 0) + } + + for _, link := range mockContestTeamLinks { + hContestTeamLinks[link.ID] = append(hContestTeamLinks[link.ID], link.Link) + } + + return hContestTeamLinks +} + func CloneHandlerMockEvents() []schema.Event { var ( eventDetails = CloneHandlerMockEventDetails() @@ -206,6 +244,7 @@ func CloneHandlerMockEventDetails() []schema.EventDetail { func CloneHandlerMockGroups() []schema.GroupDetail { var ( mGroups = CloneMockGroups() + hGroupLinks = CloneHandlerMockGroupLinksByID() hGroupsMembers = CloneHandlerMockGroupMembersByID() mGroupAdmins = CloneMockGroupUserAdmins() hGroups = make([]schema.GroupDetail, len(mGroups)) @@ -218,11 +257,12 @@ func CloneHandlerMockGroups() []schema.GroupDetail { mAdmins = append(mAdmins, getUser(adm.UserID)) } } + hLinks := hGroupLinks[g.GroupID] hGroups[i] = schema.GroupDetail{ Description: g.Description, Id: g.GroupID, Admin: mAdmins, - Link: g.Link, + Links: hLinks, Members: hGroupsMembers[g.GroupID], Name: g.Name, } @@ -264,6 +304,24 @@ func CloneHandlerMockGroupMembersByID() map[uuid.UUID][]schema.GroupMember { return hGroupMembers } +func CloneHandlerMockGroupLinksByID() map[uuid.UUID][]string { + var ( + hGroups = CloneMockGroups() + mockGroupLinks = CloneMockGroupLinks() + hGroupLinks = make(map[uuid.UUID][]string, len(hGroups)) + ) + + for _, c := range hGroups { + hGroupLinks[c.GroupID] = make([]string, 0) + } + + for _, link := range mockGroupLinks { + hGroupLinks[link.ID] = append(hGroupLinks[link.ID], link.Link) + } + + return hGroupLinks +} + func CloneHandlerMockProjects() []schema.Project { var ( mProjects = CloneMockProjects() @@ -293,12 +351,14 @@ func CloneHandlerMockProjects() []schema.Project { func CloneHandlerMockProjectDetails() []schema.ProjectDetail { var ( mProjects = CloneMockProjects() + hProjectLinks = CloneHandlerMockProjectLinksByID() hProjectMembers = CloneHandlerMockProjectMembers() mProjectMembers = CloneMockProjectMembers() hProjects = make([]schema.ProjectDetail, len(mProjects)) ) for i, mp := range mProjects { + hLinks := hProjectLinks[mp.ID] hProjects[i] = schema.ProjectDetail{ Description: mp.Description, Duration: schema.YearWithSemesterDuration{ @@ -312,7 +372,7 @@ func CloneHandlerMockProjectDetails() []schema.ProjectDetail { }, }, Id: mp.ID, - Link: mp.Link, + Links: hLinks, Members: []schema.ProjectMember{}, Name: mp.Name, } @@ -353,6 +413,24 @@ func CloneHandlerMockProjectMembers() []schema.ProjectMember { return hProjectMembers } +func CloneHandlerMockProjectLinksByID() map[uuid.UUID][]string { + var ( + hProjects = CloneMockProjects() + mockProjectLinks = CloneMockProjectLinks() + hProjectLinks = make(map[uuid.UUID][]string, len(hProjects)) + ) + + for _, c := range hProjects { + hProjectLinks[c.ID] = make([]string, 0) + } + + for _, link := range mockProjectLinks { + hProjectLinks[link.ID] = append(hProjectLinks[link.ID], link.Link) + } + + return hProjectLinks +} + func CloneHandlerMockUsers() []schema.User { var ( mUsers = CloneMockUsers() diff --git a/internal/pkgs/mockdata/model.go b/internal/pkgs/mockdata/model.go index 0d626081..72b703de 100644 --- a/internal/pkgs/mockdata/model.go +++ b/internal/pkgs/mockdata/model.go @@ -67,7 +67,6 @@ func CloneMockContests() []model.Contest { ID: ContestID1(), Name: "sample_contest_name", Description: "sample_contest_description", - Link: "https://sample.contests.com", Since: time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC), Until: time.Date(2022, 1, 2, 0, 0, 0, 0, time.UTC), }, @@ -75,7 +74,6 @@ func CloneMockContests() []model.Contest { ID: ContestID2(), Name: "sample_contest_name2", Description: "sample_contest_description2", - Link: "https://sample.contests.com", Since: time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC), Until: time.Date(2022, 1, 2, 0, 0, 0, 0, time.UTC), }, @@ -83,13 +81,37 @@ func CloneMockContests() []model.Contest { ID: ContestID3(), Name: "sample_contest_name3", Description: "sample_contest_description3", - Link: "https://sample.contests.com", Since: time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC), Until: time.Date(2022, 1, 2, 0, 0, 0, 0, time.UTC), }, } } +func CloneMockContestLinks() []model.ContestLink { + return []model.ContestLink{ + { + ID: ContestID1(), + Order: 0, + Link: "https://sample.contests1.com", + }, + { + ID: ContestID1(), + Order: 1, + Link: "https://twitter.com/contest", + }, + { + ID: ContestID2(), + Order: 0, + Link: "https://sample.contests2.com", + }, + { + ID: ContestID3(), + Order: 0, + Link: "https://sample.contests3.com", + }, + } +} + func CloneMockContestTeams() []model.ContestTeam { return []model.ContestTeam{ { @@ -98,7 +120,6 @@ func CloneMockContestTeams() []model.ContestTeam { Name: "sample_contest_team_name", Description: "sample_contest_team_description", Result: "sample_contest_team_result", - Link: "https://sample.contest_teams.com", }, { ID: ContestTeamID2(), @@ -106,7 +127,6 @@ func CloneMockContestTeams() []model.ContestTeam { Name: "sample_contest_team_name2", Description: "sample_contest_team_description2", Result: "sample_contest_team_result2", - Link: "https://sample.contest_teams.com", }, { ID: ContestTeamID3(), @@ -114,7 +134,6 @@ func CloneMockContestTeams() []model.ContestTeam { Name: "sample_contest_team_name3", Description: "sample_contest_team_description3", Result: "sample_contest_team_result3", - Link: "https://sample.contest_teams.com", }, } } @@ -128,6 +147,31 @@ func CloneMockContestTeamUserBelongings() []model.ContestTeamUserBelonging { } } +func CloneMockContestTeamLinks() []model.ContestTeamLink { + return []model.ContestTeamLink{ + { + ID: ContestTeamID1(), + Order: 0, + Link: "https://sample.contest_teams1.com", + }, + { + ID: ContestTeamID1(), + Order: 1, + Link: "https://twitter.com/contest_team1", + }, + { + ID: ContestTeamID2(), + Order: 0, + Link: "https://sample.contest_teams2.com", + }, + { + ID: ContestTeamID3(), + Order: 0, + Link: "https://sample.contest_teams3.com", + }, + } +} + func CloneMockEventLevelRelations() []model.EventLevelRelation { return []model.EventLevelRelation{ { @@ -150,7 +194,6 @@ func CloneMockGroups() []model.Group { { GroupID: GroupID1(), Name: "sample_group_name", - Link: "https://sample.groups.com", Description: "sample_group_description", }, } @@ -178,13 +221,27 @@ func CloneMockGroupUserAdmins() []model.GroupUserAdmin { } } +func CloneMockGroupLinks() []model.GroupLink { + return []model.GroupLink{ + { + ID: GroupID1(), + Order: 0, + Link: "https://sample.group1.com", + }, + { + ID: GroupID1(), + Order: 1, + Link: "https://twitter.com/group1", + }, + } +} + func CloneMockProjects() []*model.Project { return []*model.Project{ { ID: ProjectID1(), Name: "sample_project_name1", Description: "sample_project_description1", - Link: "https://sample.project1.com", SinceYear: 2021, SinceSemester: 0, UntilYear: 2021, @@ -194,7 +251,6 @@ func CloneMockProjects() []*model.Project { ID: ProjectID2(), Name: "sample_project_name2", Description: "sample_project_description2", - Link: "https://sample.project2.com", SinceYear: 2022, SinceSemester: 0, UntilYear: 2022, @@ -204,7 +260,6 @@ func CloneMockProjects() []*model.Project { ID: ProjectID3(), Name: "sample_project_name3", Description: "sample_project_description3", - Link: "https://sample.project3.com", SinceYear: 2021, SinceSemester: 0, UntilYear: 2022, @@ -242,6 +297,31 @@ func CloneMockProjectMembers() []*model.ProjectMember { } } +func CloneMockProjectLinks() []model.ProjectLink { + return []model.ProjectLink{ + { + ID: ProjectID1(), + Order: 0, + Link: "https://sample.project1.com", + }, + { + ID: ProjectID1(), + Order: 1, + Link: "https://twitter.com/project1", + }, + { + ID: ProjectID2(), + Order: 0, + Link: "https://sample.project2.com", + }, + { + ID: ProjectID3(), + Order: 0, + Link: "https://sample.project3.com", + }, + } +} + func InsertSampleDataToDB(h *gorm.DB) error { mockUsers := CloneMockUsers() if err := h.Create(&mockUsers).Error; err != nil { @@ -258,6 +338,11 @@ func InsertSampleDataToDB(h *gorm.DB) error { return err } + mockContestLinks := CloneMockContestLinks() + if err := h.Create(&mockContestLinks).Error; err != nil { + return err + } + mockContestTeams := CloneMockContestTeams() if err := h.Create(&mockContestTeams).Error; err != nil { return err @@ -268,6 +353,11 @@ func InsertSampleDataToDB(h *gorm.DB) error { return err } + mockContestTeamLinks := CloneMockContestTeamLinks() + if err := h.Create(&mockContestTeamLinks).Error; err != nil { + return err + } + mockEventLevelRelations := CloneMockEventLevelRelations() if err := h.Create(&mockEventLevelRelations).Error; err != nil { return err @@ -278,6 +368,11 @@ func InsertSampleDataToDB(h *gorm.DB) error { return err } + mockGroupLinks := CloneMockGroupLinks() + if err := h.Create(mockGroupLinks).Error; err != nil { + return err + } + mockGroupUserBelongings := CloneMockGroupUserBelongings() if err := h.Create(&mockGroupUserBelongings).Error; err != nil { return err @@ -288,6 +383,11 @@ func InsertSampleDataToDB(h *gorm.DB) error { return err } + mockProjectLinks := CloneMockProjectLinks() + if err := h.Create(&mockProjectLinks).Error; err != nil { + return err + } + mockGroupUserAdmins := CloneMockGroupUserAdmins() if err := h.Create(&mockGroupUserAdmins).Error; err != nil { return err diff --git a/internal/pkgs/random/random.go b/internal/pkgs/random/random.go index fcbb77f4..fe87a4e3 100644 --- a/internal/pkgs/random/random.go +++ b/internal/pkgs/random/random.go @@ -197,6 +197,15 @@ func Bool() bool { return rand.Int()%2 == 0 } +func Array[T any](fn func() T, min int, max int) []T { + size := rand.IntN(max-min+1) + min + ret := make([]T, size) + for i := 0; i < size; i++ { + ret[i] = fn() + } + return ret +} + func Optional[T any](t T) optional.Of[T] { return optional.New(t, Bool()) } diff --git a/internal/pkgs/random/repository.go b/internal/pkgs/random/repository.go index a355d09f..48f5ca93 100644 --- a/internal/pkgs/random/repository.go +++ b/internal/pkgs/random/repository.go @@ -14,7 +14,7 @@ func CreateContestArgs() *repository.CreateContestArgs { return &repository.CreateContestArgs{ Name: AlphaNumeric(), Description: AlphaNumeric(), - Link: Optional(RandURLString()), + Links: Array(RandURLString, 1, 3), Since: time.Now(), Until: Optional(time.Now().Add(time.Hour)), } @@ -25,7 +25,7 @@ func UpdateContestArgs() *repository.UpdateContestArgs { a := repository.UpdateContestArgs{ Name: optional.From(AlphaNumeric()), Description: optional.From(AlphaNumeric()), - Link: optional.From(RandURLString()), + Links: optional.From(Array(RandURLString, 1, 3)), Since: optional.From(Time()), Until: optional.From(Time()), } @@ -37,7 +37,7 @@ func CreateContestTeamArgs() *repository.CreateContestTeamArgs { return &repository.CreateContestTeamArgs{ Name: AlphaNumeric(), Result: Optional(AlphaNumeric()), - Link: Optional(RandURLString()), + Links: Array(RandURLString, 1, 3), Description: AlphaNumeric(), } } @@ -47,7 +47,7 @@ func UpdateContestTeamArgs() *repository.UpdateContestTeamArgs { a := repository.UpdateContestTeamArgs{ Name: optional.From(AlphaNumeric()), Result: optional.From(AlphaNumeric()), - Link: optional.From(RandURLString()), + Links: optional.From(Array(RandURLString, 1, 3)), Description: optional.From(AlphaNumeric()), } return &a @@ -58,7 +58,7 @@ func OptUpdateContestTeamArgs() *repository.UpdateContestTeamArgs { a := repository.UpdateContestTeamArgs{ Name: Optional(AlphaNumeric()), Result: Optional(AlphaNumeric()), - Link: Optional(RandURLString()), + Links: Optional(Array(RandURLString, 1, 3)), Description: Optional(AlphaNumeric()), } return &a @@ -69,7 +69,7 @@ func CreateProjectArgs() *repository.CreateProjectArgs { return &repository.CreateProjectArgs{ Name: AlphaNumeric(), Description: AlphaNumeric(), - Link: Optional(RandURLString()), + Links: Array(RandURLString, 1, 3), SinceYear: 2100, SinceSemester: 0, UntilYear: 2100, @@ -82,7 +82,7 @@ func UpdateProjectArgs() *repository.UpdateProjectArgs { a := repository.UpdateProjectArgs{ Name: optional.From(AlphaNumeric()), Description: optional.From(AlphaNumeric()), - Link: optional.From(RandURLString()), + Links: optional.From(Array(RandURLString, 1, 3)), SinceYear: optional.From(int64(2100)), // TODO: intでよさそう SinceSemester: optional.From(int64(0)), UntilYear: optional.From(int64(2100)), @@ -96,7 +96,7 @@ func OptUpdateProjectArgs() *repository.UpdateProjectArgs { a := repository.UpdateProjectArgs{ Name: Optional(AlphaNumeric()), Description: Optional(AlphaNumeric()), - Link: Optional(AlphaNumeric()), + Links: Optional(Array(RandURLString, 1, 3)), SinceYear: Optional(int64(2100)), // TODO: intでよさそう SinceSemester: Optional(int64(0)), UntilYear: Optional(int64(2100)), diff --git a/internal/usecases/repository/contest_repository.go b/internal/usecases/repository/contest_repository.go index 6cff728d..925827d6 100644 --- a/internal/usecases/repository/contest_repository.go +++ b/internal/usecases/repository/contest_repository.go @@ -16,7 +16,7 @@ import ( type CreateContestArgs struct { Name string Description string - Link optional.Of[string] + Links []string Since time.Time Until optional.Of[time.Time] } @@ -24,7 +24,7 @@ type CreateContestArgs struct { type UpdateContestArgs struct { Name optional.Of[string] Description optional.Of[string] - Link optional.Of[string] + Links optional.Of[[]string] Since optional.Of[time.Time] Until optional.Of[time.Time] } @@ -32,14 +32,14 @@ type UpdateContestArgs struct { type CreateContestTeamArgs struct { Name string Result optional.Of[string] - Link optional.Of[string] + Links []string Description string } type UpdateContestTeamArgs struct { Name optional.Of[string] Result optional.Of[string] - Link optional.Of[string] + Links optional.Of[[]string] Description optional.Of[string] } diff --git a/internal/usecases/repository/mock_repository/mock_project_repository.go b/internal/usecases/repository/mock_repository/mock_project_repository.go index 9626c3bb..939496d1 100644 --- a/internal/usecases/repository/mock_repository/mock_project_repository.go +++ b/internal/usecases/repository/mock_repository/mock_project_repository.go @@ -90,9 +90,33 @@ func (m *MockProjectRepository) DeleteProject(ctx context.Context, projectID uui } // DeleteProject indicates an expected call of DeleteProject. -func (mr *MockProjectRepositoryMockRecorder) DeleteProject(ctx, projectID interface{}) *gomock.Call { +func (mr *MockProjectRepositoryMockRecorder) DeleteProject(ctx, projectID any) *MockProjectRepositoryDeleteProjectCall { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProject", reflect.TypeOf((*MockProjectRepository)(nil).DeleteProject), ctx, projectID) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProject", reflect.TypeOf((*MockProjectRepository)(nil).DeleteProject), ctx, projectID) + return &MockProjectRepositoryDeleteProjectCall{Call: call} +} + +// MockProjectRepositoryDeleteProjectCall wrap *gomock.Call +type MockProjectRepositoryDeleteProjectCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryDeleteProjectCall) Return(arg0 error) *MockProjectRepositoryDeleteProjectCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryDeleteProjectCall) Do(f func(context.Context, uuid.UUID) error) *MockProjectRepositoryDeleteProjectCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryDeleteProjectCall) DoAndReturn(f func(context.Context, uuid.UUID) error) *MockProjectRepositoryDeleteProjectCall { + c.Call = c.Call.DoAndReturn(f) + return c } // EditProjectMembers mocks base method. diff --git a/internal/usecases/repository/project_repository.go b/internal/usecases/repository/project_repository.go index f7110df2..245ce8a7 100644 --- a/internal/usecases/repository/project_repository.go +++ b/internal/usecases/repository/project_repository.go @@ -13,7 +13,7 @@ import ( type CreateProjectArgs struct { Name string Description string - Link optional.Of[string] + Links []string SinceYear int SinceSemester int UntilYear int @@ -23,7 +23,7 @@ type CreateProjectArgs struct { type UpdateProjectArgs struct { Name optional.Of[string] Description optional.Of[string] - Link optional.Of[string] + Links optional.Of[[]string] SinceYear optional.Of[int64] SinceSemester optional.Of[int64] UntilYear optional.Of[int64] From ca42f6584a2e21df64a36cf05aeb8c9da8514115 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 14 Oct 2024 22:26:58 +0900 Subject: [PATCH 2/5] fix: change table column name --- internal/infrastructure/migration/v3.go | 48 +++++------ .../infrastructure/repository/contest_impl.go | 28 +++---- .../infrastructure/repository/group_impl.go | 2 +- .../repository/model/contests.go | 12 +-- .../infrastructure/repository/model/groups.go | 6 +- .../repository/model/project.go | 6 +- .../infrastructure/repository/project_impl.go | 12 +-- internal/pkgs/mockdata/handler.go | 8 +- internal/pkgs/mockdata/model.go | 84 +++++++++---------- 9 files changed, 103 insertions(+), 103 deletions(-) diff --git a/internal/infrastructure/migration/v3.go b/internal/infrastructure/migration/v3.go index 59eefeec..f1da726c 100644 --- a/internal/infrastructure/migration/v3.go +++ b/internal/infrastructure/migration/v3.go @@ -28,9 +28,9 @@ func v3() *gormigrate.Migration { for _, contest := range contests { contestLink := v3ContestLink{ - ID: contest.ID, - Order: 0, - Link: contest.Link, + ContestID: contest.ID, + Order: 0, + Link: contest.Link, } if err := db.Create(&contestLink).Error; err != nil { return err @@ -51,9 +51,9 @@ func v3() *gormigrate.Migration { for _, contestTeam := range contestTeams { teamLink := v3ContestTeamLink{ - ID: contestTeam.ID, - Order: 0, - Link: contestTeam.Link, + ContestTeamID: contestTeam.ID, + Order: 0, + Link: contestTeam.Link, } if err := db.Create(&teamLink).Error; err != nil { return err @@ -74,9 +74,9 @@ func v3() *gormigrate.Migration { for _, group := range groups { groupLink := v3GroupLink{ - ID: group.GroupID, - Order: 0, - Link: group.Link, + GroupID: group.GroupID, + Order: 0, + Link: group.Link, } if err := db.Create(&groupLink).Error; err != nil { return err @@ -97,9 +97,9 @@ func v3() *gormigrate.Migration { for _, project := range projects { projectLink := v3ProjectLink{ - ID: project.ID, - Order: 0, - Link: project.Link, + ProjectID: project.ID, + Order: 0, + Link: project.Link, } if err := db.Create(&projectLink).Error; err != nil { return err @@ -134,9 +134,9 @@ func (*v3OldContest) TableName() string { } type v3ContestLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ContestID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*v3ContestLink) TableName() string { @@ -161,9 +161,9 @@ func (*v3OldContestTeam) TableName() string { } type v3ContestTeamLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ContestTeamID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*v3ContestTeamLink) TableName() string { @@ -184,9 +184,9 @@ func (*v3OldGroup) TableName() string { } type v3GroupLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + GroupID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*v3GroupLink) TableName() string { @@ -211,9 +211,9 @@ func (*v3OldProject) TableName() string { } type v3ProjectLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ProjectID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*v3ProjectLink) TableName() string { diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index c574179c..59f0686e 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -60,7 +60,7 @@ func (r *ContestRepository) getContest(ctx context.Context, contestID uuid.UUID) contestLinks := make([]*model.ContestLink, 0) if err := r.h. WithContext(ctx). - Where(&model.ContestLink{ID: contestID}). + Where(&model.ContestLink{ContestID: contestID}). Find(&contestLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -122,7 +122,7 @@ func (r *ContestRepository) CreateContest(ctx context.Context, args *repository. for i, link := range args.Links { if err := tx. WithContext(ctx). - Create(&model.ContestLink{ID: contest.ID, Order: i, Link: link}). + Create(&model.ContestLink{ContestID: contest.ID, Order: i, Link: link}). Error; err != nil { return err } @@ -175,7 +175,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if afterLinks, ok := args.Links.V(); ok { if err := r.h. WithContext(ctx). - Where(&model.ContestLink{ID: contestID}). + Where(&model.ContestLink{ContestID: contestID}). Find(&contestLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -225,7 +225,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU for i, link := range changeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestLink{ID: contestID, Order: i}). + Where(&model.ContestLink{ContestID: contestID, Order: i}). Updates(&model.ContestLink{Link: link}). Error; err != nil { return err @@ -238,7 +238,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU for _, order := range removeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestLink{ID: contestID, Order: order}). + Where(&model.ContestLink{ContestID: contestID, Order: order}). Delete(&model.ContestLink{}). Error; err != nil { return err @@ -251,7 +251,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU for i, insertLink := range insertLinks { if err := tx. WithContext(ctx). - Create(&model.ContestLink{ID: contestID, Order: i, Link: insertLink}). + Create(&model.ContestLink{ContestID: contestID, Order: i, Link: insertLink}). Error; err != nil { return err } @@ -287,7 +287,7 @@ func (r *ContestRepository) DeleteContest(ctx context.Context, contestID uuid.UU if err := tx. WithContext(ctx). - Where(&model.ContestLink{ID: contestID}). + Where(&model.ContestLink{ContestID: contestID}). Delete(&model.ContestLink{}). Error; err != nil { return err @@ -402,7 +402,7 @@ func (r *ContestRepository) GetContestTeam(ctx context.Context, contestID uuid.U if err := r.h. WithContext(ctx). - Where(&model.ContestTeamLink{ID: teamID}). + Where(&model.ContestTeamLink{ContestID: teamID}). Find(&teamLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -472,7 +472,7 @@ func (r *ContestRepository) CreateContestTeam(ctx context.Context, contestID uui for i, link := range _contestTeam.Links { if err := tx. WithContext(ctx). - Create(&model.ContestTeamLink{ID: contestTeam.ID, Order: i, Link: link}). + Create(&model.ContestTeamLink{ContestID: contestTeam.ID, Order: i, Link: link}). Error; err != nil { return err } @@ -529,7 +529,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U if afterLinks, ok := args.Links.V(); ok { if err := r.h. WithContext(ctx). - Model(&model.ContestTeamLink{ID: teamID}). + Model(&model.ContestTeamLink{ContestID: teamID}). Find(&teamLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -580,7 +580,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for i, link := range changeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ID: teamID, Order: i}). + Where(&model.ContestTeamLink{ContestID: teamID, Order: i}). Updates(&model.ContestTeamLink{Link: link}). Error; err != nil { return err @@ -593,7 +593,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for _, order := range removeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ID: teamID, Order: order}). + Where(&model.ContestTeamLink{ContestID: teamID, Order: order}). Delete(&model.ContestTeamLink{}). Error; err != nil { return err @@ -606,7 +606,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for i, insertLink := range insertLinks { if err := tx. WithContext(ctx). - Create(&model.ContestTeamLink{ID: teamID, Order: i, Link: insertLink}). + Create(&model.ContestTeamLink{ContestID: teamID, Order: i, Link: insertLink}). Error; err != nil { return err } @@ -642,7 +642,7 @@ func (r *ContestRepository) DeleteContestTeam(ctx context.Context, contestID uui if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ID: teamID}). + Where(&model.ContestTeamLink{ContestID: teamID}). Delete(&model.ContestTeamLink{}). Error; err != nil { return err diff --git a/internal/infrastructure/repository/group_impl.go b/internal/infrastructure/repository/group_impl.go index 9e7535ba..183e15bb 100644 --- a/internal/infrastructure/repository/group_impl.go +++ b/internal/infrastructure/repository/group_impl.go @@ -58,7 +58,7 @@ func (r *GroupRepository) GetGroup(ctx context.Context, groupID uuid.UUID) (*dom groupLinks := make([]model.GroupLink, 0) if err := r.h. WithContext(ctx). - Where(&model.GroupLink{ID: groupID}). + Where(&model.GroupLink{GroupID: groupID}). Find(&groupLinks). Error; err != nil { if err != repository.ErrNotFound { diff --git a/internal/infrastructure/repository/model/contests.go b/internal/infrastructure/repository/model/contests.go index 0d4fe5c4..42f965d7 100644 --- a/internal/infrastructure/repository/model/contests.go +++ b/internal/infrastructure/repository/model/contests.go @@ -21,9 +21,9 @@ func (*Contest) TableName() string { } type ContestLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ContestID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` // 256件とかリンク追加されても困るし小さくした方がいいか…? // Order uint8 `gorm:"type:tinyint(1);not null;primaryKey"` } @@ -63,9 +63,9 @@ func (*ContestTeamUserBelonging) TableName() string { } type ContestTeamLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ContestID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*ContestTeamLink) TableName() string { diff --git a/internal/infrastructure/repository/model/groups.go b/internal/infrastructure/repository/model/groups.go index 6e93e3da..dfe5074e 100644 --- a/internal/infrastructure/repository/model/groups.go +++ b/internal/infrastructure/repository/model/groups.go @@ -50,9 +50,9 @@ func (*GroupUserAdmin) TableName() string { } type GroupLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + GroupID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*GroupLink) TableName() string { diff --git a/internal/infrastructure/repository/model/project.go b/internal/infrastructure/repository/model/project.go index dc758880..0e7fc239 100644 --- a/internal/infrastructure/repository/model/project.go +++ b/internal/infrastructure/repository/model/project.go @@ -41,9 +41,9 @@ func (*ProjectMember) TableName() string { } type ProjectLink struct { - ID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + ProjectID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*ProjectLink) TableName() string { diff --git a/internal/infrastructure/repository/project_impl.go b/internal/infrastructure/repository/project_impl.go index f7546031..a9ddb0dc 100644 --- a/internal/infrastructure/repository/project_impl.go +++ b/internal/infrastructure/repository/project_impl.go @@ -65,7 +65,7 @@ func (r *ProjectRepository) GetProject(ctx context.Context, projectID uuid.UUID) projectLinks := make([]model.ProjectLink, 0) if err := r.h. WithContext(ctx). - Where(&model.ProjectLink{ID: projectID}). + Where(&model.ProjectLink{ProjectID: projectID}). Find(&projectLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -147,7 +147,7 @@ func (r *ProjectRepository) CreateProject(ctx context.Context, args *repository. for i, link := range args.Links { if err := tx. WithContext(ctx). - Create(&model.ProjectLink{ID: p.ID, Order: i, Link: link}). + Create(&model.ProjectLink{ProjectID: p.ID, Order: i, Link: link}). Error; err != nil { return err } @@ -200,7 +200,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU if afterLinks, ok := args.Links.V(); ok { if err := r.h. WithContext(ctx). - Where(&model.ProjectLink{ID: projectID}). + Where(&model.ProjectLink{ProjectID: projectID}). Find(&projectLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -258,7 +258,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU for i, link := range changeLinks { if err := tx. WithContext(ctx). - Where(&model.ProjectLink{ID: projectID, Order: i}). + Where(&model.ProjectLink{ProjectID: projectID, Order: i}). Updates(&model.ProjectLink{Link: link}). Error; err != nil { return err @@ -271,7 +271,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU for _, order := range removeLinks { if err := tx. WithContext(ctx). - Where(&model.ProjectLink{ID: projectID, Order: order}). + Where(&model.ProjectLink{ProjectID: projectID, Order: order}). Delete(&model.ProjectLink{}). Error; err != nil { return err @@ -284,7 +284,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU for i, insertLink := range insertLinks { if err := tx. WithContext(ctx). - Create(&model.ProjectLink{ID: projectID, Order: i, Link: insertLink}). + Create(&model.ProjectLink{ProjectID: projectID, Order: i, Link: insertLink}). Error; err != nil { return err } diff --git a/internal/pkgs/mockdata/handler.go b/internal/pkgs/mockdata/handler.go index cde709b2..9fae343a 100644 --- a/internal/pkgs/mockdata/handler.go +++ b/internal/pkgs/mockdata/handler.go @@ -98,7 +98,7 @@ func CloneHandlerMockContestLinksByID() map[uuid.UUID][]string { } for _, link := range mockContestLinks { - hContestLinks[link.ID] = append(hContestLinks[link.ID], link.Link) + hContestLinks[link.ContestID] = append(hContestLinks[link.ContestID], link.Link) } return hContestLinks @@ -166,7 +166,7 @@ func CloneHandlerMockContestTeamLinksByID() map[uuid.UUID][]string { } for _, link := range mockContestTeamLinks { - hContestTeamLinks[link.ID] = append(hContestTeamLinks[link.ID], link.Link) + hContestTeamLinks[link.ContestID] = append(hContestTeamLinks[link.ContestID], link.Link) } return hContestTeamLinks @@ -316,7 +316,7 @@ func CloneHandlerMockGroupLinksByID() map[uuid.UUID][]string { } for _, link := range mockGroupLinks { - hGroupLinks[link.ID] = append(hGroupLinks[link.ID], link.Link) + hGroupLinks[link.GroupID] = append(hGroupLinks[link.GroupID], link.Link) } return hGroupLinks @@ -425,7 +425,7 @@ func CloneHandlerMockProjectLinksByID() map[uuid.UUID][]string { } for _, link := range mockProjectLinks { - hProjectLinks[link.ID] = append(hProjectLinks[link.ID], link.Link) + hProjectLinks[link.ProjectID] = append(hProjectLinks[link.ProjectID], link.Link) } return hProjectLinks diff --git a/internal/pkgs/mockdata/model.go b/internal/pkgs/mockdata/model.go index 72b703de..df52e5ea 100644 --- a/internal/pkgs/mockdata/model.go +++ b/internal/pkgs/mockdata/model.go @@ -90,24 +90,24 @@ func CloneMockContests() []model.Contest { func CloneMockContestLinks() []model.ContestLink { return []model.ContestLink{ { - ID: ContestID1(), - Order: 0, - Link: "https://sample.contests1.com", + ContestID: ContestID1(), + Order: 0, + Link: "https://sample.contests1.com", }, { - ID: ContestID1(), - Order: 1, - Link: "https://twitter.com/contest", + ContestID: ContestID1(), + Order: 1, + Link: "https://twitter.com/contest", }, { - ID: ContestID2(), - Order: 0, - Link: "https://sample.contests2.com", + ContestID: ContestID2(), + Order: 0, + Link: "https://sample.contests2.com", }, { - ID: ContestID3(), - Order: 0, - Link: "https://sample.contests3.com", + ContestID: ContestID3(), + Order: 0, + Link: "https://sample.contests3.com", }, } } @@ -150,24 +150,24 @@ func CloneMockContestTeamUserBelongings() []model.ContestTeamUserBelonging { func CloneMockContestTeamLinks() []model.ContestTeamLink { return []model.ContestTeamLink{ { - ID: ContestTeamID1(), - Order: 0, - Link: "https://sample.contest_teams1.com", + ContestID: ContestTeamID1(), + Order: 0, + Link: "https://sample.contest_teams1.com", }, { - ID: ContestTeamID1(), - Order: 1, - Link: "https://twitter.com/contest_team1", + ContestID: ContestTeamID1(), + Order: 1, + Link: "https://twitter.com/contest_team1", }, { - ID: ContestTeamID2(), - Order: 0, - Link: "https://sample.contest_teams2.com", + ContestID: ContestTeamID2(), + Order: 0, + Link: "https://sample.contest_teams2.com", }, { - ID: ContestTeamID3(), - Order: 0, - Link: "https://sample.contest_teams3.com", + ContestID: ContestTeamID3(), + Order: 0, + Link: "https://sample.contest_teams3.com", }, } } @@ -224,14 +224,14 @@ func CloneMockGroupUserAdmins() []model.GroupUserAdmin { func CloneMockGroupLinks() []model.GroupLink { return []model.GroupLink{ { - ID: GroupID1(), - Order: 0, - Link: "https://sample.group1.com", + GroupID: GroupID1(), + Order: 0, + Link: "https://sample.group1.com", }, { - ID: GroupID1(), - Order: 1, - Link: "https://twitter.com/group1", + GroupID: GroupID1(), + Order: 1, + Link: "https://twitter.com/group1", }, } } @@ -300,24 +300,24 @@ func CloneMockProjectMembers() []*model.ProjectMember { func CloneMockProjectLinks() []model.ProjectLink { return []model.ProjectLink{ { - ID: ProjectID1(), - Order: 0, - Link: "https://sample.project1.com", + ProjectID: ProjectID1(), + Order: 0, + Link: "https://sample.project1.com", }, { - ID: ProjectID1(), - Order: 1, - Link: "https://twitter.com/project1", + ProjectID: ProjectID1(), + Order: 1, + Link: "https://twitter.com/project1", }, { - ID: ProjectID2(), - Order: 0, - Link: "https://sample.project2.com", + ProjectID: ProjectID2(), + Order: 0, + Link: "https://sample.project2.com", }, { - ID: ProjectID3(), - Order: 0, - Link: "https://sample.project3.com", + ProjectID: ProjectID3(), + Order: 0, + Link: "https://sample.project3.com", }, } } From 80b240971e04b3860bbe506bfc94ba2195306979 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 14 Oct 2024 22:29:52 +0900 Subject: [PATCH 3/5] fix: contest_team_id -> team_id --- internal/infrastructure/migration/v3.go | 12 +++++----- .../infrastructure/repository/contest_impl.go | 14 +++++------ .../repository/model/contests.go | 6 ++--- internal/pkgs/mockdata/handler.go | 2 +- internal/pkgs/mockdata/model.go | 24 +++++++++---------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/internal/infrastructure/migration/v3.go b/internal/infrastructure/migration/v3.go index f1da726c..4cf8dcc6 100644 --- a/internal/infrastructure/migration/v3.go +++ b/internal/infrastructure/migration/v3.go @@ -51,9 +51,9 @@ func v3() *gormigrate.Migration { for _, contestTeam := range contestTeams { teamLink := v3ContestTeamLink{ - ContestTeamID: contestTeam.ID, - Order: 0, - Link: contestTeam.Link, + TeamID: contestTeam.ID, + Order: 0, + Link: contestTeam.Link, } if err := db.Create(&teamLink).Error; err != nil { return err @@ -161,9 +161,9 @@ func (*v3OldContestTeam) TableName() string { } type v3ContestTeamLink struct { - ContestTeamID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + TeamID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*v3ContestTeamLink) TableName() string { diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 59f0686e..165399a9 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -402,7 +402,7 @@ func (r *ContestRepository) GetContestTeam(ctx context.Context, contestID uuid.U if err := r.h. WithContext(ctx). - Where(&model.ContestTeamLink{ContestID: teamID}). + Where(&model.ContestTeamLink{TeamID: teamID}). Find(&teamLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -472,7 +472,7 @@ func (r *ContestRepository) CreateContestTeam(ctx context.Context, contestID uui for i, link := range _contestTeam.Links { if err := tx. WithContext(ctx). - Create(&model.ContestTeamLink{ContestID: contestTeam.ID, Order: i, Link: link}). + Create(&model.ContestTeamLink{TeamID: contestTeam.ID, Order: i, Link: link}). Error; err != nil { return err } @@ -529,7 +529,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U if afterLinks, ok := args.Links.V(); ok { if err := r.h. WithContext(ctx). - Model(&model.ContestTeamLink{ContestID: teamID}). + Model(&model.ContestTeamLink{TeamID: teamID}). Find(&teamLinks). Error; err != nil { if err != repository.ErrNotFound { @@ -580,7 +580,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for i, link := range changeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ContestID: teamID, Order: i}). + Where(&model.ContestTeamLink{TeamID: teamID, Order: i}). Updates(&model.ContestTeamLink{Link: link}). Error; err != nil { return err @@ -593,7 +593,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for _, order := range removeLinks { if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ContestID: teamID, Order: order}). + Where(&model.ContestTeamLink{TeamID: teamID, Order: order}). Delete(&model.ContestTeamLink{}). Error; err != nil { return err @@ -606,7 +606,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U for i, insertLink := range insertLinks { if err := tx. WithContext(ctx). - Create(&model.ContestTeamLink{ContestID: teamID, Order: i, Link: insertLink}). + Create(&model.ContestTeamLink{TeamID: teamID, Order: i, Link: insertLink}). Error; err != nil { return err } @@ -642,7 +642,7 @@ func (r *ContestRepository) DeleteContestTeam(ctx context.Context, contestID uui if err := tx. WithContext(ctx). - Where(&model.ContestTeamLink{ContestID: teamID}). + Where(&model.ContestTeamLink{TeamID: teamID}). Delete(&model.ContestTeamLink{}). Error; err != nil { return err diff --git a/internal/infrastructure/repository/model/contests.go b/internal/infrastructure/repository/model/contests.go index 42f965d7..159aabb0 100644 --- a/internal/infrastructure/repository/model/contests.go +++ b/internal/infrastructure/repository/model/contests.go @@ -63,9 +63,9 @@ func (*ContestTeamUserBelonging) TableName() string { } type ContestTeamLink struct { - ContestID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` - Order int `gorm:"type:int;not null;primaryKey"` - Link string `gorm:"type:text;not null"` + TeamID uuid.UUID `gorm:"type:char(36);not null;primaryKey"` + Order int `gorm:"type:int;not null;primaryKey"` + Link string `gorm:"type:text;not null"` } func (*ContestTeamLink) TableName() string { diff --git a/internal/pkgs/mockdata/handler.go b/internal/pkgs/mockdata/handler.go index 9fae343a..947e7387 100644 --- a/internal/pkgs/mockdata/handler.go +++ b/internal/pkgs/mockdata/handler.go @@ -166,7 +166,7 @@ func CloneHandlerMockContestTeamLinksByID() map[uuid.UUID][]string { } for _, link := range mockContestTeamLinks { - hContestTeamLinks[link.ContestID] = append(hContestTeamLinks[link.ContestID], link.Link) + hContestTeamLinks[link.TeamID] = append(hContestTeamLinks[link.TeamID], link.Link) } return hContestTeamLinks diff --git a/internal/pkgs/mockdata/model.go b/internal/pkgs/mockdata/model.go index df52e5ea..74e79f90 100644 --- a/internal/pkgs/mockdata/model.go +++ b/internal/pkgs/mockdata/model.go @@ -150,24 +150,24 @@ func CloneMockContestTeamUserBelongings() []model.ContestTeamUserBelonging { func CloneMockContestTeamLinks() []model.ContestTeamLink { return []model.ContestTeamLink{ { - ContestID: ContestTeamID1(), - Order: 0, - Link: "https://sample.contest_teams1.com", + TeamID: ContestTeamID1(), + Order: 0, + Link: "https://sample.contest_teams1.com", }, { - ContestID: ContestTeamID1(), - Order: 1, - Link: "https://twitter.com/contest_team1", + TeamID: ContestTeamID1(), + Order: 1, + Link: "https://twitter.com/contest_team1", }, { - ContestID: ContestTeamID2(), - Order: 0, - Link: "https://sample.contest_teams2.com", + TeamID: ContestTeamID2(), + Order: 0, + Link: "https://sample.contest_teams2.com", }, { - ContestID: ContestTeamID3(), - Order: 0, - Link: "https://sample.contest_teams3.com", + TeamID: ContestTeamID3(), + Order: 0, + Link: "https://sample.contest_teams3.com", }, } } From 44fe785a3a57f2a101f2dcbc659c8486c4d8b1dc Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 14 Oct 2024 22:56:41 +0900 Subject: [PATCH 4/5] improve: elements == capacity --- .../infrastructure/repository/contest_impl.go | 65 +++++++++++-------- .../infrastructure/repository/project_impl.go | 37 ++++++----- 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 165399a9..2750d25d 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -167,12 +167,12 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU changes["until"] = v } - contestLinks := make([]*model.ContestLink, 0) - changeLinks := make(map[int]string, 0) - insertLinks := make(map[int]string, 0) - removeLinks := make([]int, 0) + var changeLinkMap map[int]string + var insertLinkMap map[int]string + var removeLinks []int if afterLinks, ok := args.Links.V(); ok { + var contestLinks []model.ContestLink if err := r.h. WithContext(ctx). Where(&model.ContestLink{ContestID: contestID}). @@ -185,25 +185,30 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU sort.Slice(contestLinks, func(i, j int) bool { return contestLinks[i].Order < contestLinks[j].Order }) } - // リンクの増減を確認 sizeBefore := len(contestLinks) sizeAfter := len(afterLinks) + sizeChange := min(sizeBefore, sizeAfter) + + changeLinkMap = make(map[int]string, sizeChange) - for i := 0; i < min(sizeBefore, sizeAfter); i++ { + i := 0 + for ; i < sizeChange; i++ { if contestLinks[i].Link != afterLinks[i] { - changeLinks[i] = afterLinks[i] + changeLinkMap[i] = afterLinks[i] } } if sizeBefore > sizeAfter { - for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = make([]int, sizeBefore-sizeAfter) + for ; i < sizeBefore; i++ { removeLinks = append(removeLinks, i) } } if sizeAfter > sizeBefore { - for i := sizeBefore; i < sizeAfter; i++ { - insertLinks[i] = afterLinks[i] + insertLinkMap = make(map[int]string, sizeAfter-sizeBefore) + for ; i < sizeAfter; i++ { + insertLinkMap[i] = afterLinks[i] } } } @@ -221,8 +226,8 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU } // リンク変更 - if len(changeLinks) > 0 { - for i, link := range changeLinks { + if len(changeLinkMap) > 0 { + for i, link := range changeLinkMap { if err := tx. WithContext(ctx). Where(&model.ContestLink{ContestID: contestID, Order: i}). @@ -247,8 +252,8 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU } // リンク作成 - if len(insertLinks) != 0 { - for i, insertLink := range insertLinks { + if len(insertLinkMap) != 0 { + for i, insertLink := range insertLinkMap { if err := tx. WithContext(ctx). Create(&model.ContestLink{ContestID: contestID, Order: i, Link: insertLink}). @@ -521,12 +526,12 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U changes["result"] = v } - teamLinks := make([]model.ContestTeamLink, 0) - changeLinks := make(map[int]string, 0) - insertLinks := make(map[int]string, 0) - removeLinks := make([]int, 0) + var changeLinkMap map[int]string + var insertLinkMap map[int]string + var removeLinks []int if afterLinks, ok := args.Links.V(); ok { + var teamLinks []model.ContestTeamLink if err := r.h. WithContext(ctx). Model(&model.ContestTeamLink{TeamID: teamID}). @@ -541,22 +546,28 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U sizeBefore := len(teamLinks) sizeAfter := len(afterLinks) + sizeChange := min(sizeBefore, sizeAfter) + + changeLinkMap = make(map[int]string, sizeChange) - for i := 0; i < min(sizeBefore, sizeAfter); i++ { + i := 0 + for ; i < sizeChange; i++ { if teamLinks[i].Link != afterLinks[i] { - changeLinks[i] = afterLinks[i] + changeLinkMap[i] = afterLinks[i] } } if sizeBefore > sizeAfter { - for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = make([]int, sizeBefore-sizeAfter) + for ; i < sizeBefore; i++ { removeLinks = append(removeLinks, i) } } if sizeAfter > sizeBefore { - for i := sizeBefore; i < sizeAfter; i++ { - insertLinks[i] = afterLinks[i] + insertLinkMap = make(map[int]string, sizeAfter-sizeBefore) + for ; i < sizeAfter; i++ { + insertLinkMap[i] = afterLinks[i] } } } else if len(changes) == 0 { @@ -576,8 +587,8 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U } // リンク変更 - if len(changeLinks) > 0 { - for i, link := range changeLinks { + if len(changeLinkMap) > 0 { + for i, link := range changeLinkMap { if err := tx. WithContext(ctx). Where(&model.ContestTeamLink{TeamID: teamID, Order: i}). @@ -602,8 +613,8 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U } // リンク作成 - if len(insertLinks) != 0 { - for i, insertLink := range insertLinks { + if len(insertLinkMap) != 0 { + for i, insertLink := range insertLinkMap { if err := tx. WithContext(ctx). Create(&model.ContestTeamLink{TeamID: teamID, Order: i, Link: insertLink}). diff --git a/internal/infrastructure/repository/project_impl.go b/internal/infrastructure/repository/project_impl.go index a9ddb0dc..154d6878 100644 --- a/internal/infrastructure/repository/project_impl.go +++ b/internal/infrastructure/repository/project_impl.go @@ -192,12 +192,12 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU } } - projectLinks := make([]model.ProjectLink, 0) - changeLinks := make(map[int]string, 0) - insertLinks := make(map[int]string, 0) - removeLinks := make([]int, 0) + var changeLinkMap map[int]string + var insertLinkMap map[int]string + var removeLinks []int if afterLinks, ok := args.Links.V(); ok { + var projectLinks []model.ProjectLink if err := r.h. WithContext(ctx). Where(&model.ProjectLink{ProjectID: projectID}). @@ -210,29 +210,30 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU sort.Slice(projectLinks, func(i, j int) bool { return projectLinks[i].Order < projectLinks[j].Order }) } - links := make([]string, len(projectLinks)) - for i, link := range projectLinks { - links[i] = link.Link - } - sizeBefore := len(projectLinks) sizeAfter := len(afterLinks) + sizeChange := min(sizeBefore, sizeAfter) + + changeLinkMap = make(map[int]string, sizeChange) - for i := 0; i < min(sizeBefore, sizeAfter); i++ { + i := 0 + for ; i < sizeChange; i++ { if projectLinks[i].Link != afterLinks[i] { - changeLinks[i] = afterLinks[i] + changeLinkMap[i] = afterLinks[i] } } if sizeBefore > sizeAfter { - for i := sizeAfter; i < sizeBefore; i++ { + removeLinks = make([]int, sizeBefore-sizeAfter) + for ; i < sizeBefore; i++ { removeLinks = append(removeLinks, i) } } if sizeAfter > sizeBefore { - for i := sizeBefore; i < sizeAfter; i++ { - insertLinks[i] = afterLinks[i] + insertLinkMap = make(map[int]string, sizeAfter-sizeBefore) + for ; i < sizeAfter; i++ { + insertLinkMap[i] = afterLinks[i] } } } else if len(changes) == 0 { @@ -254,8 +255,8 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU } // リンク変更 - if len(changeLinks) > 0 { - for i, link := range changeLinks { + if len(changeLinkMap) > 0 { + for i, link := range changeLinkMap { if err := tx. WithContext(ctx). Where(&model.ProjectLink{ProjectID: projectID, Order: i}). @@ -280,8 +281,8 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU } // リンク作成 - if len(insertLinks) != 0 { - for i, insertLink := range insertLinks { + if len(insertLinkMap) != 0 { + for i, insertLink := range insertLinkMap { if err := tx. WithContext(ctx). Create(&model.ProjectLink{ProjectID: projectID, Order: i, Link: insertLink}). From a49a66f9c19e699067743fbc63f07817911aff91 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Thu, 17 Oct 2024 22:02:25 +0900 Subject: [PATCH 5/5] fix: bad change links --- internal/infrastructure/repository/contest_impl.go | 8 ++++---- internal/infrastructure/repository/project_impl.go | 4 ++-- internal/pkgs/random/repository.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 2750d25d..e234ac9a 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -201,7 +201,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if sizeBefore > sizeAfter { removeLinks = make([]int, sizeBefore-sizeAfter) for ; i < sizeBefore; i++ { - removeLinks = append(removeLinks, i) + removeLinks[i-sizeAfter] = i } } @@ -231,7 +231,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if err := tx. WithContext(ctx). Where(&model.ContestLink{ContestID: contestID, Order: i}). - Updates(&model.ContestLink{Link: link}). + Updates(&model.ContestLink{Link: link, Order: i}). Error; err != nil { return err } @@ -560,7 +560,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U if sizeBefore > sizeAfter { removeLinks = make([]int, sizeBefore-sizeAfter) for ; i < sizeBefore; i++ { - removeLinks = append(removeLinks, i) + removeLinks[i-sizeAfter] = i } } @@ -592,7 +592,7 @@ func (r *ContestRepository) UpdateContestTeam(ctx context.Context, teamID uuid.U if err := tx. WithContext(ctx). Where(&model.ContestTeamLink{TeamID: teamID, Order: i}). - Updates(&model.ContestTeamLink{Link: link}). + Updates(&model.ContestTeamLink{Link: link, Order: i}). Error; err != nil { return err } diff --git a/internal/infrastructure/repository/project_impl.go b/internal/infrastructure/repository/project_impl.go index 154d6878..6c9a06c3 100644 --- a/internal/infrastructure/repository/project_impl.go +++ b/internal/infrastructure/repository/project_impl.go @@ -226,7 +226,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU if sizeBefore > sizeAfter { removeLinks = make([]int, sizeBefore-sizeAfter) for ; i < sizeBefore; i++ { - removeLinks = append(removeLinks, i) + removeLinks[i-sizeAfter] = i } } @@ -260,7 +260,7 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU if err := tx. WithContext(ctx). Where(&model.ProjectLink{ProjectID: projectID, Order: i}). - Updates(&model.ProjectLink{Link: link}). + Updates(&model.ProjectLink{Link: link, Order: i}). Error; err != nil { return err } diff --git a/internal/pkgs/random/repository.go b/internal/pkgs/random/repository.go index 48f5ca93..4cb74a59 100644 --- a/internal/pkgs/random/repository.go +++ b/internal/pkgs/random/repository.go @@ -14,7 +14,7 @@ func CreateContestArgs() *repository.CreateContestArgs { return &repository.CreateContestArgs{ Name: AlphaNumeric(), Description: AlphaNumeric(), - Links: Array(RandURLString, 1, 3), + Links: Array(RandURLString, 1, 2), Since: time.Now(), Until: Optional(time.Now().Add(time.Hour)), } @@ -25,7 +25,7 @@ func UpdateContestArgs() *repository.UpdateContestArgs { a := repository.UpdateContestArgs{ Name: optional.From(AlphaNumeric()), Description: optional.From(AlphaNumeric()), - Links: optional.From(Array(RandURLString, 1, 3)), + Links: optional.From(Array(RandURLString, 3, 4)), Since: optional.From(Time()), Until: optional.From(Time()), }