Module: AtomicInternalId
- Extended by:
- ActiveSupport::Concern
- Included in:
- AlertManagement::Alert, Ci::Pipeline, Deployment, DesignManagement::Design, Issue, MergeRequest, Milestone, Ml::Candidate, Ml::Experiment, Operations::FeatureFlag, Operations::FeatureFlags::UserList, SupplyChain::Attestation
- 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
Constant Summary collapse
- MissingValueError =
Class.new(StandardError)
Class Method Summary collapse
- .group_init(klass, column_name = :iid) ⇒ Object
- .namespace_init(klass, column_name = :iid) ⇒ Object
- .project_init(klass, column_name = :iid) ⇒ Object
- .scope_attrs(scope_value) ⇒ Object
- .scope_usage(klass) ⇒ Object
Instance Method Summary collapse
- #internal_id_read_scope(scope) ⇒ Object
- #internal_id_scope_attrs(scope) ⇒ Object
- #internal_id_scope_usage ⇒ Object
Class Method Details
.group_init(klass, column_name = :iid) ⇒ Object
234 235 236 237 238 239 240 241 242 |
# File 'app/models/concerns/atomic_internal_id.rb', line 234 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 |
.namespace_init(klass, column_name = :iid) ⇒ Object
244 245 246 247 248 249 250 251 252 |
# File 'app/models/concerns/atomic_internal_id.rb', line 244 def self.namespace_init(klass, column_name = :iid) ->(instance, scope) do if instance klass.where(namespace_id: instance.namespace_id).maximum(column_name) elsif scope.present? klass.where(**scope).maximum(column_name) end end end |
.project_init(klass, column_name = :iid) ⇒ Object
224 225 226 227 228 229 230 231 232 |
# File 'app/models/concerns/atomic_internal_id.rb', line 224 def self.project_init(klass, column_name = :iid) ->(instance, scope) do if instance klass.default_scoped.where(project_id: instance.project_id).maximum(column_name) elsif scope.present? klass.default_scoped.where(**scope).maximum(column_name) end end end |
.scope_attrs(scope_value) ⇒ Object
206 207 208 |
# File 'app/models/concerns/atomic_internal_id.rb', line 206 def self.scope_attrs(scope_value) { scope_value.class.table_name.singularize.to_sym => scope_value } if scope_value end |
.scope_usage(klass) ⇒ Object
220 221 222 |
# File 'app/models/concerns/atomic_internal_id.rb', line 220 def self.scope_usage(klass) klass.respond_to?(:internal_id_scope_usage) ? klass.internal_id_scope_usage : klass.table_name.to_sym end |
Instance Method Details
#internal_id_read_scope(scope) ⇒ Object
254 255 256 |
# File 'app/models/concerns/atomic_internal_id.rb', line 254 def internal_id_read_scope(scope) association(scope).reader end |
#internal_id_scope_attrs(scope) ⇒ Object
210 211 212 213 214 |
# File 'app/models/concerns/atomic_internal_id.rb', line 210 def internal_id_scope_attrs(scope) scope_value = internal_id_read_scope(scope) ::AtomicInternalId.scope_attrs(scope_value) end |
#internal_id_scope_usage ⇒ Object
216 217 218 |
# File 'app/models/concerns/atomic_internal_id.rb', line 216 def internal_id_scope_usage ::AtomicInternalId.scope_usage(self.class) end |