summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/services/base_count_service.rb4
-rw-r--r--app/services/projects/batch_count_service.rb35
-rw-r--r--app/services/projects/batch_forks_count_service.rb14
-rw-r--r--app/services/projects/batch_open_issues_count_service.rb15
-rw-r--r--app/services/projects/count_service.rb2
-rw-r--r--lib/api/groups.rb25
6 files changed, 88 insertions, 7 deletions
diff --git a/app/services/base_count_service.rb b/app/services/base_count_service.rb
index 19873fe09a5..2e4fd1db03e 100644
--- a/app/services/base_count_service.rb
+++ b/app/services/base_count_service.rb
@@ -12,8 +12,8 @@ class BaseCountService
Rails.cache.fetch(cache_key, cache_options) { uncached_count }.to_i
end
- def refresh_cache
- Rails.cache.write(cache_key, uncached_count, raw: raw?)
+ def refresh_cache(&block)
+ Rails.cache.write(cache_key, block_given? ? yield : uncached_count, raw: raw?)
end
def uncached_count
diff --git a/app/services/projects/batch_count_service.rb b/app/services/projects/batch_count_service.rb
new file mode 100644
index 00000000000..5b69e24b893
--- /dev/null
+++ b/app/services/projects/batch_count_service.rb
@@ -0,0 +1,35 @@
+module Projects
+ class BatchCountService
+ def initialize(projects)
+ @projects = projects
+ end
+
+ def count
+ @projects.map do |project|
+ [project.id, current_count_service(project).count]
+ end.to_h
+ end
+
+ def refresh_cache
+ @projects.each do |project|
+ current_count_service(project).refresh_cache { global_count[project.id].to_i }
+ end
+ end
+
+ def current_count_service(project)
+ if defined? @service
+ @service.project = project
+ else
+ count_service.new(project)
+ end
+ end
+
+ def global_count(project)
+ raise NotImplementedError, 'global_count must be implemented and return an hash indexed by the project id'
+ end
+
+ def count_service
+ raise NotImplementedError, 'count_service must be implemented and return a Projects::CountService object'
+ end
+ end
+end
diff --git a/app/services/projects/batch_forks_count_service.rb b/app/services/projects/batch_forks_count_service.rb
new file mode 100644
index 00000000000..51fad1c12a4
--- /dev/null
+++ b/app/services/projects/batch_forks_count_service.rb
@@ -0,0 +1,14 @@
+module Projects
+ # Service class for getting and caching the number of forks of several projects
+ class BatchForksCountService < Projects::BatchCountService
+ def global_count
+ @global_count ||= ForkedProjectLink.where(forked_from_project: @projects.map(&:id))
+ .group(:forked_from_project_id)
+ .count
+ end
+
+ def count_service
+ ::Projects::ForksCountService
+ end
+ end
+end
diff --git a/app/services/projects/batch_open_issues_count_service.rb b/app/services/projects/batch_open_issues_count_service.rb
new file mode 100644
index 00000000000..a0d9120487c
--- /dev/null
+++ b/app/services/projects/batch_open_issues_count_service.rb
@@ -0,0 +1,15 @@
+module Projects
+ # Service class for getting and caching the number of forks of several projects
+ class BatchOpenIssuesCountService < Projects::BatchCountService
+ def global_count
+ @global_count ||= Issue.opened.public_only
+ .where(project: @projects.map(&:id))
+ .group(:project_id)
+ .count
+ end
+
+ def count_service
+ ::Projects::OpenIssuesCountService
+ end
+ end
+end
diff --git a/app/services/projects/count_service.rb b/app/services/projects/count_service.rb
index 7e575b2d6f3..a3ec52232dd 100644
--- a/app/services/projects/count_service.rb
+++ b/app/services/projects/count_service.rb
@@ -7,6 +7,8 @@ module Projects
# all caches.
VERSION = 1
+ attr_accessor :project
+
def initialize(project)
@project = project
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index df2d97bceda..746dcc9fc91 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -52,6 +52,24 @@ module API
groups
end
+ def find_group_projects(params)
+ group = find_group!(params[:id])
+ projects = GroupProjectsFinder.new(group: group, current_user: current_user, params: project_finder_params).execute
+ projects = projects.preload(:project_feature, :route, :group)
+ .preload(namespace: [:route, :owner],
+ tags: :taggings,
+ project_group_links: :group,
+ fork_network: :root_project,
+ forked_project_link: :forked_from_project,
+ forked_from_project: [:route, :forks, namespace: :route, tags: :taggings])
+ projects = reorder_projects(projects)
+ paginated_projects = paginate(projects)
+ projects_with_fork = paginated_projects + paginated_projects.map(&:forked_from_project).compact
+ ::Projects::BatchForksCountService.new(projects_with_fork).refresh_cache
+ ::Projects::BatchOpenIssuesCountService.new(paginated_projects).refresh_cache
+ paginated_projects
+ end
+
def present_groups(params, groups)
options = {
with: Entities::Group,
@@ -170,12 +188,9 @@ module API
use :pagination
end
get ":id/projects" do
- group = find_group!(params[:id])
- projects = GroupProjectsFinder.new(group: group, current_user: current_user, params: project_finder_params).execute
- projects = projects.preload(:fork_network, :forked_project_link, :project_feature, :project_group_links, :tags, :taggings, :group, :namespace, :route)
- projects = reorder_projects(projects)
+ projects = find_group_projects(params)
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project
- present paginate(projects), with: entity, current_user: current_user
+ present projects, with: entity, current_user: current_user
end
desc 'Get a list of subgroups in this group.' do