diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/event.rb | 13 | ||||
-rw-r--r-- | app/models/event_collection.rb | 68 |
2 files changed, 43 insertions, 38 deletions
diff --git a/app/models/event.rb b/app/models/event.rb index 580bb770599..3cdfaaf6c40 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -77,15 +77,6 @@ class Event < ApplicationRecord scope :recent, -> { reorder(id: :desc) } scope :code_push, -> { where(action: PUSHED) } - scope :in_projects, -> (projects) do - sub_query = projects - .except(:order) - .select(1) - .where('projects.id = events.project_id') - - where('EXISTS (?)', sub_query).recent - end - scope :with_associations, -> do # We're using preload for "push_event_payload" as otherwise the association # is not always available (depending on the query being built). @@ -135,6 +126,10 @@ class Event < ApplicationRecord def target_types TARGET_TYPES.keys end + + def has_group_events? + false + end end def present diff --git a/app/models/event_collection.rb b/app/models/event_collection.rb index a4c69b11781..418ff091d3a 100644 --- a/app/models/event_collection.rb +++ b/app/models/event_collection.rb @@ -6,6 +6,8 @@ # in a controller), it's not suitable for building queries that are used for # building other queries. class EventCollection + include Gitlab::Utils::StrongMemoize + # To prevent users from putting too much pressure on the database by cycling # through thousands of events we put a limit on the number of pages. MAX_PAGE = 10 @@ -13,59 +15,61 @@ class EventCollection # projects - An ActiveRecord::Relation object that returns the projects for # which to retrieve events. # filter - An EventFilter instance to use for filtering events. - def initialize(projects, limit: 20, offset: 0, filter: nil) + def initialize(projects, limit: 20, offset: 0, filter: nil, groups: nil) @projects = projects @limit = limit @offset = offset @filter = filter + @groups = groups end # Returns an Array containing the events. def to_a return [] if current_page > MAX_PAGE - relation = if Gitlab::Database.join_lateral_supported? - relation_with_join_lateral - else - relation_without_join_lateral - end - - relation.with_associations.to_a + relation_with_join_lateral.with_associations.to_a end private - # Returns the events relation to use when JOIN LATERAL is not supported. - # - # This relation simply gets all the events for all authorized projects, then - # limits that set. - def relation_without_join_lateral - events = filtered_events.in_projects(projects) - - paginate_events(events) - end - - # Returns the events relation to use when JOIN LATERAL is supported. - # # This relation is built using JOIN LATERAL, producing faster queries than a # regular LIMIT + OFFSET approach. def relation_with_join_lateral - projects_for_lateral = projects.select(:id).to_sql - - lateral = filtered_events - .limit(limit_for_join_lateral) - .where('events.project_id = projects_for_lateral.id') - .to_sql - # The outer query does not need to re-apply the filters since the JOIN # LATERAL body already takes care of this. outer = base_relation - .from("(#{projects_for_lateral}) projects_for_lateral") - .joins("JOIN LATERAL (#{lateral}) AS #{Event.table_name} ON true") + .from("(#{parents_for_lateral}) parents_for_lateral") + .joins("JOIN LATERAL (#{join_lateral}) AS #{Event.table_name} ON true") paginate_events(outer) end + def join_lateral + condition = if groups.present? + 'events.project_id = parents_for_lateral.project_id OR events.group_id = parents_for_lateral.group_id' + else + 'events.project_id = parents_for_lateral.project_id' + end + + filtered_events + .limit(limit_for_join_lateral) + .where(condition) + .to_sql + end + + def parents_for_lateral + if groups.present? + members = [ + groups.select('NULL as project_id, id as group_id'), + projects.select('id as project_id, NULL as group_id') + ] + + Gitlab::SQL::Union.new(members).to_sql # rubocop: disable Gitlab/Union + else + projects.select('id as project_id').to_sql + end + end + def filtered_events @filter ? @filter.apply_filter(base_relation) : base_relation end @@ -97,4 +101,10 @@ class EventCollection def projects @projects.except(:order) end + + def groups + strong_memoize(:groups) do + groups.except(:order) if @groups && Event.has_group_events? + end + end end |