Files
Super-HomeworkManager/internal/repository/assignment_repository.go
2026-01-08 23:31:49 +09:00

349 lines
11 KiB
Go

package repository
import (
"time"
"homework-manager/internal/database"
"homework-manager/internal/models"
"gorm.io/gorm"
)
type AssignmentRepository struct {
db *gorm.DB
}
func NewAssignmentRepository() *AssignmentRepository {
return &AssignmentRepository{db: database.GetDB()}
}
func (r *AssignmentRepository) Create(assignment *models.Assignment) error {
return r.db.Create(assignment).Error
}
func (r *AssignmentRepository) FindByID(id uint) (*models.Assignment, error) {
var assignment models.Assignment
err := r.db.First(&assignment, id).Error
if err != nil {
return nil, err
}
return &assignment, nil
}
func (r *AssignmentRepository) FindByUserID(userID uint) ([]models.Assignment, error) {
var assignments []models.Assignment
err := r.db.Where("user_id = ?", userID).Order("due_date ASC").Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) FindPendingByUserID(userID uint, limit, offset int) ([]models.Assignment, error) {
var assignments []models.Assignment
query := r.db.Where("user_id = ? AND is_completed = ?", userID, false).
Order("due_date ASC")
if limit > 0 {
query = query.Limit(limit).Offset(offset)
}
err := query.Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) FindCompletedByUserID(userID uint, limit, offset int) ([]models.Assignment, error) {
var assignments []models.Assignment
query := r.db.Where("user_id = ? AND is_completed = ?", userID, true).
Order("completed_at DESC")
if limit > 0 {
query = query.Limit(limit).Offset(offset)
}
err := query.Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) FindDueTodayByUserID(userID uint) ([]models.Assignment, error) {
now := time.Now()
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endOfDay := startOfDay.AddDate(0, 0, 1)
var assignments []models.Assignment
err := r.db.Where("user_id = ? AND is_completed = ? AND due_date >= ? AND due_date < ?",
userID, false, startOfDay, endOfDay).
Order("due_date ASC").Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) FindDueThisWeekByUserID(userID uint) ([]models.Assignment, error) {
now := time.Now()
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
weekLater := startOfDay.AddDate(0, 0, 7)
var assignments []models.Assignment
err := r.db.Where("user_id = ? AND is_completed = ? AND due_date >= ? AND due_date < ?",
userID, false, startOfDay, weekLater).
Order("due_date ASC").Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) FindOverdueByUserID(userID uint, limit, offset int) ([]models.Assignment, error) {
now := time.Now()
var assignments []models.Assignment
query := r.db.Where("user_id = ? AND is_completed = ? AND due_date < ?",
userID, false, now).
Order("due_date ASC")
if limit > 0 {
query = query.Limit(limit).Offset(offset)
}
err := query.Find(&assignments).Error
return assignments, err
}
func (r *AssignmentRepository) Update(assignment *models.Assignment) error {
return r.db.Save(assignment).Error
}
func (r *AssignmentRepository) Delete(id uint) error {
return r.db.Delete(&models.Assignment{}, id).Error
}
func (r *AssignmentRepository) CountByUserID(userID uint) (int64, error) {
var count int64
err := r.db.Model(&models.Assignment{}).Where("user_id = ?", userID).Count(&count).Error
return count, err
}
func (r *AssignmentRepository) CountPendingByUserID(userID uint) (int64, error) {
var count int64
err := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND is_completed = ?", userID, false).Count(&count).Error
return count, err
}
func (r *AssignmentRepository) GetSubjectsByUserID(userID uint) ([]string, error) {
var subjects []string
err := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND subject != ''", userID).
Distinct("subject").
Pluck("subject", &subjects).Error
return subjects, err
}
func (r *AssignmentRepository) CountCompletedByUserID(userID uint) (int64, error) {
var count int64
err := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND is_completed = ?", userID, true).Count(&count).Error
return count, err
}
func (r *AssignmentRepository) Search(userID uint, queryStr, priority, filter string, page, pageSize int) ([]models.Assignment, int64, error) {
var assignments []models.Assignment
var totalCount int64
dbQuery := r.db.Model(&models.Assignment{}).Where("user_id = ?", userID)
if queryStr != "" {
dbQuery = dbQuery.Where("title LIKE ? OR description LIKE ?", "%"+queryStr+"%", "%"+queryStr+"%")
}
if priority != "" {
dbQuery = dbQuery.Where("priority = ?", priority)
}
now := time.Now()
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endOfDay := startOfDay.AddDate(0, 0, 1)
weekLater := startOfDay.AddDate(0, 0, 7)
switch filter {
case "completed":
dbQuery = dbQuery.Where("is_completed = ?", true)
case "overdue":
dbQuery = dbQuery.Where("is_completed = ? AND due_date < ?", false, now)
case "due_today":
dbQuery = dbQuery.Where("is_completed = ? AND due_date >= ? AND due_date < ?", false, startOfDay, endOfDay)
case "due_this_week":
dbQuery = dbQuery.Where("is_completed = ? AND due_date >= ? AND due_date < ?", false, startOfDay, weekLater)
default: // pending
dbQuery = dbQuery.Where("is_completed = ?", false)
}
if err := dbQuery.Count(&totalCount).Error; err != nil {
return nil, 0, err
}
if filter == "completed" {
dbQuery = dbQuery.Order("completed_at DESC")
} else {
dbQuery = dbQuery.Order("due_date ASC")
}
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 10
}
offset := (page - 1) * pageSize
err := dbQuery.Limit(pageSize).Offset(offset).Find(&assignments).Error
return assignments, totalCount, err
}
func (r *AssignmentRepository) CountOverdueByUserID(userID uint) (int64, error) {
var count int64
now := time.Now()
err := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND is_completed = ? AND due_date < ?", userID, false, now).Count(&count).Error
return count, err
}
type StatisticsFilter struct {
Subject string
From *time.Time
To *time.Time
IncludeArchived bool
}
type AssignmentStatistics struct {
Total int64
Completed int64
Pending int64
Overdue int64
CompletedOnTime int64
OnTimeCompletionRate float64
}
type SubjectStatistics struct {
Subject string
Total int64
Completed int64
Pending int64
Overdue int64
CompletedOnTime int64
OnTimeCompletionRate float64
}
func (r *AssignmentRepository) GetStatistics(userID uint, filter StatisticsFilter) (*AssignmentStatistics, error) {
now := time.Now()
stats := &AssignmentStatistics{}
baseQuery := r.db.Model(&models.Assignment{}).Where("user_id = ?", userID)
if filter.Subject != "" {
baseQuery = baseQuery.Where("subject = ?", filter.Subject)
}
if filter.From != nil {
baseQuery = baseQuery.Where("created_at >= ?", *filter.From)
}
if filter.To != nil {
toEnd := filter.To.AddDate(0, 0, 1)
baseQuery = baseQuery.Where("created_at < ?", toEnd)
}
if !filter.IncludeArchived {
baseQuery = baseQuery.Where("is_archived = ?", false)
}
if err := baseQuery.Count(&stats.Total).Error; err != nil {
return nil, err
}
completedQuery := baseQuery.Session(&gorm.Session{})
if err := completedQuery.Where("is_completed = ?", true).Count(&stats.Completed).Error; err != nil {
return nil, err
}
pendingQuery := baseQuery.Session(&gorm.Session{})
if err := pendingQuery.Where("is_completed = ?", false).Count(&stats.Pending).Error; err != nil {
return nil, err
}
overdueQuery := baseQuery.Session(&gorm.Session{})
if err := overdueQuery.Where("is_completed = ? AND due_date < ?", false, now).Count(&stats.Overdue).Error; err != nil {
return nil, err
}
onTimeQuery := baseQuery.Session(&gorm.Session{})
if err := onTimeQuery.Where("is_completed = ? AND completed_at <= due_date", true).Count(&stats.CompletedOnTime).Error; err != nil {
return nil, err
}
if stats.Completed > 0 {
stats.OnTimeCompletionRate = float64(stats.CompletedOnTime) / float64(stats.Completed) * 100
}
return stats, nil
}
func (r *AssignmentRepository) GetStatisticsBySubjects(userID uint, filter StatisticsFilter) ([]SubjectStatistics, error) {
now := time.Now()
subjects, err := r.GetSubjectsByUserID(userID)
if err != nil {
return nil, err
}
var results []SubjectStatistics
for _, subject := range subjects {
subjectFilter := StatisticsFilter{
Subject: subject,
From: filter.From,
To: filter.To,
}
stats, err := r.GetStatistics(userID, subjectFilter)
if err != nil {
return nil, err
}
overdueQuery := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND subject = ? AND is_completed = ? AND due_date < ?", userID, subject, false, now)
if filter.From != nil {
overdueQuery = overdueQuery.Where("created_at >= ?", *filter.From)
}
if filter.To != nil {
toEnd := filter.To.AddDate(0, 0, 1)
overdueQuery = overdueQuery.Where("created_at < ?", toEnd)
}
var overdueCount int64
overdueQuery.Count(&overdueCount)
results = append(results, SubjectStatistics{
Subject: subject,
Total: stats.Total,
Completed: stats.Completed,
Pending: stats.Pending,
Overdue: overdueCount,
CompletedOnTime: stats.CompletedOnTime,
OnTimeCompletionRate: stats.OnTimeCompletionRate,
})
}
return results, nil
}
func (r *AssignmentRepository) ArchiveBySubject(userID uint, subject string) error {
return r.db.Model(&models.Assignment{}).
Where("user_id = ? AND subject = ?", userID, subject).
Update("is_archived", true).Error
}
func (r *AssignmentRepository) UnarchiveBySubject(userID uint, subject string) error {
return r.db.Model(&models.Assignment{}).
Where("user_id = ? AND subject = ?", userID, subject).
Update("is_archived", false).Error
}
func (r *AssignmentRepository) GetArchivedSubjects(userID uint) ([]string, error) {
var subjects []string
err := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND is_archived = ? AND subject != ''", userID, true).
Distinct("subject").
Pluck("subject", &subjects).Error
return subjects, err
}
func (r *AssignmentRepository) GetSubjectsByUserIDWithArchived(userID uint, includeArchived bool) ([]string, error) {
var subjects []string
query := r.db.Model(&models.Assignment{}).
Where("user_id = ? AND subject != ''", userID)
if !includeArchived {
query = query.Where("is_archived = ?", false)
}
err := query.Distinct("subject").Pluck("subject", &subjects).Error
return subjects, err
}