package store import ( "context" "database/sql" "errors" "github.com/wotra/wotra/internal/domain" ) // BalanceAdjustmentStore handles persistence for balance_adjustments. type BalanceAdjustmentStore struct { db *sql.DB } func NewBalanceAdjustmentStore(db *sql.DB) *BalanceAdjustmentStore { return &BalanceAdjustmentStore{db: db} } func (s *BalanceAdjustmentStore) Create(ctx context.Context, a *domain.BalanceAdjustment) error { _, err := s.db.ExecContext(ctx, `INSERT INTO balance_adjustments (id, delta_ms, note, effective_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`, a.ID, a.DeltaMs, a.Note, a.EffectiveAt, a.CreatedAt, a.UpdatedAt, ) return err } func (s *BalanceAdjustmentStore) Update(ctx context.Context, a *domain.BalanceAdjustment) error { res, err := s.db.ExecContext(ctx, `UPDATE balance_adjustments SET delta_ms=?, note=?, effective_at=?, updated_at=? WHERE id=?`, a.DeltaMs, a.Note, a.EffectiveAt, a.UpdatedAt, a.ID, ) if err != nil { return err } n, _ := res.RowsAffected() if n == 0 { return ErrAdjustmentNotFound } return nil } func (s *BalanceAdjustmentStore) Delete(ctx context.Context, id string) error { res, err := s.db.ExecContext(ctx, `DELETE FROM balance_adjustments WHERE id=?`, id) if err != nil { return err } n, _ := res.RowsAffected() if n == 0 { return ErrAdjustmentNotFound } return nil } func (s *BalanceAdjustmentStore) GetByID(ctx context.Context, id string) (*domain.BalanceAdjustment, error) { row := s.db.QueryRowContext(ctx, `SELECT id, delta_ms, note, effective_at, created_at, updated_at FROM balance_adjustments WHERE id=?`, id) var a domain.BalanceAdjustment err := row.Scan(&a.ID, &a.DeltaMs, &a.Note, &a.EffectiveAt, &a.CreatedAt, &a.UpdatedAt) if errors.Is(err, sql.ErrNoRows) { return nil, ErrAdjustmentNotFound } if err != nil { return nil, err } return &a, nil } // List returns all adjustments ordered by effective_at DESC. func (s *BalanceAdjustmentStore) List(ctx context.Context) ([]*domain.BalanceAdjustment, error) { rows, err := s.db.QueryContext(ctx, `SELECT id, delta_ms, note, effective_at, created_at, updated_at FROM balance_adjustments ORDER BY effective_at DESC`) if err != nil { return nil, err } defer rows.Close() var result []*domain.BalanceAdjustment for rows.Next() { var a domain.BalanceAdjustment if err := rows.Scan(&a.ID, &a.DeltaMs, &a.Note, &a.EffectiveAt, &a.CreatedAt, &a.UpdatedAt); err != nil { return nil, err } result = append(result, &a) } return result, rows.Err() } // SumDelta returns the sum of delta_ms and row count across all adjustments. func (s *BalanceAdjustmentStore) SumDelta(ctx context.Context) (totalDeltaMs int64, count int, err error) { err = s.db.QueryRowContext(ctx, `SELECT COALESCE(SUM(delta_ms), 0), COUNT(*) FROM balance_adjustments`, ).Scan(&totalDeltaMs, &count) return } // ErrAdjustmentNotFound is returned when no balance_adjustment row matches the given ID. var ErrAdjustmentNotFound = errors.New("balance adjustment not found")