Commit 8312c861 authored by Alex Pooley's avatar Alex Pooley

Corrected linear btree descendants query

parent c5a348be
...@@ -126,36 +126,26 @@ module Namespaces ...@@ -126,36 +126,26 @@ module Namespaces
end end
def self_and_descendants_with_comparison_operators(include_self: true) def self_and_descendants_with_comparison_operators(include_self: true)
base = all.select( base = all.select(:traversal_ids)
:traversal_ids,
'LEAD (namespaces.traversal_ids, 1) OVER (ORDER BY namespaces.traversal_ids ASC) next_traversal_ids'
)
base_cte = Gitlab::SQL::CTE.new(:descendants_base_cte, base) base_cte = Gitlab::SQL::CTE.new(:descendants_base_cte, base)
namespaces = Arel::Table.new(:namespaces) namespaces = Arel::Table.new(:namespaces)
# Bound the search space to ourselves (optional) and descendants. # Bound the search space to ourselves (optional) and descendants.
# #
# WHERE (base_cte.next_traversal_ids IS NULL OR base_cte.next_traversal_ids > namespaces.traversal_ids) # WHERE next_traversal_ids_sibling(base_cte.traversal_ids) > namespaces.traversal_ids
# AND next_traversal_ids_sibling(base_cte.traversal_ids) > namespaces.traversal_ids
records = unscoped records = unscoped
.distinct
.with(base_cte.to_arel)
.from([base_cte.table, namespaces]) .from([base_cte.table, namespaces])
.where(base_cte.table[:next_traversal_ids].eq(nil).or(base_cte.table[:next_traversal_ids].gt(namespaces[:traversal_ids])))
.where(next_sibling_func(base_cte.table[:traversal_ids]).gt(namespaces[:traversal_ids])) .where(next_sibling_func(base_cte.table[:traversal_ids]).gt(namespaces[:traversal_ids]))
# AND base_cte.traversal_ids <= namespaces.traversal_ids # AND base_cte.traversal_ids <= namespaces.traversal_ids
records = if include_self if include_self
records.where(base_cte.table[:traversal_ids].lteq(namespaces[:traversal_ids])) records.where(base_cte.table[:traversal_ids].lteq(namespaces[:traversal_ids]))
else else
records.where(base_cte.table[:traversal_ids].lt(namespaces[:traversal_ids])) records.where(base_cte.table[:traversal_ids].lt(namespaces[:traversal_ids]))
end end
records_cte = Gitlab::SQL::CTE.new(:descendants_cte, records)
unscoped
.unscope(where: [:type])
.with(base_cte.to_arel, records_cte.to_arel)
.from(records_cte.alias_to(namespaces))
end end
def next_sibling_func(*args) def next_sibling_func(*args)
......
...@@ -244,6 +244,16 @@ RSpec.shared_examples 'namespace traversal scopes' do ...@@ -244,6 +244,16 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to contain_exactly(group_2, nested_group_2, deep_nested_group_2) } it { is_expected.to contain_exactly(group_2, nested_group_2, deep_nested_group_2) }
end end
context 'with nested query groups' do
let!(:nested_group_1b) { create(:group, parent: group_1) }
let!(:deep_nested_group_1b) { create(:group, parent: nested_group_1b) }
let(:group1_hierarchy) { [group_1, nested_group_1, deep_nested_group_1, nested_group_1b, deep_nested_group_1b] }
subject { described_class.where(id: [group_1, nested_group_1]).self_and_descendants }
it { is_expected.to match_array group1_hierarchy }
end
end end
describe '.self_and_descendants' do describe '.self_and_descendants' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment