summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/event.rb13
-rw-r--r--app/models/event_collection.rb68
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