# Re-aggregate distinct membership; tag row tuples alone use additive contributions. 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 # Materialise full-cell membership once, including omitted multi-value axes. membership = @population.scope.except(:select, :order) joins = @axes.joins membership = membership.joins(joins) unless joins.empty? # Retain exactly the records contributing a full cell, including changed_field. basis = membership.select('v.*').distinct .limit(18_446_744_073_709_551_615).to_sql 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, :where, :from).from('population_members v') additive = @axes.rows.any? { _1['field'] == 'tags' } retained = additive ? (0...@axes.rows.length).to_a | indexes : indexes joins = @axes.joins(retained.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 = indexes.each_with_index.map { |key, index| "a#{ key } 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'] if additive # Sum full row tuples, not page cells; preserve DISTINCT inside each tuple. inner = @axes.grouped_sql(scope, retained) coordinates = indexes.map { "a#{ _1 }" } projected = coordinates.each_with_index.map { |key, index| "#{ key } AS v#{ index }" } output = ["#{ row_depth } AS row_depth", "#{ column_depth } AS column_depth"] + projected + padding + ['SUM(count) AS count'] grouping = coordinates.empty? ? '' : " GROUP BY #{ coordinates.join(', ') }" "SELECT #{ output.join(', ') } FROM (#{ inner }) leaf#{ grouping }" else inner = @axes.grouped_sql(scope, indexes) "SELECT #{ fields.join(', ') } FROM (#{ inner }) grouped" end end end return [] if queries.empty? sql = queries.map { "(#{ _1 })" }.join(' UNION ALL ') @population.definition.model.connection.select_all( "WITH population_members AS (#{ basis }) " + "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 }"] }, row_depth:, column_depth:, label_key: CountsPivotLayout.label_key(@axes.rows.length, @axes.columns.length, row_depth, column_depth), count: record['count'].to_i } end end end