diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 16:37:47 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 16:37:47 +0300 |
commit | aee0a117a889461ce8ced6fcf73207fe017f1d99 (patch) | |
tree | 891d9ef189227a8445d83f35c1b0fc99573f4380 /app/models/namespaces/traversal | |
parent | 8d46af3258650d305f53b819eabf7ab18d22f59e (diff) |
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/models/namespaces/traversal')
-rw-r--r-- | app/models/namespaces/traversal/linear.rb | 38 | ||||
-rw-r--r-- | app/models/namespaces/traversal/linear_scopes.rb | 29 | ||||
-rw-r--r-- | app/models/namespaces/traversal/recursive.rb | 1 |
3 files changed, 55 insertions, 13 deletions
diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index 1736fe82ca5..5a5f2a5d063 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -64,6 +64,13 @@ module Namespaces traversal_ids.present? end + def use_traversal_ids_for_ancestors_upto? + return false unless use_traversal_ids? + return false unless Feature.enabled?(:use_traversal_ids_for_ancestors_upto, root_ancestor, default_enabled: :yaml) + + traversal_ids.present? + end + def use_traversal_ids_for_root_ancestor? return false unless Feature.enabled?(:use_traversal_ids_for_root_ancestor, default_enabled: :yaml) @@ -114,6 +121,35 @@ module Namespaces hierarchy_order == :desc ? traversal_ids[0..-2] : traversal_ids[0..-2].reverse end + # Returns all ancestors upto but excluding the top. + # When no top is given, all ancestors are returned. + # When top is not found, returns all ancestors. + # + # This copies the behavior of the recursive method. We will deprecate + # this behavior soon. + def ancestors_upto(top = nil, hierarchy_order: nil) + return super unless use_traversal_ids_for_ancestors_upto? + + # We can't use a default value in the method definition above because + # we need to preserve those specific parameters for super. + hierarchy_order ||= :desc + + # Get all ancestor IDs inclusively between top and our parent. + top_index = top ? traversal_ids.find_index(top.id) : 0 + ids = traversal_ids[top_index...-1] + ids_string = ids.map { |id| Integer(id) }.join(',') + + # WITH ORDINALITY lets us order the result to match traversal_ids order. + from_sql = <<~SQL + unnest(ARRAY[#{ids_string}]::bigint[]) WITH ORDINALITY AS ancestors(id, ord) + INNER JOIN namespaces ON namespaces.id = ancestors.id + SQL + + self.class + .from(Arel.sql(from_sql)) + .order('ancestors.ord': hierarchy_order) + end + def self_and_ancestors(hierarchy_order: nil) return super unless use_traversal_ids_for_ancestors? @@ -168,7 +204,7 @@ module Namespaces end if bottom - skope = skope.where(id: bottom.traversal_ids[0..-1]) + skope = skope.where(id: bottom.traversal_ids) end # The original `with_depth` attribute in ObjectHierarchy increments as you diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb index f5c44171c42..0dfb7320461 100644 --- a/app/models/namespaces/traversal/linear_scopes.rb +++ b/app/models/namespaces/traversal/linear_scopes.rb @@ -105,27 +105,32 @@ module Namespaces :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(:descendants_base_cte, base) namespaces = Arel::Table.new(:namespaces) - records = unscoped - .with(cte.to_arel) - .from([cte.table, 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 - records = records - .where(cte.table[:next_traversal_ids].eq(nil).or(cte.table[:next_traversal_ids].gt(namespaces[:traversal_ids]))) - .where(next_sibling_func(cte.table[:traversal_ids]).gt(namespaces[:traversal_ids])) + records = unscoped + .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 - if include_self - records.where(cte.table[:traversal_ids].lteq(namespaces[:traversal_ids])) - else - records.where(cte.table[:traversal_ids].lt(namespaces[:traversal_ids])) - end + 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)) end def next_sibling_func(*args) diff --git a/app/models/namespaces/traversal/recursive.rb b/app/models/namespaces/traversal/recursive.rb index 8d2c5d3be5a..53eac27aa54 100644 --- a/app/models/namespaces/traversal/recursive.rb +++ b/app/models/namespaces/traversal/recursive.rb @@ -46,6 +46,7 @@ module Namespaces object_hierarchy(self.class.where(id: id)) .ancestors(upto: top, hierarchy_order: hierarchy_order) end + alias_method :recursive_ancestors_upto, :ancestors_upto def self_and_ancestors(hierarchy_order: nil) return self.class.where(id: id) unless parent_id |