From 1e3c4ed2983d99611bd1abdfd2b44dfe166f88d4 Mon Sep 17 00:00:00 2001 From: Robert Hunt Date: Tue, 22 Jul 2025 16:13:37 +0100 Subject: [PATCH] Update finder to optimize the performance of searching a root group Signed-off-by: Robert Hunt --- ee/app/finders/ai/usage_events_finder.rb | 6 +++++- .../finders/ai/usage_events_finder_spec.rb | 21 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ee/app/finders/ai/usage_events_finder.rb b/ee/app/finders/ai/usage_events_finder.rb index 2178926c8174bb..ee7b66cee9dc5b 100644 --- a/ee/app/finders/ai/usage_events_finder.rb +++ b/ee/app/finders/ai/usage_events_finder.rb @@ -27,7 +27,11 @@ def execute private def array_scope - resource.self_and_descendants(skope: Namespace).select(:id) + if resource.root? + Namespace.by_root_id(resource.id).select(:id) + else + resource.self_and_descendants(skope: Namespace).select(:id) + end end def in_operator_scope diff --git a/ee/spec/finders/ai/usage_events_finder_spec.rb b/ee/spec/finders/ai/usage_events_finder_spec.rb index 57643694d10b6e..afb617f950cb92 100644 --- a/ee/spec/finders/ai/usage_events_finder_spec.rb +++ b/ee/spec/finders/ai/usage_events_finder_spec.rb @@ -16,6 +16,9 @@ allow(Ability).to receive(:allowed?) .with(user, :read_enterprise_ai_analytics, group) .and_return(allowed) + allow(Ability).to receive(:allowed?) + .with(user, :read_enterprise_ai_analytics, subgroup) + .and_return(allowed) end context 'when user cannot read AI Usage events' do @@ -80,7 +83,7 @@ expect(result.last).to eq(old_event) end - it 'includes events from descendant namespaces' do + it 'includes events from descendant namespaces when searching from a root group' do parent_event = create(:ai_usage_event, user: user, namespace: group) child_event = create(:ai_usage_event, user: user, namespace: subgroup) other_namespace_event = create(:ai_usage_event, user: user, namespace: create(:group)) @@ -90,6 +93,22 @@ expect(result).not_to include(other_namespace_event) end + context 'when searching subgroups' do + subject(:finder) { described_class.new(user, resource: subgroup).execute } + + let_it_be(:lowest_group) { create(:group, parent: subgroup) } + + it 'includes events from descendant namespaces when searching from a subgroup' do + parent_event = create(:ai_usage_event, user: user, namespace: subgroup) + child_event = create(:ai_usage_event, user: user, namespace: lowest_group) + other_namespace_event = create(:ai_usage_event, user: user, namespace: group) + + result = finder + expect(result).to contain_exactly(parent_event, child_event) + expect(result).not_to include(other_namespace_event) + end + end + it 'ignores events with future timestamps' do # Create events with different timestamps old_event = create(:ai_usage_event, user: user, namespace: group, timestamp: 2.days.ago) -- GitLab