diff options
Diffstat (limited to 'lib/event_filter.rb')
-rw-r--r-- | lib/event_filter.rb | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 8833207dd1d..8c3377fdb80 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -15,6 +15,8 @@ class EventFilter WIKI = 'wiki' DESIGNS = 'designs' + PROJECT_ONLY_EVENT_TYPES = [PUSH, MERGED, TEAM, ISSUE, DESIGNS].freeze + def initialize(filter) # Split using comma to maintain backward compatibility Ex/ "filter1,filter2" filter = filter.to_s.split(',')[0].to_s @@ -49,13 +51,15 @@ class EventFilter # rubocop: disable Metrics/CyclomaticComplexity # This method build specialized in-operator optimized queries based on different # filter parameters. All queries will benefit from the index covering the following columns: - # author_id target_type action id + # * author_id target_type action id + # * project_id target_type action id + # * group_id target_type action id # # More context: https://docs.gitlab.com/ee/development/database/efficient_in_operator_queries.html#the-inoperatoroptimization-module - def in_operator_query_builder_params(user_ids) + def in_operator_query_builder_params(array_data) case filter when ALL - in_operator_params(array_scope_ids: user_ids) + in_operator_params(array_data: array_data) when PUSH # Here we need to add an order hint column to force the correct index usage. # Without the order hint, the following conditions will use the `index_events_on_author_id_and_id` @@ -66,25 +70,25 @@ class EventFilter # to use the correct index: # > target_type IS NULL AND action = 5 AND author_id = X ORDER BY target_type DESC, id DESC in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.where(target_type: nil).pushed_action, order_hint_column: :target_type ) when MERGED in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.where(target_type: MergeRequest.to_s).merged_action ) when COMMENTS in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.commented_action, in_column: :target_type, in_values: [Note, *Note.descendants].map(&:name) # To make the query efficient we need to list all Note classes ) when TEAM in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.where(target_type: nil), order_hint_column: :target_type, in_column: :action, @@ -92,34 +96,34 @@ class EventFilter ) when ISSUE in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.where(target_type: Issue.name), in_column: :action, in_values: Event.actions.values_at(*Event::ISSUE_ACTIONS) ) when WIKI in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.for_wiki_page, in_column: :action, in_values: Event.actions.values_at(*Event::WIKI_ACTIONS) ) when DESIGNS in_operator_params( - array_scope_ids: user_ids, + array_data: array_data, scope: Event.for_design, in_column: :action, in_values: Event.actions.values_at(*Event::DESIGN_ACTIONS) ) else - in_operator_params(array_scope_ids: user_ids) + in_operator_params(array_data: array_data) end end # rubocop: enable Metrics/CyclomaticComplexity private - def in_operator_params(array_scope_ids:, scope: nil, in_column: nil, in_values: nil, order_hint_column: nil) + def in_operator_params(array_data:, scope: nil, in_column: nil, in_values: nil, order_hint_column: nil) base_scope = Event.all base_scope = base_scope.merge(scope) if scope @@ -146,8 +150,8 @@ class EventFilter base_scope = base_scope.reorder(order) array_params = in_operator_array_params( - array_scope_ids: array_scope_ids, scope: base_scope, + array_data: array_data, in_column: in_column, in_values: in_values ) @@ -161,22 +165,30 @@ class EventFilter # This method builds the array_ parameters # without in_column parameter: uses one IN filter: author_id # with in_column: two IN filters: author_id, (target_type OR action) - def in_operator_array_params(scope:, array_scope_ids:, in_column: nil, in_values: nil) + # @param array_data [Hash] Must contain the scope_ids, scope_model, mapping_column keys + def in_operator_array_params(scope:, array_data:, in_column: nil, in_values: nil) + array_scope_ids = array_data[:scope_ids] + array_scope_model = array_data[:scope_model] + array_mapping_column = array_data[:mapping_column] + + # Adding non-existent record to generate valid SQL if array_scope_ids is empty + array_scope_ids << 0 if array_scope_ids.empty? + if in_column - # Builds Carthesian product of the in_values and the array_scope_ids (in this case: user_ids). + # Builds Cartesian product of the in_values and the array_scope_ids (in this case: user_ids). # The process is described here: https://docs.gitlab.com/ee/development/database/efficient_in_operator_queries.html#multiple-in-queries # VALUES ((array_scope_ids[0], in_values[0]), (array_scope_ids[1], in_values[0]) ...) cartesian = array_scope_ids.product(in_values) - user_with_column_list = Arel::Nodes::ValuesList.new(cartesian) + column_list = Arel::Nodes::ValuesList.new(cartesian) as = "array_ids(id, #{Event.connection.quote_column_name(in_column)})" - from = Arel::Nodes::Grouping.new(user_with_column_list).as(as) + from = Arel::Nodes::Grouping.new(column_list).as(as) { - array_scope: User.select(:id, in_column).from(from), - array_mapping_scope: -> (author_id_expression, in_column_expression) do + array_scope: array_scope_model.select(:id, in_column).from(from), + array_mapping_scope: -> (primary_id_expression, in_column_expression) do Event .merge(scope) - .where(Event.arel_table[:author_id].eq(author_id_expression)) + .where(Event.arel_table[array_mapping_column].eq(primary_id_expression)) .where(Event.arel_table[in_column].eq(in_column_expression)) end } @@ -186,11 +198,11 @@ class EventFilter array_ids_list = Arel::Nodes::ValuesList.new(array_scope_ids.map { |id| [id] }) from = Arel::Nodes::Grouping.new(array_ids_list).as('array_ids(id)') { - array_scope: User.select(:id).from(from), - array_mapping_scope: -> (author_id_expression) do + array_scope: array_scope_model.select(:id).from(from), + array_mapping_scope: -> (primary_id_expression) do Event .merge(scope) - .where(Event.arel_table[:author_id].eq(author_id_expression)) + .where(Event.arel_table[array_mapping_column].eq(primary_id_expression)) end } end |