9f673bfca3
Remove soft delete from HabitEntry: - Eliminate DeletedAt field from entity and database - Change UnmarkHabit from soft delete to hard delete - Simplify all queries removing deleted_at checks - Update migration to remove deleted_at column Add date filtering and smart pagination to GetHabitEntries: - Support optional from/to date parameters - Implement intelligent pagination rules: * No date range: pagination required * Date range > 1 year: pagination required * Date range ≤ 1 year: pagination optional - Pagination defaults (page=1, limit=50) only when required - Return metadata with total count, page, and limit Technical improvements: - Cleaner codebase without soft delete complexity - Better performance (no filtering in queries) - More intuitive API with flexible pagination - Comprehensive test coverage for validation rules
75 lines
1.6 KiB
Go
75 lines
1.6 KiB
Go
package commands
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"apocapoc-api/internal/domain/repositories"
|
|
"apocapoc-api/internal/shared/errors"
|
|
)
|
|
|
|
type UnmarkHabitCommand struct {
|
|
HabitID string
|
|
UserID string
|
|
ScheduledDate time.Time
|
|
}
|
|
|
|
type UnmarkHabitHandler struct {
|
|
habitRepo repositories.HabitRepository
|
|
entryRepo repositories.HabitEntryRepository
|
|
}
|
|
|
|
func NewUnmarkHabitHandler(
|
|
habitRepo repositories.HabitRepository,
|
|
entryRepo repositories.HabitEntryRepository,
|
|
) *UnmarkHabitHandler {
|
|
return &UnmarkHabitHandler{
|
|
habitRepo: habitRepo,
|
|
entryRepo: entryRepo,
|
|
}
|
|
}
|
|
|
|
func (h *UnmarkHabitHandler) Handle(ctx context.Context, cmd UnmarkHabitCommand) error {
|
|
// Verify habit exists and user owns it
|
|
habit, err := h.habitRepo.FindByID(ctx, cmd.HabitID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if habit.UserID != cmd.UserID {
|
|
return errors.ErrUnauthorized
|
|
}
|
|
|
|
// Find the entry for the scheduled date
|
|
// We search within the same day
|
|
startOfDay := time.Date(
|
|
cmd.ScheduledDate.Year(),
|
|
cmd.ScheduledDate.Month(),
|
|
cmd.ScheduledDate.Day(),
|
|
0, 0, 0, 0,
|
|
cmd.ScheduledDate.Location(),
|
|
)
|
|
endOfDay := startOfDay.Add(24 * time.Hour)
|
|
|
|
entries, err := h.entryRepo.FindByHabitIDAndDateRange(ctx, cmd.HabitID, startOfDay, endOfDay)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Find the entry for this date
|
|
var targetEntryID string
|
|
for _, entry := range entries {
|
|
if entry.ScheduledDate.Equal(cmd.ScheduledDate) {
|
|
targetEntryID = entry.ID
|
|
break
|
|
}
|
|
}
|
|
|
|
if targetEntryID == "" {
|
|
return errors.ErrNotFound
|
|
}
|
|
|
|
// Hard delete the entry
|
|
return h.entryRepo.Delete(ctx, targetEntryID)
|
|
}
|