このコミットが含まれているのは:
@@ -98,10 +98,10 @@ class CountsTableQuery
|
||||
extras << "sort#{ index }.count AS sort#{ index }"
|
||||
"sort#{ index } IS NULL ASC, sort#{ index } #{ direction.upcase }"
|
||||
elsif row_keys.include?(key)
|
||||
"#{ key } IS NULL ASC, #{ key } #{ direction.upcase }"
|
||||
axis_order_sql(key, direction)
|
||||
end
|
||||
end
|
||||
order_rows = row_sort + row_keys.map { "#{ _1 } IS NULL, #{ _1 }" }
|
||||
order_rows = row_sort + row_keys.map { axis_order_sql(_1) }
|
||||
order_rows = ['singleton ASC'] if order_rows.empty?
|
||||
grouped = "SELECT #{ row_selection } FROM cells #{ row_group }"
|
||||
selection = (['grouped.*'] + extras).join(', ')
|
||||
@@ -115,10 +115,10 @@ class CountsTableQuery
|
||||
order_cols = @sort.filter_map do |key, direction|
|
||||
next unless key.match?(/\Aa[0-9]+\z/) && !row_keys.include?(key)
|
||||
|
||||
"cells.#{ key } #{ direction.upcase }"
|
||||
axis_order_sql(key, direction, qualifier: 'cells')
|
||||
end
|
||||
order = ['page_rows.position'] + order_cols +
|
||||
axes.all.each_index.map { "cells.a#{ _1 }" }
|
||||
axes.all.each_index.map { axis_order_sql("a#{ _1 }", qualifier: 'cells') }
|
||||
records = @connection.select_all(<<~SQL)
|
||||
#{ prefix }, row_groups AS (#{ group_sql }),
|
||||
numbered AS (SELECT row_groups.*,
|
||||
@@ -231,39 +231,41 @@ class CountsTableQuery
|
||||
# detail pagination continue to use the authorised population exclusively.
|
||||
source = CountsPopulation.new(
|
||||
@params.merge('execution_at' => population.at.iso8601(6)), authorisation_flg: false)
|
||||
records = source.scope.except(:select).optimizer_hints('MAX_EXECUTION_TIME(10000)').count
|
||||
denied = source.scope.except(:select)
|
||||
.where(Arel.sql("NOT (#{ HistoryAccess.sql(@definition.model, 'v') })"))
|
||||
.optimizer_hints('MAX_EXECUTION_TIME(10000)').count
|
||||
rows = records
|
||||
if mode == 'summary'
|
||||
unrestricted_axes = CountsAxes.new(source)
|
||||
relation = source.scope
|
||||
joins = unrestricted_axes.joins
|
||||
relation = relation.joins(joins) unless joins.empty?
|
||||
expressions = unrestricted_axes.expressions
|
||||
keys = axes.rows.each_index.map { "a#{ _1 }" }
|
||||
if keys.empty?
|
||||
rows = 1
|
||||
else
|
||||
selected = expressions.each_with_index.map { |expression, index|
|
||||
"#{ expression } AS a#{ index }"
|
||||
}
|
||||
sql = relation.except(:select).select(Arel.sql(selected.join(', ')))
|
||||
.distinct.to_sql
|
||||
prefix = "WITH cells AS (#{ sql })"
|
||||
groups = @connection.select_value(<<~SQL).to_i
|
||||
#{ prefix }
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10000) */ COUNT(*) FROM (
|
||||
SELECT #{ keys.join(', ') } FROM cells GROUP BY #{ keys.join(', ') }
|
||||
) output_groups
|
||||
SQL
|
||||
rows = output_row_count(prefix, keys, CountsPivotLayout.depths(keys, @sort), groups)
|
||||
end
|
||||
end
|
||||
rows = if mode == 'details'
|
||||
source.scope.except(:select).optimizer_hints('MAX_EXECUTION_TIME(10000)').count
|
||||
else
|
||||
summary_output_count(source)
|
||||
end
|
||||
@output_totals = { output_count: rows, excluded_count: denied }
|
||||
end
|
||||
|
||||
def summary_output_count(source)
|
||||
keys = axes.rows.each_index.map { "a#{ _1 }" }
|
||||
return 1 if keys.empty?
|
||||
|
||||
unrestricted_axes = CountsAxes.new(source)
|
||||
relation = source.scope
|
||||
joins = unrestricted_axes.joins
|
||||
relation = relation.joins(joins) unless joins.empty?
|
||||
expressions = unrestricted_axes.expressions
|
||||
selected = expressions.each_with_index.map { |expression, index|
|
||||
"#{ expression } AS a#{ index }"
|
||||
}
|
||||
sql = relation.except(:select).select(Arel.sql(selected.join(', ')))
|
||||
.distinct.to_sql
|
||||
prefix = "WITH cells AS (#{ sql })"
|
||||
groups = @connection.select_value(<<~SQL).to_i
|
||||
#{ prefix }
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10000) */ COUNT(*) FROM (
|
||||
SELECT #{ keys.join(', ') } FROM cells GROUP BY #{ keys.join(', ') }
|
||||
) output_groups
|
||||
SQL
|
||||
output_row_count(prefix, keys, CountsPivotLayout.depths(keys, @sort), groups)
|
||||
end
|
||||
|
||||
def locale = @locale ||= Locale.find_by!(code: @params.fetch('locale', 'ja'))
|
||||
|
||||
def limited_columns(prefix)
|
||||
@@ -272,9 +274,7 @@ class CountsTableQuery
|
||||
|
||||
configured = @sort.select { |key, _direction| keys.include?(key) }
|
||||
directions = (configured + keys.map { [_1, 'asc'] }).uniq { _1.first }
|
||||
order = directions.map { |key, direction|
|
||||
"#{ key } IS NULL ASC, #{ key } #{ direction.upcase }"
|
||||
}.join(', ')
|
||||
order = directions.map { |key, direction| axis_order_sql(key, direction) }.join(', ')
|
||||
custom = QueryState.records(@params, 'column_order')
|
||||
if custom.any?
|
||||
raise ArgumentError unless custom.map { _1['value'] }.uniq.length == custom.length
|
||||
@@ -311,6 +311,19 @@ class CountsTableQuery
|
||||
source.select(Arel.sql(selected.join(', '))).to_sql
|
||||
end
|
||||
|
||||
def axis_order_sql(key, direction = 'asc', qualifier: nil)
|
||||
column = qualifier ? "#{ qualifier }.#{ key }" : key
|
||||
expression = column
|
||||
if axes.all.fetch(key.delete_prefix('a').to_i).fetch('field') == 'category'
|
||||
# Tag's enum preserves the same category order as TagsController.
|
||||
cases = Tag.categories.keys.each_with_index.map { |category, index|
|
||||
"WHEN #{ @connection.quote(category) } THEN #{ index }"
|
||||
}.join(' ')
|
||||
expression = "CASE #{ column } #{ cases } ELSE #{ Tag.categories.length } END"
|
||||
end
|
||||
"#{ column } IS NULL ASC, #{ expression } #{ direction.upcase }"
|
||||
end
|
||||
|
||||
def measure_values(key)
|
||||
records = QueryState.records(@params, 'measures').select { _1['key'] == key }
|
||||
raise ArgumentError if records.empty?
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする