package store import ( "context" "database/sql" "encoding/json" "errors" "steward/internal/model" ) func scanHistory(sc interface{ Scan(...any) error }) (*model.HistoryEntry, error) { e := &model.HistoryEntry{} var t, changes string var uid, revertOf, revertedBy sql.NullInt64 if err := sc.Scan(&e.ID, &t, &uid, &e.Username, &e.Via, &e.Description, &changes, &revertOf, &revertedBy); err != nil { return nil, err } e.Time = parseTS(t) e.UserID, e.RevertOf, e.RevertedBy = uid.Int64, revertOf.Int64, revertedBy.Int64 if err := json.Unmarshal([]byte(changes), &e.Changes); err != nil { return nil, err } return e, nil } const historyCols = `id, time, user_id, username, via, description, changes, revert_of, reverted_by` // ListHistory lists entries, newest first; before > 0 pages back. func (s *Store) ListHistory(ctx context.Context, limit int, before int64) ([]*model.HistoryEntry, error) { if limit <= 0 || limit > 500 { limit = 100 } q := `SELECT ` + historyCols + ` FROM history` var args []any if before > 0 { q += ` WHERE id < ?` args = append(args, before) } q += ` ORDER BY id DESC LIMIT ?` args = append(args, limit) rows, err := s.db.QueryContext(ctx, q, args...) if err != nil { return nil, err } defer rows.Close() out := []*model.HistoryEntry{} for rows.Next() { e, err := scanHistory(rows) if err != nil { return nil, err } out = append(out, e) } return out, rows.Err() } // GetHistory loads one entry. func (s *Store) GetHistory(ctx context.Context, id int64) (*model.HistoryEntry, error) { e, err := scanHistory(s.db.QueryRowContext(ctx, `SELECT `+historyCols+` FROM history WHERE id = ?`, id)) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } return e, err }