Class: Hecks::Ports::Persistence::AppendOnly
- Inherits:
-
Object
- Object
- Hecks::Ports::Persistence::AppendOnly
- Defined in:
- lib/hecks/ports/persistence/append_only.rb
Overview
Makes append-before-projection a port invariant. Adapters retain control of their durable format, but every one must accept the same entry stream and materialize current state from it.
Instance Attribute Summary collapse
-
#adapter ⇒ Object
readonly
Returns the value of attribute adapter.
Instance Method Summary collapse
- #aggregate ⇒ Object
- #all(**opts) ⇒ Object
- #append(entry) ⇒ Object
- #atomic_put(instance, insert_only: false) ⇒ Object
- #capabilities ⇒ Object
- #count ⇒ Object
- #delete(id) ⇒ Object
- #entries ⇒ Object
-
#events ⇒ Object
NOT an endless `def events = ...
- #find(id) ⇒ Object
-
#initialize(adapter) ⇒ AppendOnly
constructor
A new instance of AppendOnly.
- #project(entry) ⇒ Object
- #query_read_model(domain, model, args, bluebook = nil) ⇒ Object
- #record_event(event) ⇒ Object
-
#recover! ⇒ Object
An append is durable before a projection is attempted.
- #reset! ⇒ Object
- #save(instance) ⇒ Object
Constructor Details
#initialize(adapter) ⇒ AppendOnly
Returns a new instance of AppendOnly.
22 23 24 25 26 27 28 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 22 def initialize(adapter) @adapter = adapter required = %i[append project entries] missing = required.reject { |method| adapter.respond_to?(method) } raise Runtime::WiringError, "#{adapter.class} does not implement append-only persistence: #{missing.join(', ')}" unless missing.empty? end |
Instance Attribute Details
#adapter ⇒ Object (readonly)
Returns the value of attribute adapter.
18 19 20 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 18 def adapter @adapter end |
Instance Method Details
#aggregate ⇒ Object
20 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 20 def aggregate = @adapter.aggregate |
#all(**opts) ⇒ Object
31 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 31 def all(**opts) = @adapter.all(**opts) |
#append(entry) ⇒ Object
64 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 64 def append(entry) = @adapter.append(entry) |
#atomic_put(instance, insert_only: false) ⇒ Object
74 75 76 77 78 79 80 81 82 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 74 def atomic_put(instance, insert_only: false) unless capabilities.include?(:atomic_put) && @adapter.respond_to?(:atomic_put) raise Runtime::WiringError, "#{@adapter.class} advertises no atomic_put persistence capability" end entry = Entry.new(operation: "save", id: instance.id.to_s, state: instance.state.dup) status = @adapter.atomic_put(entry, insert_only: insert_only) Outcome.new(status: status, instance: instance) end |
#capabilities ⇒ Object
35 36 37 38 39 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 35 def capabilities return [] unless @adapter.respond_to?(:persistence_capabilities) Array(@adapter.persistence_capabilities).map(&:to_sym).freeze end |
#count ⇒ Object
32 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 32 def count = @adapter.count |
#delete(id) ⇒ Object
84 85 86 87 88 89 90 91 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 84 def delete(id) return false unless find(id) entry = Entry.new(operation: "delete", id: id.to_s, state: nil) append(entry) project(entry) true end |
#entries ⇒ Object
33 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 33 def entries = @adapter.entries |
#events ⇒ Object
NOT an endless def events = ... if ... — that modifier binds to
the WHOLE def, not just its body, so it evaluates against
@adapter while @adapter is still nil (class-body time,
before initialize ever runs) and silently skips defining the
method at all. Found live: nothing in this codebase called
AppendOnly#events before Memory got a reset! test that did.
53 54 55 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 53 def events @adapter.events if @adapter.respond_to?(:events) end |
#find(id) ⇒ Object
30 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 30 def find(id) = @adapter.find(id) |
#project(entry) ⇒ Object
65 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 65 def project(entry) = @adapter.project(entry) |
#query_read_model(domain, model, args, bluebook = nil) ⇒ Object
94 95 96 97 98 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 94 def query_read_model(domain, model, args, bluebook = nil) return unless @adapter.respond_to?(:query_read_model) @adapter.query_read_model(domain, model, args, bluebook) end |
#record_event(event) ⇒ Object
93 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 93
def record_event(event) = @adapter.record_event(event) if
|
#recover! ⇒ Object
An append is durable before a projection is attempted. Replaying the log restores a snapshot/table after a crash in that small window.
59 60 61 62 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 59 def recover! entries.each { |entry| project(entry) } self end |
#reset! ⇒ Object
41 42 43 44 45 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 41 def reset! raise Runtime::WiringError, "append-only adapter cannot reset" unless @adapter.respond_to?(:reset!) @adapter.reset! end |
#save(instance) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/hecks/ports/persistence/append_only.rb', line 67 def save(instance) entry = Entry.new(operation: "save", id: instance.id.to_s, state: instance.state.dup) append(entry) project(entry) instance end |