diff options
Diffstat (limited to 'app/models/event_collection.rb')
-rw-r--r-- | app/models/event_collection.rb | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/app/models/event_collection.rb b/app/models/event_collection.rb index a4c69b11781..4778f74568e 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,57 +15,52 @@ 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 + relation = if groups + project_and_group_events else - relation_without_join_lateral + relation_with_join_lateral('project_id', projects) end + relation = paginate_events(relation) relation.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) + def project_and_group_events + project_events = relation_with_join_lateral('project_id', projects) + group_events = relation_with_join_lateral('group_id', groups) - paginate_events(events) + Event.from_union([project_events, group_events]).recent 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 + def relation_with_join_lateral(parent_column, parents) + parents_for_lateral = parents.select(:id).to_sql lateral = filtered_events .limit(limit_for_join_lateral) - .where('events.project_id = projects_for_lateral.id') + .where("events.#{parent_column} = parents_for_lateral.id") # rubocop:disable GitlabSecurity/SqlInjection .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") + base_relation + .from("(#{parents_for_lateral}) parents_for_lateral") .joins("JOIN LATERAL (#{lateral}) AS #{Event.table_name} ON true") - - paginate_events(outer) end def filtered_events @@ -97,4 +94,10 @@ class EventCollection def projects @projects.except(:order) end + + def groups + strong_memoize(:groups) do + groups.except(:order) if @groups + end + end end |