Add a separate finder for collecting children of groups

This commit is contained in:
Bob Van Landuyt 2017-09-04 16:23:55 +02:00
parent 283e13b836
commit 063b531211
2 changed files with 125 additions and 0 deletions

View file

@ -0,0 +1,54 @@
class GroupChildrenFinder
include Gitlab::Allowable
attr_reader :current_user, :parent_group, :params
def initialize(current_user = nil, parent_group:, params: {})
@current_user = current_user
@parent_group = parent_group
@params = params
end
def execute
Kaminari.paginate_array(children)
end
# This allows us to fetch only the count without loading the objects. Unless
# the objects were already loaded.
def total_count
@total_count ||= if defined?(@children)
children.size
else
child_groups.count + projects.count
end
end
private
def children
@children ||= child_groups + projects
end
def child_groups
return Group.none unless Group.supports_nested_groups?
return Group.none unless can?(current_user, :read_group, parent_group)
groups = GroupsFinder.new(current_user,
parent: parent_group,
all_available: true,
all_children_for_parent: params[:filter_groups].present?).execute
groups = groups.search(params[:filter]) if params[:filter].present?
groups = groups.includes(:route).includes(:children)
groups.sort(params[:sort])
end
def projects
return Project.none unless can?(current_user, :read_group, parent_group)
projects = GroupProjectsFinder.new(group: parent_group, params: params, current_user: current_user).execute
projects = projects.includes(:route)
projects = projects.search(params[:filter]) if params[:filter].present?
projects.sort(params[:sort])
end
end

View file

@ -0,0 +1,71 @@
require 'spec_helper'
describe GroupChildrenFinder do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:params) { {} }
subject(:finder) { described_class.new(user, parent_group: group, params: params) }
before do
group.add_owner(user)
end
describe '#execute' do
it 'includes projects' do
project = create(:project, namespace: group)
expect(finder.execute).to contain_exactly(project)
end
context 'with a filter' do
let(:params) { { filter: 'test' } }
it 'includes only projects matching the filter' do
_other_project = create(:project, namespace: group)
matching_project = create(:project, namespace: group, name: 'testproject')
expect(finder.execute).to contain_exactly(matching_project)
end
end
end
context 'with nested groups', :nested_groups do
let!(:project) { create(:project, namespace: group) }
let!(:subgroup) { create(:group, parent: group) }
describe '#execute' do
it 'contains projects and subgroups' do
expect(finder.execute).to contain_exactly(subgroup, project)
end
context 'with a filter' do
let(:params) { { filter: 'test' } }
it 'contains only matching projects and subgroups' do
matching_project = create(:project, namespace: group, name: 'Testproject')
matching_subgroup = create(:group, name: 'testgroup', parent: group)
expect(finder.execute).to contain_exactly(matching_subgroup, matching_project)
end
end
end
describe '#total_count' do
it 'counts the array children were already loaded' do
finder.instance_variable_set(:@children, [double])
expect(finder).not_to receive(:child_groups)
expect(finder).not_to receive(:projects)
expect(finder.total_count).to eq(1)
end
it 'performs a count without loading children when they are not loaded yet' do
expect(finder).to receive(:child_groups).and_call_original
expect(finder).to receive(:projects).and_call_original
expect(finder.total_count).to eq(2)
end
end
end
end