diff options
Diffstat (limited to 'app/models/namespaces')
-rw-r--r-- | app/models/namespaces/project_namespace.rb | 4 | ||||
-rw-r--r-- | app/models/namespaces/sync_event.rb | 16 | ||||
-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 | ||||
-rw-r--r-- | app/models/namespaces/user_namespace.rb | 2 |
6 files changed, 75 insertions, 15 deletions
diff --git a/app/models/namespaces/project_namespace.rb b/app/models/namespaces/project_namespace.rb index 22ec550dee2..fbd87e3232d 100644 --- a/app/models/namespaces/project_namespace.rb +++ b/app/models/namespaces/project_namespace.rb @@ -7,5 +7,9 @@ module Namespaces def self.sti_name 'Project' end + + def self.polymorphic_name + 'Namespaces::ProjectNamespace' + end end end diff --git a/app/models/namespaces/sync_event.rb b/app/models/namespaces/sync_event.rb new file mode 100644 index 00000000000..8534d8afb8c --- /dev/null +++ b/app/models/namespaces/sync_event.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# This model serves to keep track of changes to the namespaces table in the main database, and allowing to safely +# replicate these changes to other databases. +class Namespaces::SyncEvent < ApplicationRecord + self.table_name = 'namespaces_sync_events' + + belongs_to :namespace + + scope :preload_synced_relation, -> { preload(:namespace) } + scope :order_by_id_asc, -> { order(id: :asc) } + + def self.enqueue_worker + ::Namespaces::ProcessSyncEventsWorker.perform_async # rubocop:disable CodeReuse/Worker + end +end 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 diff --git a/app/models/namespaces/user_namespace.rb b/app/models/namespaces/user_namespace.rb index d4d7d352e71..14b867b2607 100644 --- a/app/models/namespaces/user_namespace.rb +++ b/app/models/namespaces/user_namespace.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -# TODO: currently not created/mapped in the database, will be done in another issue -# https://gitlab.com/gitlab-org/gitlab/-/issues/341070 module Namespaces #################################################################### # PLEASE DO NOT OVERRIDE METHODS IN THIS CLASS! |