package store import ( "context" "database/sql" "github.com/wotra/wotra/internal/domain" ) // ClosedDayStore handles persistence for closed days. type ClosedDayStore struct { db *sql.DB } func NewClosedDayStore(db *sql.DB) *ClosedDayStore { return &ClosedDayStore{db: db} } func (s *ClosedDayStore) Upsert(ctx context.Context, d *domain.ClosedDay) error { _, err := s.db.ExecContext(ctx, `INSERT INTO closed_days (day_key, start_time, end_time, worked_ms, kind, closed_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(day_key) DO UPDATE SET start_time=excluded.start_time, end_time=excluded.end_time, worked_ms=excluded.worked_ms, kind=excluded.kind, closed_at=excluded.closed_at, updated_at=excluded.updated_at`, d.DayKey, d.StartTime, d.EndTime, d.WorkedMs, d.Kind, d.ClosedAt, d.UpdatedAt, ) return err } func (s *ClosedDayStore) Delete(ctx context.Context, dayKey string) error { _, err := s.db.ExecContext(ctx, `DELETE FROM closed_days WHERE day_key=?`, dayKey) return err } func (s *ClosedDayStore) GetByDayKey(ctx context.Context, dayKey string) (*domain.ClosedDay, error) { row := s.db.QueryRowContext(ctx, `SELECT day_key, start_time, end_time, worked_ms, kind, closed_at, updated_at FROM closed_days WHERE day_key=?`, dayKey) return scanClosedDay(row) } func (s *ClosedDayStore) ListByDateRange(ctx context.Context, fromDayKey, toDayKey string) ([]*domain.ClosedDay, error) { rows, err := s.db.QueryContext(ctx, `SELECT day_key, start_time, end_time, worked_ms, kind, closed_at, updated_at FROM closed_days WHERE day_key >= ? AND day_key <= ? ORDER BY day_key ASC`, fromDayKey, toDayKey) if err != nil { return nil, err } defer rows.Close() var result []*domain.ClosedDay for rows.Next() { d, err := scanClosedDayRow(rows) if err != nil { return nil, err } result = append(result, d) } return result, rows.Err() } func scanClosedDay(row *sql.Row) (*domain.ClosedDay, error) { var d domain.ClosedDay var startTime, endTime sql.NullInt64 err := row.Scan(&d.DayKey, &startTime, &endTime, &d.WorkedMs, &d.Kind, &d.ClosedAt, &d.UpdatedAt) if err != nil { return nil, err } if startTime.Valid { d.StartTime = &startTime.Int64 } if endTime.Valid { d.EndTime = &endTime.Int64 } return &d, nil } func scanClosedDayRow(rows *sql.Rows) (*domain.ClosedDay, error) { var d domain.ClosedDay var startTime, endTime sql.NullInt64 err := rows.Scan(&d.DayKey, &startTime, &endTime, &d.WorkedMs, &d.Kind, &d.ClosedAt, &d.UpdatedAt) if err != nil { return nil, err } if startTime.Valid { d.StartTime = &startTime.Int64 } if endTime.Valid { d.EndTime = &endTime.Int64 } return &d, nil }