60 行
2.7 KiB
Ruby
60 行
2.7 KiB
Ruby
# Re-aggregate the population, never add up already grouped cells (multi-value axes overlap).
|
|
class CountsPivotTotals
|
|
def initialize(population, axes, row_headers, column_headers)
|
|
@population = population
|
|
@axes = axes
|
|
@rows = row_headers.group_by { _1[:values].length }
|
|
@columns = column_headers.group_by { _1[:values].length }
|
|
end
|
|
|
|
def call
|
|
queries = @rows.flat_map do |row_depth, headers|
|
|
@columns.filter_map do |column_depth, columns|
|
|
next if row_depth == @axes.rows.length && column_depth == @axes.columns.length
|
|
|
|
indexes = (0...row_depth).to_a +
|
|
(0...column_depth).map { @axes.rows.length + _1 }
|
|
expressions = indexes.map { @axes.expressions[_1] }
|
|
scope = @population.scope.except(:select, :order)
|
|
joins = @axes.joins(indexes.map { @axes.all[_1].fetch('field') })
|
|
scope = scope.joins(joins) unless joins.empty?
|
|
if row_depth.positive?
|
|
tuples = headers.map { _1[:values] }.uniq
|
|
predicate = tuples.map { Array.new(row_depth) { |i|
|
|
"(#{ expressions[i] }) <=> ?"
|
|
}.join(' AND ') }.map { "(#{ _1 })" }.join(' OR ')
|
|
scope = scope.where(predicate, *tuples.flatten)
|
|
end
|
|
if column_depth.positive?
|
|
tuples = columns.map { _1[:values] }.uniq
|
|
predicate = tuples.map { Array.new(column_depth) { |i|
|
|
"(#{ expressions[row_depth + i] }) <=> ?"
|
|
}.join(' AND ') }.map { "(#{ _1 })" }.join(' OR ')
|
|
scope = scope.where(predicate, *tuples.flatten)
|
|
end
|
|
grouped = expressions.each_with_index.map { |expression, index|
|
|
"#{ expression } AS v#{ index }"
|
|
}
|
|
# Fixed-width result coordinates, independent of NULL and of translated labels.
|
|
padding = (expressions.length...@axes.all.length).map { "NULL AS v#{ _1 }" }
|
|
fields = ["#{ row_depth } AS row_depth", "#{ column_depth } AS column_depth"] +
|
|
grouped + padding + ['COUNT(DISTINCT v.id) AS count']
|
|
scope = scope.group(*expressions.map { Arel.sql(_1) }) if expressions.any?
|
|
scope.optimizer_hints('MAX_EXECUTION_TIME(10000)')
|
|
.select(Arel.sql(fields.join(', '))).to_sql
|
|
end
|
|
end
|
|
return [] if queries.empty?
|
|
|
|
sql = queries.map { "(#{ _1 })" }.join(' UNION ALL ')
|
|
@population.definition.model.connection.select_all(
|
|
"SELECT /*+ MAX_EXECUTION_TIME(10000) */ * FROM (#{ sql }) totals").map do |record|
|
|
row_depth = record['row_depth'].to_i
|
|
column_depth = record['column_depth'].to_i
|
|
{ row: (0...row_depth).map { record["v#{ _1 }"] },
|
|
column: (0...column_depth).map { record["v#{ row_depth + _1 }"] },
|
|
count: record['count'].to_i }
|
|
end
|
|
end
|
|
end
|