feat(m1): backend scaffold - entries CRUD, start/stop, auth, migrations
This commit is contained in:
87
internal/store/closed_week_store.go
Normal file
87
internal/store/closed_week_store.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/wotra/wotra/internal/domain"
|
||||
)
|
||||
|
||||
// ClosedWeekStore handles persistence for closed weeks.
|
||||
type ClosedWeekStore struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewClosedWeekStore(db *sql.DB) *ClosedWeekStore {
|
||||
return &ClosedWeekStore{db: db}
|
||||
}
|
||||
|
||||
func (s *ClosedWeekStore) Upsert(ctx context.Context, w *domain.ClosedWeek) error {
|
||||
_, err := s.db.ExecContext(ctx,
|
||||
`INSERT INTO closed_weeks (week_key, expected_ms, worked_ms, delta_ms, closed_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(week_key) DO UPDATE SET
|
||||
expected_ms=excluded.expected_ms, worked_ms=excluded.worked_ms,
|
||||
delta_ms=excluded.delta_ms, closed_at=excluded.closed_at, updated_at=excluded.updated_at`,
|
||||
w.WeekKey, w.ExpectedMs, w.WorkedMs, w.DeltaMs, w.ClosedAt, w.UpdatedAt,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ClosedWeekStore) Delete(ctx context.Context, weekKey string) error {
|
||||
_, err := s.db.ExecContext(ctx, `DELETE FROM closed_weeks WHERE week_key=?`, weekKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ClosedWeekStore) GetByWeekKey(ctx context.Context, weekKey string) (*domain.ClosedWeek, error) {
|
||||
row := s.db.QueryRowContext(ctx,
|
||||
`SELECT week_key, expected_ms, worked_ms, delta_ms, closed_at, updated_at
|
||||
FROM closed_weeks WHERE week_key=?`, weekKey)
|
||||
var w domain.ClosedWeek
|
||||
err := row.Scan(&w.WeekKey, &w.ExpectedMs, &w.WorkedMs, &w.DeltaMs, &w.ClosedAt, &w.UpdatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &w, nil
|
||||
}
|
||||
|
||||
func (s *ClosedWeekStore) ListByRange(ctx context.Context, fromWeekKey, toWeekKey string) ([]*domain.ClosedWeek, error) {
|
||||
rows, err := s.db.QueryContext(ctx,
|
||||
`SELECT week_key, expected_ms, worked_ms, delta_ms, closed_at, updated_at
|
||||
FROM closed_weeks WHERE week_key >= ? AND week_key <= ? ORDER BY week_key ASC`,
|
||||
fromWeekKey, toWeekKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var result []*domain.ClosedWeek
|
||||
for rows.Next() {
|
||||
var w domain.ClosedWeek
|
||||
if err := rows.Scan(&w.WeekKey, &w.ExpectedMs, &w.WorkedMs, &w.DeltaMs, &w.ClosedAt, &w.UpdatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, &w)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
// SumWorkedMsForWeek sums worked_ms across closed_days for the given day keys.
|
||||
func SumWorkedMsForWeek(ctx context.Context, db *sql.DB, dayKeys []string) (int64, error) {
|
||||
if len(dayKeys) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Build IN clause
|
||||
placeholders := make([]byte, 0, len(dayKeys)*2)
|
||||
args := make([]interface{}, len(dayKeys))
|
||||
for i, k := range dayKeys {
|
||||
if i > 0 {
|
||||
placeholders = append(placeholders, ',')
|
||||
}
|
||||
placeholders = append(placeholders, '?')
|
||||
args[i] = k
|
||||
}
|
||||
query := "SELECT COALESCE(SUM(worked_ms),0) FROM closed_days WHERE day_key IN (" + string(placeholders) + ")"
|
||||
var total int64
|
||||
err := db.QueryRowContext(ctx, query, args...).Scan(&total)
|
||||
return total, err
|
||||
}
|
||||
Reference in New Issue
Block a user