refactor: derive summary selects from metric registry
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
# Raw reporting events and rollup rows do not share a single metric namespace.
|
||||
# This registry keeps the mapping aligned across write and read paths.
|
||||
# Raw reporting events and rollup rows do not share a single metric namespace; this registry keeps write and read paths aligned.
|
||||
module ReportingEvents::MetricRegistry
|
||||
SUMMARY_METRICS = {
|
||||
resolutions_count: :resolved_conversations_count,
|
||||
avg_resolution_time: :avg_resolution_time,
|
||||
avg_first_response_time: :avg_first_response_time,
|
||||
reply_time: :avg_reply_time
|
||||
}.freeze
|
||||
|
||||
EVENT_METRICS = {
|
||||
'conversation_resolved' => lambda do |values|
|
||||
{
|
||||
@@ -18,36 +24,13 @@ module ReportingEvents::MetricRegistry
|
||||
conversations_count: { aggregate: :count }.freeze,
|
||||
incoming_messages_count: { aggregate: :count }.freeze,
|
||||
outgoing_messages_count: { aggregate: :count }.freeze,
|
||||
avg_first_response_time: {
|
||||
raw_event_name: :first_response,
|
||||
rollup_metric: :first_response,
|
||||
aggregate: :average
|
||||
}.freeze,
|
||||
avg_resolution_time: {
|
||||
raw_event_name: :conversation_resolved,
|
||||
rollup_metric: :resolution_time,
|
||||
aggregate: :average
|
||||
}.freeze,
|
||||
reply_time: {
|
||||
raw_event_name: :reply_time,
|
||||
rollup_metric: :reply_time,
|
||||
aggregate: :average
|
||||
}.freeze,
|
||||
resolutions_count: {
|
||||
raw_event_name: :conversation_resolved,
|
||||
rollup_metric: :resolutions_count,
|
||||
aggregate: :count
|
||||
}.freeze,
|
||||
bot_resolutions_count: {
|
||||
raw_event_name: :conversation_bot_resolved,
|
||||
rollup_metric: :bot_resolutions_count,
|
||||
aggregate: :count
|
||||
}.freeze,
|
||||
avg_first_response_time: { raw_event_name: :first_response, rollup_metric: :first_response, aggregate: :average }.freeze,
|
||||
avg_resolution_time: { raw_event_name: :conversation_resolved, rollup_metric: :resolution_time, aggregate: :average }.freeze,
|
||||
reply_time: { raw_event_name: :reply_time, rollup_metric: :reply_time, aggregate: :average }.freeze,
|
||||
resolutions_count: { raw_event_name: :conversation_resolved, rollup_metric: :resolutions_count, aggregate: :count }.freeze,
|
||||
bot_resolutions_count: { raw_event_name: :conversation_bot_resolved, rollup_metric: :bot_resolutions_count, aggregate: :count }.freeze,
|
||||
bot_handoffs_count: {
|
||||
raw_event_name: :conversation_bot_handoff,
|
||||
rollup_metric: :bot_handoffs_count,
|
||||
aggregate: :count,
|
||||
raw_count_strategy: :distinct_conversation
|
||||
raw_event_name: :conversation_bot_handoff, rollup_metric: :bot_handoffs_count, aggregate: :count, raw_count_strategy: :distinct_conversation
|
||||
}.freeze
|
||||
}.freeze
|
||||
|
||||
@@ -101,17 +84,21 @@ module ReportingEvents::MetricRegistry
|
||||
report_metric(metric)&.dig(:raw_event_name)
|
||||
end
|
||||
|
||||
def count_metric(count)
|
||||
def summary_metrics
|
||||
SUMMARY_METRICS.map do |metric_name, summary_key|
|
||||
report_metric(metric_name).merge(metric_name: metric_name, summary_key: summary_key)
|
||||
end
|
||||
end
|
||||
|
||||
private_class_method def count_metric(count)
|
||||
{ count: count, sum_value: 0, sum_value_business_hours: 0 }
|
||||
end
|
||||
private_class_method :count_metric
|
||||
|
||||
def duration_metric(values)
|
||||
private_class_method def duration_metric(values)
|
||||
{
|
||||
count: values[:count],
|
||||
sum_value: values[:sum_value],
|
||||
sum_value_business_hours: values[:sum_value_business_hours]
|
||||
}
|
||||
end
|
||||
private_class_method :duration_metric
|
||||
end
|
||||
|
||||
@@ -90,6 +90,10 @@ class Reports::DataSource
|
||||
report_metric&.dig(:raw_count_strategy)
|
||||
end
|
||||
|
||||
def summary_metrics
|
||||
@summary_metrics ||= ReportingEvents::MetricRegistry.summary_metrics
|
||||
end
|
||||
|
||||
def use_business_hours?
|
||||
ActiveModel::Type::Boolean.new.cast(business_hours)
|
||||
end
|
||||
|
||||
@@ -105,37 +105,27 @@ class Reports::RawDataSource < Reports::DataSource
|
||||
def merge_summary_results(metric_results, conversation_counts)
|
||||
(metric_results.keys | conversation_counts.keys).each_with_object({}) do |dimension_id, results|
|
||||
record = metric_results[dimension_id]
|
||||
|
||||
results[dimension_id] = {
|
||||
conversations_count: conversation_counts[dimension_id].to_i,
|
||||
resolved_conversations_count: record&.resolved_count.to_i,
|
||||
avg_resolution_time: record&.avg_resolution_time,
|
||||
avg_first_response_time: record&.avg_first_response_time,
|
||||
avg_reply_time: record&.avg_reply_time
|
||||
}
|
||||
results[dimension_id] = summary_attributes_for(record, conversation_counts[dimension_id])
|
||||
end
|
||||
end
|
||||
|
||||
def summary_select_fields
|
||||
[
|
||||
"#{summary_group_by_key} as #{summary_index_key}",
|
||||
count_select(:resolutions_count, :resolved_count),
|
||||
average_select(:avg_resolution_time, :avg_resolution_time),
|
||||
average_select(:avg_first_response_time, :avg_first_response_time),
|
||||
average_select(:reply_time, :avg_reply_time)
|
||||
]
|
||||
["#{summary_group_by_key} as #{summary_index_key}"] + summary_metrics.map { |definition| summary_select_field(definition) }
|
||||
end
|
||||
|
||||
def count_select(metric_name, alias_name)
|
||||
"COUNT(CASE WHEN name = '#{raw_metric_event_name(metric_name)}' THEN 1 END) as #{alias_name}"
|
||||
def summary_select_field(definition)
|
||||
if definition[:aggregate] == :count
|
||||
"COUNT(CASE WHEN name = '#{definition[:raw_event_name]}' THEN 1 END) as #{definition[:summary_key]}"
|
||||
else
|
||||
"AVG(CASE WHEN name = '#{definition[:raw_event_name]}' THEN #{average_value_key} END) as #{definition[:summary_key]}"
|
||||
end
|
||||
end
|
||||
|
||||
def average_select(metric_name, alias_name)
|
||||
"AVG(CASE WHEN name = '#{raw_metric_event_name(metric_name)}' THEN #{average_value_key} END) as #{alias_name}"
|
||||
end
|
||||
|
||||
def raw_metric_event_name(metric_name)
|
||||
ReportingEvents::MetricRegistry.raw_event_name_for(metric_name)
|
||||
def summary_attributes_for(record, conversations_count = 0)
|
||||
summary_metrics.each_with_object({ conversations_count: conversations_count.to_i }) do |definition, attributes|
|
||||
value = record&.public_send(definition[:summary_key])
|
||||
attributes[definition[:summary_key]] = definition[:aggregate] == :count ? value.to_i : value
|
||||
end
|
||||
end
|
||||
|
||||
def summary_group_by_key
|
||||
|
||||
@@ -90,38 +90,44 @@ class Reports::RollupDataSource < Reports::DataSource
|
||||
end
|
||||
|
||||
def summary_select_fields
|
||||
['dimension_id'] + summary_metrics.flat_map { |definition| summary_select_fields_for_metric(definition) }
|
||||
end
|
||||
|
||||
def summary_select_fields_for_metric(definition)
|
||||
return [sum_count_select(definition[:rollup_metric], definition[:summary_key])] if definition[:aggregate] == :count
|
||||
|
||||
[
|
||||
'dimension_id',
|
||||
sum_count_select(:resolutions_count, :resolved_count),
|
||||
sum_count_select(:avg_resolution_time, :resolution_count),
|
||||
sum_value_select(:avg_resolution_time, :resolution_sum_value),
|
||||
sum_count_select(:avg_first_response_time, :first_response_count),
|
||||
sum_value_select(:avg_first_response_time, :first_response_sum_value),
|
||||
sum_count_select(:reply_time, :reply_count),
|
||||
sum_value_select(:reply_time, :reply_sum_value)
|
||||
sum_count_select(definition[:rollup_metric], summary_count_alias(definition)),
|
||||
sum_value_select(definition[:rollup_metric], summary_sum_alias(definition))
|
||||
]
|
||||
end
|
||||
|
||||
def sum_count_select(metric_name, alias_name)
|
||||
"SUM(CASE WHEN metric = '#{rollup_metric_name(metric_name)}' THEN count ELSE 0 END) as #{alias_name}"
|
||||
def sum_count_select(rollup_metric_name, alias_name)
|
||||
"SUM(CASE WHEN metric = '#{rollup_metric_name}' THEN count ELSE 0 END) as #{alias_name}"
|
||||
end
|
||||
|
||||
def sum_value_select(metric_name, alias_name)
|
||||
"SUM(CASE WHEN metric = '#{rollup_metric_name(metric_name)}' THEN #{rollup_value_column} ELSE 0 END) as #{alias_name}"
|
||||
end
|
||||
|
||||
def rollup_metric_name(metric_name)
|
||||
ReportingEvents::MetricRegistry.rollup_metric_for(metric_name)
|
||||
def sum_value_select(rollup_metric_name, alias_name)
|
||||
"SUM(CASE WHEN metric = '#{rollup_metric_name}' THEN #{rollup_value_column} ELSE 0 END) as #{alias_name}"
|
||||
end
|
||||
|
||||
def summary_attributes_for(row, conversations_count = 0)
|
||||
{
|
||||
conversations_count: conversations_count.to_i,
|
||||
resolved_conversations_count: row&.resolved_count.to_i,
|
||||
avg_resolution_time: average_from(row&.resolution_sum_value, row&.resolution_count),
|
||||
avg_first_response_time: average_from(row&.first_response_sum_value, row&.first_response_count),
|
||||
avg_reply_time: average_from(row&.reply_sum_value, row&.reply_count)
|
||||
}
|
||||
summary_metrics.each_with_object({ conversations_count: conversations_count.to_i }) do |definition, attributes|
|
||||
attributes[definition[:summary_key]] = summary_value_for(row, definition)
|
||||
end
|
||||
end
|
||||
|
||||
def summary_value_for(row, definition)
|
||||
return row&.public_send(definition[:summary_key]).to_i if definition[:aggregate] == :count
|
||||
|
||||
average_from(row&.public_send(summary_sum_alias(definition)), row&.public_send(summary_count_alias(definition)))
|
||||
end
|
||||
|
||||
def summary_count_alias(definition)
|
||||
"#{definition[:summary_key]}_count"
|
||||
end
|
||||
|
||||
def summary_sum_alias(definition)
|
||||
"#{definition[:summary_key]}_sum_value"
|
||||
end
|
||||
|
||||
def dimension_id_for_rollup
|
||||
|
||||
Reference in New Issue
Block a user