-
Notifications
You must be signed in to change notification settings - Fork 0
ユーザー情報に基づいたソートを実装 #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a999117
493952b
6ad65de
a332a85
7d81b26
b02cc87
84c8743
af46e68
0f6d9cd
85cc546
76d36f0
2f195bf
0de6fd5
de0908a
c32b3b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. スキーマってTypeSpec側でアップデートしたんだっけ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. そうか、APIの変更が必要なのか |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,4 +40,8 @@ type SubjectListFilter struct { | |
| Semester []CourseSemester | ||
| RequirementType []SubjectRequirementType | ||
| CulturalSubjectCategory []CulturalSubjectCategory | ||
|
|
||
| SortByUserAttribute bool | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. フィルターの型にソートのパラメータを付与するんじゃなくて、ソート用の型を作って分けてもいいんじゃないかな? |
||
| SortCourse *CourseType | ||
| SortGrade *Grade | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package domain | ||
|
|
||
|
KurenNagata marked this conversation as resolved.
|
||
| type User struct { | ||
| ID string | ||
| Course *CourseType | ||
| Grade *Grade | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. テストは一旦なくてもいいかも |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| package handler | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "testing" | ||
|
|
||
| api "github.com/fun-dotto/server/gen/academic" | ||
| "github.com/fun-dotto/server/internal/modules/academic/domain" | ||
| ) | ||
|
|
||
| // fakeSubjectService は List に渡された filter を記録するだけのスタブ。 | ||
| type fakeSubjectService struct { | ||
| gotFilter domain.SubjectListFilter | ||
| called bool | ||
| } | ||
|
|
||
| func (f *fakeSubjectService) List(_ context.Context, filter domain.SubjectListFilter) ([]domain.Subject, error) { | ||
| f.gotFilter = filter | ||
| f.called = true | ||
| return nil, nil | ||
| } | ||
|
|
||
| func (f *fakeSubjectService) GetByID(context.Context, string) (domain.Subject, error) { | ||
| return domain.Subject{}, nil | ||
| } | ||
|
|
||
| func (f *fakeSubjectService) Delete(context.Context, string) error { return nil } | ||
|
|
||
| func (f *fakeSubjectService) GetSyllabus(context.Context, string) (domain.Syllabus, error) { | ||
| return domain.Syllabus{}, nil | ||
| } | ||
|
|
||
| type fakeUserService struct { | ||
| user domain.User | ||
| found bool | ||
| err error | ||
| gotID string | ||
| called bool | ||
| } | ||
|
|
||
| func (f *fakeUserService) FindByID(_ context.Context, id string) (domain.User, bool, error) { | ||
| f.gotID = id | ||
| f.called = true | ||
| return f.user, f.found, f.err | ||
| } | ||
|
|
||
| func TestSubjectsV1List_UserAttributeSort(t *testing.T) { | ||
| course := domain.CourseTypeComplexSystem | ||
| grade := domain.GradeB3 | ||
| userID := "firebase-uid-001" | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| // 入力 | ||
| paramUserID *string | ||
| userSvc *fakeUserService | ||
| // 期待値 | ||
| wantUserSvcCalled bool | ||
| wantSortEnabled bool | ||
| wantSortCourse *domain.CourseType | ||
| wantSortGrade *domain.Grade | ||
| wantErr bool | ||
| }{ | ||
| { | ||
| name: "userId 未指定ならソートせず UserService も呼ばない", | ||
| paramUserID: nil, | ||
| userSvc: &fakeUserService{}, | ||
| wantUserSvcCalled: false, | ||
| wantSortEnabled: false, | ||
| }, | ||
| { | ||
| name: "userId 指定かつユーザーが存在すればソート条件が立つ", | ||
| paramUserID: &userID, | ||
| userSvc: &fakeUserService{ | ||
| user: domain.User{ID: userID, Course: &course, Grade: &grade}, | ||
| found: true, | ||
| }, | ||
| wantUserSvcCalled: true, | ||
| wantSortEnabled: true, | ||
| wantSortCourse: &course, | ||
| wantSortGrade: &grade, | ||
| }, | ||
| { | ||
| name: "ユーザーが存在しなければエラーにせず現行順にフォールバックする", | ||
| paramUserID: &userID, | ||
| userSvc: &fakeUserService{found: false}, | ||
| wantUserSvcCalled: true, | ||
| wantSortEnabled: false, | ||
| }, | ||
| { | ||
| name: "コース・学年が未設定のユーザーでもソートは有効になる", | ||
| paramUserID: &userID, | ||
| userSvc: &fakeUserService{ | ||
| user: domain.User{ID: userID}, | ||
| found: true, | ||
| }, | ||
| wantUserSvcCalled: true, | ||
| wantSortEnabled: true, | ||
| wantSortCourse: nil, | ||
| wantSortGrade: nil, | ||
| }, | ||
| { | ||
| name: "UserService がエラーを返せばハンドラもエラーを返す", | ||
| paramUserID: &userID, | ||
| userSvc: &fakeUserService{err: errors.New("db is down")}, | ||
| wantUserSvcCalled: true, | ||
| wantErr: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| subjectSvc := &fakeSubjectService{} | ||
| h := &Handler{subjectSvc: subjectSvc, userSvc: tt.userSvc} | ||
|
|
||
| _, err := h.SubjectsV1List(context.Background(), api.SubjectsV1ListRequestObject{ | ||
| Params: api.SubjectsV1ListParams{UserId: tt.paramUserID}, | ||
| }) | ||
|
|
||
| if tt.wantErr { | ||
| if err == nil { | ||
| t.Fatal("エラーを期待したが nil だった") | ||
| } | ||
| if subjectSvc.called { | ||
| t.Error("エラー時は SubjectService.List を呼ぶべきではない") | ||
| } | ||
| return | ||
| } | ||
| if err != nil { | ||
| t.Fatalf("予期しないエラー: %v", err) | ||
| } | ||
|
|
||
| if tt.userSvc.called != tt.wantUserSvcCalled { | ||
| t.Errorf("UserService.FindByID called = %v, want %v", tt.userSvc.called, tt.wantUserSvcCalled) | ||
| } | ||
| if tt.wantUserSvcCalled && tt.userSvc.gotID != userID { | ||
| t.Errorf("FindByID に渡された id = %q, want %q", tt.userSvc.gotID, userID) | ||
| } | ||
|
|
||
| got := subjectSvc.gotFilter | ||
| if got.SortByUserAttribute != tt.wantSortEnabled { | ||
| t.Errorf("SortByUserAttribute = %v, want %v", got.SortByUserAttribute, tt.wantSortEnabled) | ||
| } | ||
| if !equalCourse(got.SortCourse, tt.wantSortCourse) { | ||
| t.Errorf("SortCourse = %v, want %v", got.SortCourse, tt.wantSortCourse) | ||
| } | ||
| if !equalGrade(got.SortGrade, tt.wantSortGrade) { | ||
| t.Errorf("SortGrade = %v, want %v", got.SortGrade, tt.wantSortGrade) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func equalCourse(a, b *domain.CourseType) bool { | ||
| if a == nil || b == nil { | ||
| return a == b | ||
| } | ||
| return *a == *b | ||
| } | ||
|
|
||
| func equalGrade(a, b *domain.Grade) bool { | ||
| if a == nil || b == nil { | ||
| return a == b | ||
| } | ||
| return *a == *b | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この変更は必要ないかも?