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

Corrected linear btree descendants query

parent c5a348be
......@@ -126,36 +126,26 @@ module Namespaces
end
def self_and_descendants_with_comparison_operators(include_self: true)
base = all.select(
:traversal_ids,
'LEAD (namespaces.traversal_ids, 1) OVER (ORDER BY namespaces.traversal_ids ASC) next_traversal_ids'
)
base = all.select(:traversal_ids)
base_cte = Gitlab::SQL::CTE.new(:descendants_base_cte, base)
namespaces = Arel::Table.new(:namespaces)
# 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)
# AND next_traversal_ids_sibling(base_cte.traversal_ids) > namespaces.traversal_ids
# WHERE next_traversal_ids_sibling(base_cte.traversal_ids) > namespaces.traversal_ids
records = unscoped
.distinct
.with(base_cte.to_arel)
.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]))
# AND base_cte.traversal_ids <= namespaces.traversal_ids
records = if include_self
records.where(base_cte.table[:traversal_ids].lteq(namespaces[:traversal_ids]))
else
records.where(base_cte.table[:traversal_ids].lt(namespaces[:traversal_ids]))
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))
if include_self
records.where(base_cte.table[:traversal_ids].lteq(namespaces[:traversal_ids]))
else
records.where(base_cte.table[:traversal_ids].lt(namespaces[:traversal_ids]))
end
end
def next_sibling_func(*args)
......
......@@ -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) }
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
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