diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-04 15:06:14 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-04 15:06:14 +0300 |
commit | 0d46bf06388d485824bc2f1e736b92b2a8a397e4 (patch) | |
tree | 626a835841722463da4def7905b95e874eb77578 /app/models/concerns/atomic_internal_id.rb | |
parent | 1f1bdf54e1974f89f3a6ba734ec2c42552e90639 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models/concerns/atomic_internal_id.rb')
-rw-r--r-- | app/models/concerns/atomic_internal_id.rb | 74 |
1 files changed, 54 insertions, 20 deletions
diff --git a/app/models/concerns/atomic_internal_id.rb b/app/models/concerns/atomic_internal_id.rb index 95de11a72bf..b510129b35d 100644 --- a/app/models/concerns/atomic_internal_id.rb +++ b/app/models/concerns/atomic_internal_id.rb @@ -27,53 +27,73 @@ module AtomicInternalId extend ActiveSupport::Concern class_methods do - def has_internal_id(column, scope:, init:, presence: true) # rubocop:disable Naming/PredicateName + def has_internal_id(column, scope:, init:, ensure_if: nil, presence: true) # rubocop:disable Naming/PredicateName # We require init here to retain the ability to recalculate in the absence of a # InternaLId record (we may delete records in `internal_ids` for example). raise "has_internal_id requires a init block, none given." unless init + raise "has_internal_id needs to be defined on association." unless self.reflect_on_association(scope) - before_validation :"ensure_#{scope}_#{column}!", on: :create + before_validation :"track_#{scope}_#{column}!", on: :create + before_validation :"ensure_#{scope}_#{column}!", on: :create, if: ensure_if validates column, presence: presence define_method("ensure_#{scope}_#{column}!") do - scope_value = association(scope).reader + scope_value = internal_id_read_scope(scope) value = read_attribute(column) - return value unless scope_value - scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value } - usage = self.class.table_name.to_sym - - if value.present? && (@iid_needs_tracking || Feature.enabled?(:iid_always_track, default_enabled: true)) - # The value was set externally, e.g. by the user - # We update the InternalId record to keep track of the greatest value. - InternalId.track_greatest(self, scope_attrs, usage, value, init) - - @iid_needs_tracking = false - elsif !value.present? + if value.nil? # We don't have a value yet and use a InternalId record to generate # the next value. - value = InternalId.generate_next(self, scope_attrs, usage, init) + value = InternalId.generate_next( + self, + internal_id_scope_attrs(scope), + internal_id_scope_usage, + init) write_attribute(column, value) end value end + define_method("track_#{scope}_#{column}!") do + iid_always_track = Feature.enabled?(:iid_always_track, default_enabled: true) + return unless @internal_id_needs_tracking || iid_always_track + + @internal_id_needs_tracking = false + + scope_value = internal_id_read_scope(scope) + value = read_attribute(column) + return unless scope_value + + if value.present? + # The value was set externally, e.g. by the user + # We update the InternalId record to keep track of the greatest value. + InternalId.track_greatest( + self, + internal_id_scope_attrs(scope), + internal_id_scope_usage, + value, + init) + end + end + define_method("#{column}=") do |value| super(value).tap do |v| # Indicate the iid was set from externally - @iid_needs_tracking = true + @internal_id_needs_tracking = true end end define_method("reset_#{scope}_#{column}") do if value = read_attribute(column) - scope_value = association(scope).reader - scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value } - usage = self.class.table_name.to_sym + did_reset = InternalId.reset( + self, + internal_id_scope_attrs(scope), + internal_id_scope_usage, + value) - if InternalId.reset(self, scope_attrs, usage, value) + if did_reset write_attribute(column, nil) end end @@ -82,4 +102,18 @@ module AtomicInternalId end end end + + def internal_id_scope_attrs(scope) + scope_value = internal_id_read_scope(scope) + + { scope_value.class.table_name.singularize.to_sym => scope_value } if scope_value + end + + def internal_id_scope_usage + self.class.table_name.to_sym + end + + def internal_id_read_scope(scope) + association(scope).reader + end end |