diff options
-rw-r--r-- | app/services/base_count_service.rb | 4 | ||||
-rw-r--r-- | app/services/projects/batch_count_service.rb | 35 | ||||
-rw-r--r-- | app/services/projects/batch_forks_count_service.rb | 14 | ||||
-rw-r--r-- | app/services/projects/batch_open_issues_count_service.rb | 15 | ||||
-rw-r--r-- | app/services/projects/count_service.rb | 2 | ||||
-rw-r--r-- | lib/api/groups.rb | 25 |
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 |