Module: Fixtury::MutationObserver
- Defined in:
- lib/fixtury/mutation_observer.rb
Overview
The mutation observer class is responsible for tracking the isolation level of resources as they are created and updated. If a resource is created in one isolation level, but updated in another, the mutation observer will raise an error. If Rails is present, the Railtie will hook into ActiveRecord to automatically report these changes to the MutationObserver
Defined Under Namespace
Modules: ActiveRecordHooks
Class Attribute Summary collapse
-
.current_execution ⇒ Object
readonly
Returns the value of attribute current_execution.
Class Method Summary collapse
-
.current_definition ⇒ Fixtury::Definition?
The definition associated with the current execution.
-
.current_isolation_key ⇒ String?
The isolation key of the current definition associated with the current execution.
- .log(msg, level: ::Fixtury::LOG_LEVEL_DEBUG) ⇒ Object
-
.normalized_locator_key(obj) ⇒ String?
Since there may be inheritance at play, we use the base class to consolidate ensure the same db record always produces the same locator key by using the base class to generate the locator key.
-
.observe(execution) {|void| ... } ⇒ Object
Observe mutation activity while the given block is executed.
-
.on_record_create(obj) ⇒ void
When a record is created we assign ownership to the current isolation key, if present.
-
.on_record_update(obj, changes) ⇒ void
When a record is updated we check to see if the reported owner matches the current isolation key.
- .owners ⇒ Object
- .reported_owner(locator_key) ⇒ Object
Class Attribute Details
.current_execution ⇒ Object (readonly)
Returns the value of attribute current_execution.
35 36 37 |
# File 'lib/fixtury/mutation_observer.rb', line 35 def current_execution @current_execution end |
Class Method Details
.current_definition ⇒ Fixtury::Definition?
The definition associated with the current execution.
71 72 73 |
# File 'lib/fixtury/mutation_observer.rb', line 71 def current_definition current_execution&.definition end |
.current_isolation_key ⇒ String?
The isolation key of the current definition associated with the current execution.
64 65 66 |
# File 'lib/fixtury/mutation_observer.rb', line 64 def current_isolation_key current_definition&.isolation_key end |
.log(msg, level: ::Fixtury::LOG_LEVEL_DEBUG) ⇒ Object
37 38 39 |
# File 'lib/fixtury/mutation_observer.rb', line 37 def log(msg, level: ::Fixtury::LOG_LEVEL_DEBUG) ::Fixtury.log(msg, name: "mutation_observer", level: level) end |
.normalized_locator_key(obj) ⇒ String?
Since there may be inheritance at play, we use the base class to consolidate ensure the same db record always produces the same locator key by using the base class to generate the locator key.
81 82 83 84 85 86 87 |
# File 'lib/fixtury/mutation_observer.rb', line 81 def normalized_locator_key(obj) return nil unless current_execution pk = obj.class.primary_key delegate_object = obj.class.base_class.new(pk => obj.read_attribute(pk)) current_execution.store.locator.dump(delegate_object, context: "<mutation_observer>") end |
.observe(execution) {|void| ... } ⇒ Object
Observe mutation activity while the given block is executed.
53 54 55 56 57 58 59 |
# File 'lib/fixtury/mutation_observer.rb', line 53 def observe(execution) prev_execution = current_execution @current_execution = execution yield ensure @current_execution = prev_execution end |
.on_record_create(obj) ⇒ void
This method returns an undefined value.
When a record is created we assign ownership to the current isolation key, if present.
93 94 95 96 97 98 99 |
# File 'lib/fixtury/mutation_observer.rb', line 93 def on_record_create(obj) locator_key = normalized_locator_key(obj) return unless locator_key log("Setting isolation level of #{locator_key.inspect} to #{current_isolation_key.inspect} via #{current_definition.inspect}") owners[locator_key] = current_isolation_key end |
.on_record_update(obj, changes) ⇒ void
This method returns an undefined value.
When a record is updated we check to see if the reported owner matches the current isolation key. If it doesn’t, we raise an error.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/fixtury/mutation_observer.rb', line 108 def on_record_update(obj, changes) return if changes.blank? locator_key = normalized_locator_key(obj) log("verifying record update for #{locator_key}") actual_owner = reported_owner(locator_key) return unless actual_owner if current_isolation_key.nil? log("Allowing update to #{locator_key.inspect} because there is no registered owner.") return end if actual_owner == current_isolation_key log("Allowing update to #{locator_key.inspect} in the #{actual_owner.inspect} isolation level via #{current_definition.inspect}.") return end raise Errors::IsolatedMutationError, "Cannot modify #{locator_key.inspect}. Owned by: #{actual_owner.inspect}. Modified by: #{current_isolation_key.inspect}. Requested changes: #{changes.inspect}" end |
.owners ⇒ Object
41 42 43 |
# File 'lib/fixtury/mutation_observer.rb', line 41 def owners @owners ||= {} end |
.reported_owner(locator_key) ⇒ Object
45 46 47 |
# File 'lib/fixtury/mutation_observer.rb', line 45 def reported_owner(locator_key) owners[locator_key] end |