Module: AtomicInternalId

Extended by:
ActiveSupport::Concern
Included in:
AlertManagement::Alert, Ci::Pipeline, Deployment, DesignManagement::Design, Issue, Iteration, MergeRequest, Operations::FeatureFlag, Operations::FeatureFlags::UserList, Timebox
Defined in:
app/models/concerns/atomic_internal_id.rb

Overview

Include atomic internal id generation scheme for a model

This allows us to atomically generate internal ids that are unique within a given scope.

For example, let's generate internal ids for Issue per Project: “` class Issue < ApplicationRecord

has_internal_id :iid, scope: :project, init: ->(s) { s.project.issues.maximum(:iid) }

end “`

This generates unique internal ids per project for newly created issues. The generated internal id is saved in the `iid` attribute of `Issue`.

This concern uses InternalId records to facilitate atomicity. In the absence of a record for the given scope, one will be created automatically. In this situation, the `init` block is called to calculate the initial value. In the example above, we calculate the maximum `iid` of all issues within the given project.

Note that a model may have more than one internal id associated with possibly different scopes.

Defined Under Namespace

Classes: Supply

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.group_init(klass, column_name = :iid) ⇒ Object


198
199
200
201
202
203
204
205
206
# File 'app/models/concerns/atomic_internal_id.rb', line 198

def self.group_init(klass, column_name = :iid)
  ->(instance, scope) do
    if instance
      klass.where(group_id: instance.group_id).maximum(column_name)
    elsif scope.present?
      klass.where(group: scope[:namespace]).maximum(column_name)
    end
  end
end

.project_init(klass, column_name = :iid) ⇒ Object


188
189
190
191
192
193
194
195
196
# File 'app/models/concerns/atomic_internal_id.rb', line 188

def self.project_init(klass, column_name = :iid)
  ->(instance, scope) do
    if instance
      klass.where(project_id: instance.project_id).maximum(column_name)
    elsif scope.present?
      klass.where(**scope).maximum(column_name)
    end
  end
end

.scope_attrs(scope_value) ⇒ Object


170
171
172
# File 'app/models/concerns/atomic_internal_id.rb', line 170

def self.scope_attrs(scope_value)
  { scope_value.class.table_name.singularize.to_sym => scope_value } if scope_value
end

.scope_usage(including_class) ⇒ Object


184
185
186
# File 'app/models/concerns/atomic_internal_id.rb', line 184

def self.scope_usage(including_class)
  including_class.table_name.to_sym
end

Instance Method Details

#internal_id_read_scope(scope) ⇒ Object


208
209
210
# File 'app/models/concerns/atomic_internal_id.rb', line 208

def internal_id_read_scope(scope)
  association(scope).reader
end

#internal_id_scope_attrs(scope) ⇒ Object


174
175
176
177
178
# File 'app/models/concerns/atomic_internal_id.rb', line 174

def internal_id_scope_attrs(scope)
  scope_value = internal_id_read_scope(scope)

  ::AtomicInternalId.scope_attrs(scope_value)
end

#internal_id_scope_usageObject


180
181
182
# File 'app/models/concerns/atomic_internal_id.rb', line 180

def internal_id_scope_usage
  ::AtomicInternalId.scope_usage(self.class)
end