Commit 835853e4 authored by James Fargher's avatar James Fargher

Merge branch '346877-insulate-linear-descendant-queries' into 'master'

Resolve "Insulate linear descendant queries"

See merge request gitlab-org/gitlab!75595
parents 1ffa7766 5679e63c
...@@ -105,27 +105,32 @@ module Namespaces ...@@ -105,27 +105,32 @@ module Namespaces
:traversal_ids, :traversal_ids,
'LEAD (namespaces.traversal_ids, 1) OVER (ORDER BY namespaces.traversal_ids ASC) next_traversal_ids' 'LEAD (namespaces.traversal_ids, 1) OVER (ORDER BY namespaces.traversal_ids ASC) next_traversal_ids'
) )
cte = Gitlab::SQL::CTE.new(:base_cte, base) base_cte = Gitlab::SQL::CTE.new(:base_cte, base)
namespaces = Arel::Table.new(:namespaces) namespaces = Arel::Table.new(:namespaces)
records = unscoped
.with(cte.to_arel)
.from([cte.table, 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 (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 # AND next_traversal_ids_sibling(base_cte.traversal_ids) > namespaces.traversal_ids
records = records records = unscoped
.where(cte.table[:next_traversal_ids].eq(nil).or(cte.table[:next_traversal_ids].gt(namespaces[:traversal_ids]))) .from([base_cte.table, namespaces])
.where(next_sibling_func(cte.table[:traversal_ids]).gt(namespaces[:traversal_ids])) .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 # AND base_cte.traversal_ids <= namespaces.traversal_ids
if include_self records = if include_self
records.where(cte.table[:traversal_ids].lteq(namespaces[:traversal_ids])) records.where(base_cte.table[:traversal_ids].lteq(namespaces[:traversal_ids]))
else else
records.where(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)
......
...@@ -213,6 +213,12 @@ RSpec.shared_examples 'namespace traversal scopes' do ...@@ -213,6 +213,12 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to contain_exactly(deep_nested_group_1, deep_nested_group_2) } it { is_expected.to contain_exactly(deep_nested_group_1, deep_nested_group_2) }
end end
context 'with offset and limit' do
subject { described_class.where(id: [group_1, group_2]).offset(1).limit(1).self_and_descendants }
it { is_expected.to contain_exactly(group_2, nested_group_2, deep_nested_group_2) }
end
end end
describe '.self_and_descendants' do describe '.self_and_descendants' do
...@@ -242,6 +248,19 @@ RSpec.shared_examples 'namespace traversal scopes' do ...@@ -242,6 +248,19 @@ RSpec.shared_examples 'namespace traversal scopes' do
it { is_expected.to contain_exactly(deep_nested_group_1.id, deep_nested_group_2.id) } it { is_expected.to contain_exactly(deep_nested_group_1.id, deep_nested_group_2.id) }
end end
context 'with offset and limit' do
subject do
described_class
.where(id: [group_1, group_2])
.limit(1)
.offset(1)
.self_and_descendant_ids
.pluck(:id)
end
it { is_expected.to contain_exactly(group_2.id, nested_group_2.id, deep_nested_group_2.id) }
end
end end
describe '.self_and_descendant_ids' do describe '.self_and_descendant_ids' 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