diff --git a/app/report/repositories/report_repository.go b/app/report/repositories/report_repository.go index 5b039b7..f370b73 100644 --- a/app/report/repositories/report_repository.go +++ b/app/report/repositories/report_repository.go @@ -61,7 +61,7 @@ func (repo *ReportRepository) FindAll() ([]models.Report, error) { } func (repo *ReportRepository) FindRankAtAgeAndGender(user *users.User, start, end time.Time) (types.ResponseRank, error) { - var userAvgScore float64 + var userAvgScore, allAvgScore float64 var totalUsers, rank int64 ageGroup := user.Age / 10 * 10 @@ -87,6 +87,19 @@ func (repo *ReportRepository) FindRankAtAgeAndGender(user *users.User, start, en return types.ResponseRank{}, err } + // calculate average score for all users in the same age group and gender + err = repo.DB.Table("reports"). + Select("avg(score)"). + Joins("inner join users on users.id = reports.user_id"). + Where("users.age >= ? AND users.age < ?", ageGroup, ageGroup+10). + Where("users.gender = ?", user.Gender). + Where("reports.created_at BETWEEN ? AND ?", start, end). + Scan(&allAvgScore).Error + + if err != nil { + return types.ResponseRank{}, err + } + // calculate rank sql := ` SELECT COUNT(*) as rank_count @@ -110,13 +123,16 @@ func (repo *ReportRepository) FindRankAtAgeAndGender(user *users.User, start, en rank = totalUsers - rank normalRatio := fmt.Sprintf("%.2f", float64(rank)/float64(totalUsers)*100.00) + averageScore := fmt.Sprintf("%.2f", userAvgScore) + allAvgScoreStr := fmt.Sprintf("%.2f", allAvgScore) return types.ResponseRank{ - UserID: user.ID, - Nickname: user.Nickname, - Age: user.Age, - Gender: user.Gender, - NormalRatio: normalRatio, - AverageScore: userAvgScore, + UserID: user.ID, + Nickname: user.Nickname, + Age: user.Age, + Gender: user.Gender, + NormalRatio: normalRatio, + AverageScore: averageScore, + AllAverageScore: allAvgScoreStr, }, nil } diff --git a/app/report/repositories/report_repository_test.go b/app/report/repositories/report_repository_test.go index cfeaa59..08ce8dc 100644 --- a/app/report/repositories/report_repository_test.go +++ b/app/report/repositories/report_repository_test.go @@ -632,6 +632,7 @@ func TestReportRepository_FindRankAtAgeAndGender(t *testing.T) { ageGroup := 20 userAvgScore := 80.0 + allAvgScore := 90.0 // Set up expectations for the mock DB to return the sample report mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE reports.user_id = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). @@ -645,6 +646,12 @@ func TestReportRepository_FindRankAtAgeAndGender(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"count"}). AddRow("100")) + // Set up expectations for the mock DB to return average score for all users in the same age group and gender + mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE \\(users.age >= \\? AND users.age < \\?\\) AND users.gender = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). + WithArgs(ageGroup, ageGroup+10, user.Gender, start, end). + WillReturnRows(sqlmock.NewRows([]string{"avg"}). + AddRow(allAvgScore)) + // Set up expectations for the mock DB to return rank mock.ExpectQuery("SELECT COUNT\\(\\*\\) as rank_count FROM \\(\\s*SELECT reports.user_id, AVG\\(score\\) as average_score FROM reports INNER JOIN users\\s+on\\s+users.id = reports.user_id WHERE users.age >= \\? AND users.age < \\? AND users.gender = \\? AND reports.created_at BETWEEN \\? AND \\? GROUP BY reports.user_id\\s*\\) as subquery WHERE average_score > \\?"). WithArgs(ageGroup, ageGroup+10, user.Gender, start, end, userAvgScore). @@ -666,7 +673,8 @@ func TestReportRepository_FindRankAtAgeAndGender(t *testing.T) { assert.Equal(t, user.Age, responseRank.Age) assert.Equal(t, user.Gender, responseRank.Gender) assert.Equal(t, "80.00", responseRank.NormalRatio) - assert.Equal(t, 80.0, responseRank.AverageScore) + assert.Equal(t, "80.00", responseRank.AverageScore) + assert.Equal(t, "90.00", responseRank.AllAverageScore) } func TestReportRepository_FindRankAtAgeAndGender_Error(t *testing.T) { @@ -809,8 +817,72 @@ func TestReportRepository_FindRankAtAgeAndGender_Error3(t *testing.T) { start := time.Now().AddDate(0, 0, -30) end := time.Now() + ageGroup := 20 + + // Set up expectations for the mock DB to return the sample report + mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE reports.user_id = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). + WithArgs(user.ID, start, end). + WillReturnRows(sqlmock.NewRows([]string{"avg"}). + AddRow("80.0")) + + // Set up expectations for the mock DB to return total users + mock.ExpectQuery("SELECT count\\(\\*\\) FROM `users` WHERE \\(age >= \\? AND age < \\?\\) AND gender = \\?"). + WithArgs(ageGroup, ageGroup+10, user.Gender). + WillReturnRows(sqlmock.NewRows([]string{"count"}). + AddRow("100")) + + // Set up expectations for the mock DB to return average score for all users in the same age group and gender + mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE \\(users.age >= \\? AND users.age < \\?\\) AND users.gender = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). + WithArgs(ageGroup, ageGroup+10, user.Gender, start, end). + WillReturnError(err) + + // Call the method under test + _, err = reportRepository.FindRankAtAgeAndGender(&user, start, end) + if err == nil { + t.Fatalf("Error finding rank: %v", err) + } + + // Check that the expectations were met + assert.NoError(t, mock.ExpectationsWereMet()) +} + +func TestReportRepository_FindRankAtAgeAndGender_Error4(t *testing.T) { + // Create mock DB + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("Error creating mock DB: %v", err) + } + + // Set up expectations for the mock DB (ex: SELECT VERSION()) + mock.ExpectQuery("SELECT VERSION()"). + WillReturnRows(sqlmock.NewRows([]string{"VERSION"}). + AddRow("8.0.0")) + + // Create gorm.DB + gormDB, err := gorm.Open(mysql.New(mysql.Config{Conn: db}), &gorm.Config{}) + if err != nil { + t.Fatalf("Error creating gorm.DB: %v", err) + } + + // Create ReportRepository + reportRepository := repositories.NewReportRepository(gormDB) + + // Create sample user for the test + user := usermodel.User{ + ID: 1, + Name: "test", + Nickname: "test", + Email: "test@gmail.com", + Age: 20, + Gender: "male", + } + + start := time.Now().AddDate(0, 0, -30) + end := time.Now() + ageGroup := 20 userAvgScore := 80.0 + allAvgScore := 90.0 // Set up expectations for the mock DB to return the sample report mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE reports.user_id = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). @@ -824,6 +896,12 @@ func TestReportRepository_FindRankAtAgeAndGender_Error3(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"count"}). AddRow("100")) + // Set up expectations for the mock DB to return average score for all users in the same age group and gender + mock.ExpectQuery("SELECT avg\\(score\\) FROM `reports` inner join users on users.id = reports.user_id WHERE \\(users.age >= \\? AND users.age < \\?\\) AND users.gender = \\? AND \\(reports.created_at BETWEEN \\? AND \\?\\)"). + WithArgs(ageGroup, ageGroup+10, user.Gender, start, end). + WillReturnRows(sqlmock.NewRows([]string{"avg"}). + AddRow(allAvgScore)) + // Set up expectations for the mock DB to return rank mock.ExpectQuery("SELECT COUNT\\(\\*\\) as rank_count FROM \\(\\s*SELECT reports.user_id, AVG\\(score\\) as average_score FROM reports INNER JOIN users\\s+on\\s+users.id = reports.user_id WHERE users.age >= \\? AND users.age < \\? AND users.gender = \\? AND reports.created_at BETWEEN \\? AND \\? GROUP BY reports.user_id\\s*\\) as subquery WHERE average_score > \\?"). WithArgs(ageGroup, ageGroup+10, user.Gender, start, end, userAvgScore). diff --git a/app/report/services/report_service.go b/app/report/services/report_service.go index 3cc9a9b..1e01c5c 100644 --- a/app/report/services/report_service.go +++ b/app/report/services/report_service.go @@ -363,12 +363,13 @@ func (service *ReportService) FindRankAtAgeAndGender(c *gin.Context) (types.Resp rank, _ := service.ReportRepository.FindRankAtAgeAndGender(user, time.Now().AddDate(0, 0, -30), time.Now()) responseRank := types.ResponseRank{ - UserID: rank.UserID, - Nickname: user.Nickname, - Age: rank.Age, - Gender: rank.Gender, - NormalRatio: rank.NormalRatio, - AverageScore: rank.AverageScore, + UserID: rank.UserID, + Nickname: user.Nickname, + Age: rank.Age, + Gender: rank.Gender, + NormalRatio: rank.NormalRatio, + AverageScore: rank.AverageScore, + AllAverageScore: rank.AllAverageScore, } return responseRank, nil diff --git a/app/report/services/report_service_test.go b/app/report/services/report_service_test.go index c4ae977..7c1214e 100644 --- a/app/report/services/report_service_test.go +++ b/app/report/services/report_service_test.go @@ -832,12 +832,13 @@ func TestFindRankAtAgeAndGender(t *testing.T) { // Set up sample rank for the test rank := types.ResponseRank{ - UserID: 1, - Nickname: "test", - Age: 20, - Gender: "male", - NormalRatio: "90.00", - AverageScore: 90.000, + UserID: 1, + Nickname: "test", + Age: 20, + Gender: "male", + NormalRatio: "90.00", + AverageScore: "90.00", + AllAverageScore: "90.00", } // Set up expectations for the mock repository and util diff --git a/app/report/types/response_types.go b/app/report/types/response_types.go index b604f7f..37aa2d2 100644 --- a/app/report/types/response_types.go +++ b/app/report/types/response_types.go @@ -32,10 +32,11 @@ type ResponseReport struct { } type ResponseRank struct { - UserID uint `json:"user_id"` - Nickname string `json:"nickname"` - Gender string `json:"gender"` - Age int `json:"age"` - NormalRatio string `json:"normal_ratio"` - AverageScore float64 `json:"average_score"` + UserID uint `json:"user_id"` + Nickname string `json:"nickname"` + Gender string `json:"gender"` + Age int `json:"age"` + NormalRatio string `json:"normal_ratio"` + AverageScore string `json:"average_score"` + AllAverageScore string `json:"all_average_score"` }