Class: SesDashboard::StatsAggregator

Inherits:
Object
  • Object
show all
Defined in:
lib/ses_dashboard/stats_aggregator.rb

Overview

Aggregates email statistics for the dashboard.

Usage:

agg = StatsAggregator.new(project_id: project.id, from: 14.days.ago, to: Time.current)
agg.counters       # => { sent: 100, delivered: 90, bounced: 3, ... }
agg.time_series    # => { labels: ["2024-01-01", ...], data: [5, 12, ...] }
agg.total_opens    # => 45
agg.total_clicks   # => 12

Instance Method Summary collapse

Constructor Details

#initialize(project_id: nil, from: nil, to: nil) ⇒ StatsAggregator

Returns a new instance of StatsAggregator.



12
13
14
15
16
# File 'lib/ses_dashboard/stats_aggregator.rb', line 12

def initialize(project_id: nil, from: nil, to: nil)
  @project_id = project_id
  @from       = from
  @to         = to
end

Instance Method Details

#countersObject

Returns counts grouped by status. “not_delivered” is derived as the sum of bounced + complained + rejected.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/ses_dashboard/stats_aggregator.rb', line 20

def counters
  scope = base_scope
  counts = scope.group(:status).count

  not_delivered = (counts["bounced"] || 0) +
                  (counts["complained"] || 0) +
                  (counts["rejected"] || 0)

  {
    total:         scope.count,
    sent:          counts["sent"] || 0,
    delivered:     counts["delivered"] || 0,
    bounced:       counts["bounced"] || 0,
    complained:    counts["complained"] || 0,
    rejected:      counts["rejected"] || 0,
    failed:        counts["failed"] || 0,
    not_delivered: not_delivered
  }
end

#time_seriesObject

Returns a Chart.js-compatible hash: { labels: […], data: […] } Groups by calendar day over the from..to range, filling gaps with zero.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/ses_dashboard/stats_aggregator.rb', line 50

def time_series
  from = effective_from
  to   = effective_to

  expr = Arel.sql(date_group_expr)
  raw = base_scope
          .where(sent_at: from..to)
          .group(expr)
          .order(expr)
          .count

  all_days = date_range_days(from, to)
  labels   = all_days.map { |d| d.strftime("%Y-%m-%d") }
  data     = all_days.map { |d| raw[d.strftime("%Y-%m-%d")] || 0 }

  { labels: labels, data: data }
end

#total_clicksObject



44
45
46
# File 'lib/ses_dashboard/stats_aggregator.rb', line 44

def total_clicks
  base_scope.sum(:clicks)
end

#total_opensObject



40
41
42
# File 'lib/ses_dashboard/stats_aggregator.rb', line 40

def total_opens
  base_scope.sum(:opens)
end