feat: Add rollup read path to report builders

This commit is contained in:
Shivam Mishra
2026-02-11 21:28:17 +05:30
parent 0e35067bc8
commit 46ab6c3946
4 changed files with 218 additions and 5 deletions
@@ -1,5 +1,6 @@
class V2::Reports::BaseSummaryBuilder
include DateRangeHelper
include V2::Reports::Concerns::RollupConditions
def build
load_data
@@ -10,7 +11,7 @@ class V2::Reports::BaseSummaryBuilder
def load_data
@conversations_count = fetch_conversations_count
load_reporting_events_data
use_rollup? ? load_rollup_data : load_reporting_events_data
end
def load_reporting_events_data
@@ -34,6 +35,44 @@ class V2::Reports::BaseSummaryBuilder
@avg_reply_time = results.transform_values(&:avg_reply_time)
end
def load_rollup_data
group_by_key.to_s.split('.').last
dimension_type = dimension_type_to_rollup
# Fetch rollup data grouped by dimension_id
rollup_rows = ReportingEventRollup.where(
account_id: account.id,
dimension_type: dimension_type,
date: range.first..range.last
).group(:dimension_id).select(
'dimension_id',
'SUM(CASE WHEN metric = \'resolutions_count\' THEN count ELSE 0 END) as resolved_count',
'SUM(CASE WHEN metric = \'resolution_time\' THEN count ELSE 0 END) as resolution_count',
'SUM(CASE WHEN metric = \'resolution_time\' THEN sum_value ELSE 0 END) as resolution_sum_value',
'SUM(CASE WHEN metric = \'first_response\' THEN count ELSE 0 END) as first_response_count',
'SUM(CASE WHEN metric = \'first_response\' THEN sum_value ELSE 0 END) as first_response_sum_value',
'SUM(CASE WHEN metric = \'reply_time\' THEN count ELSE 0 END) as reply_count',
'SUM(CASE WHEN metric = \'reply_time\' THEN sum_value ELSE 0 END) as reply_sum_value'
)
# Convert to the expected format
results = {}
rollup_rows.each do |row|
results[row.dimension_id] = row
end
@resolved_count = results.transform_values { |r| r.resolved_count.to_i }
@avg_resolution_time = results.transform_values do |r|
r.resolution_count.to_i.zero? ? nil : (r.resolution_sum_value.to_f / r.resolution_count.to_i)
end
@avg_first_response_time = results.transform_values do |r|
r.first_response_count.to_i.zero? ? nil : (r.first_response_sum_value.to_f / r.first_response_count.to_i)
end
@avg_reply_time = results.transform_values do |r|
r.reply_count.to_i.zero? ? nil : (r.reply_sum_value.to_f / r.reply_count.to_i)
end
end
def reporting_events
@reporting_events ||= account.reporting_events.where(created_at: range)
end
@@ -1,5 +1,15 @@
class V2::Reports::Timeseries::AverageReportBuilder < V2::Reports::Timeseries::BaseTimeseriesBuilder
def timeseries
use_rollup? ? rollup_timeseries : raw_timeseries
end
def aggregate_value
use_rollup? ? rollup_aggregate_value : raw_aggregate_value
end
private
def raw_timeseries
grouped_average_time = reporting_events.average(average_value_key)
grouped_event_count = reporting_events.count
grouped_average_time.each_with_object([]) do |element, arr|
@@ -12,11 +22,90 @@ class V2::Reports::Timeseries::AverageReportBuilder < V2::Reports::Timeseries::B
end
end
def aggregate_value
def rollup_timeseries
dimension_type = dimension_type_to_rollup
dimension_id = dimension_id_for_rollup
metric = metric_to_rollup_metric(params[:metric])
rollup_rows = ReportingEventRollup.where(
account_id: account.id,
metric: metric,
dimension_type: dimension_type,
dimension_id: dimension_id,
date: range.first..range.last
)
group_and_aggregate_rollup(rollup_rows)
end
def raw_aggregate_value
object_scope.average(average_value_key)
end
private
def rollup_aggregate_value
dimension_type = dimension_type_to_rollup
dimension_id = dimension_id_for_rollup
metric = metric_to_rollup_metric(params[:metric])
result = ReportingEventRollup.where(
account_id: account.id,
metric: metric,
dimension_type: dimension_type,
dimension_id: dimension_id,
date: range.first..range.last
).pluck(Arel.sql('SUM(count), SUM(sum_value)'))
.first
return nil if result.blank? || result[0].to_i.zero?
result[1].to_f / result[0].to_i
end
def dimension_id_for_rollup
case params[:type].to_s
when 'account'
account.id
when 'agent'
params[:id].to_i
when 'inbox'
params[:id].to_i
when 'team'
params[:id].to_i
end
end
def group_and_aggregate_rollup(rollup_rows)
grouped_data = {}
rollup_rows.each do |row|
date_key = case group_by
when 'day'
row.date
when 'week'
row.date.beginning_of_week(:monday)
when 'month'
row.date.beginning_of_month
when 'year'
row.date.beginning_of_year
else
row.date
end
grouped_data[date_key] ||= { count: 0, sum_value: 0.0 }
grouped_data[date_key][:count] += row.count
grouped_data[date_key][:sum_value] += row.sum_value
end
grouped_data.each_with_object([]) do |(date_key, data), arr|
next if data[:count].zero?
arr << {
value: data[:sum_value] / data[:count],
timestamp: date_key.in_time_zone(timezone).to_i,
count: data[:count]
}
end.sort_by { |h| h[:timestamp] }
end
def event_name
metric_to_event_name = {
@@ -1,6 +1,7 @@
class V2::Reports::Timeseries::BaseTimeseriesBuilder
include TimezoneHelper
include DateRangeHelper
include V2::Reports::Concerns::RollupConditions
DEFAULT_GROUP_BY = 'day'.freeze
pattr_initialize :account, :params
@@ -1,5 +1,15 @@
class V2::Reports::Timeseries::CountReportBuilder < V2::Reports::Timeseries::BaseTimeseriesBuilder
def timeseries
use_rollup? ? rollup_timeseries : raw_timeseries
end
def aggregate_value
use_rollup? ? rollup_aggregate_value : raw_aggregate_value
end
private
def raw_timeseries
grouped_count.each_with_object([]) do |element, arr|
event_date, event_count = element
@@ -11,11 +21,85 @@ class V2::Reports::Timeseries::CountReportBuilder < V2::Reports::Timeseries::Bas
end
end
def aggregate_value
def rollup_timeseries
metric = metric_to_rollup_metric(params[:metric])
return [] if metric.blank?
dimension_type = dimension_type_to_rollup
dimension_id = dimension_id_for_rollup
rollup_rows = ReportingEventRollup.where(
account_id: account.id,
metric: metric,
dimension_type: dimension_type,
dimension_id: dimension_id,
date: range.first..range.last
)
group_and_aggregate_rollup_counts(rollup_rows)
end
def raw_aggregate_value
object_scope.count
end
private
def rollup_aggregate_value
metric = metric_to_rollup_metric(params[:metric])
return 0 if metric.blank?
dimension_type = dimension_type_to_rollup
dimension_id = dimension_id_for_rollup
ReportingEventRollup.where(
account_id: account.id,
metric: metric,
dimension_type: dimension_type,
dimension_id: dimension_id,
date: range.first..range.last
).sum(:count).to_i
end
def dimension_id_for_rollup
case params[:type].to_s
when 'account'
account.id
when 'agent'
params[:id].to_i
when 'inbox'
params[:id].to_i
when 'team'
params[:id].to_i
end
end
def group_and_aggregate_rollup_counts(rollup_rows)
grouped_data = {}
rollup_rows.each do |row|
date_key = case group_by
when 'day'
row.date
when 'week'
row.date.beginning_of_week(:monday)
when 'month'
row.date.beginning_of_month
when 'year'
row.date.beginning_of_year
else
row.date
end
grouped_data[date_key] ||= 0
grouped_data[date_key] += row.count
end
grouped_data.each_with_object([]) do |(date_key, count), arr|
arr << {
value: count,
timestamp: date_key.in_time_zone(timezone).to_i
}
end.sort_by { |h| h[:timestamp] }
end
def metric
@metric ||= params[:metric]