Class: Hecks::Adapters::Memory
- Inherits:
-
Object
- Object
- Hecks::Adapters::Memory
- Defined in:
- lib/hecks/adapters/driven/memory.rb
Instance Attribute Summary collapse
-
#aggregate ⇒ Object
readonly
Returns the value of attribute aggregate.
Class Method Summary collapse
-
.tenant_capable? ⇒ Boolean
TENANT-CAPABLE TRIVIALLY — see Runtime::TenantCheck's own header for the full reasoning.
Instance Method Summary collapse
- #all(order_by: nil, direction: :asc) ⇒ Object
- #append(entry) ⇒ Object
-
#atomic_put(entry, insert_only: false) ⇒ Object
One in-memory critical section in the only thread touching this plain Hash: classify and replace without a preliminary repository lookup.
- #count ⇒ Object
- #delete(id) ⇒ Object
- #entries ⇒ Object
- #events ⇒ Object
- #find(id) ⇒ Object
-
#initialize(aggregate:, settings: {}, root: nil) ⇒ Memory
constructor
A new instance of Memory.
- #persistence_capabilities ⇒ Object
- #project(entry) ⇒ Object
- #query(specification, args = {}, context: {}) ⇒ Object
- #record_event(event) ⇒ Object
-
#reset! ⇒ Object
Every other driven adapter (Postgres/PostgresEra/Sqlite/D1) already implements this —
Ports::Persistence::AppendOnly#reset!forwards to it and only raises when the wrapped adapter doesn't respond toreset!at all, which was always this adapter's own gap, not a deliberate omission (nothing about "in memory" implies "cannot be cleared"). - #save(instance) ⇒ Object
Constructor Details
#initialize(aggregate:, settings: {}, root: nil) ⇒ Memory
Returns a new instance of Memory.
20 21 22 23 24 25 |
# File 'lib/hecks/adapters/driven/memory.rb', line 20 def initialize(aggregate:, settings: {}, root: nil) @aggregate = aggregate @records = {} @events = [] @entries = [] end |
Instance Attribute Details
#aggregate ⇒ Object (readonly)
Returns the value of attribute aggregate.
18 19 20 |
# File 'lib/hecks/adapters/driven/memory.rb', line 18 def aggregate @aggregate end |
Class Method Details
.tenant_capable? ⇒ Boolean
TENANT-CAPABLE TRIVIALLY — see Runtime::TenantCheck's own header
for the full reasoning. @records is a plain instance variable;
two Runtime.boot calls build two entirely separate Registry
objects and, through them, two entirely separate Memory
instances, so two tenant boots never share this adapter's state
by construction — nothing here needs to know "tenant" exists.
15 |
# File 'lib/hecks/adapters/driven/memory.rb', line 15 def self.tenant_capable? = true |
Instance Method Details
#all(order_by: nil, direction: :asc) ⇒ Object
30 31 32 |
# File 'lib/hecks/adapters/driven/memory.rb', line 30 def all(order_by: nil, direction: :asc) InMemoryOrdering.ordered(@records.values, aggregate: @aggregate, order_by: order_by, direction: direction) end |
#append(entry) ⇒ Object
38 39 40 41 |
# File 'lib/hecks/adapters/driven/memory.rb', line 38 def append(entry) @entries << entry entry end |
#atomic_put(entry, insert_only: false) ⇒ Object
One in-memory critical section in the only thread touching this plain Hash: classify and replace without a preliminary repository lookup. Durable append and projection remain ordered exactly as ordinary save.
60 61 62 63 64 65 66 67 68 |
# File 'lib/hecks/adapters/driven/memory.rb', line 60 def atomic_put(entry, insert_only: false) exists = @records.key?(entry.id.to_s) return :conflicted if insert_only && exists status = exists ? :replaced : :inserted append(entry) project(entry) status end |
#count ⇒ Object
28 |
# File 'lib/hecks/adapters/driven/memory.rb', line 28 def count = @records.size |
#delete(id) ⇒ Object
70 71 72 73 74 |
# File 'lib/hecks/adapters/driven/memory.rb', line 70 def delete(id) entry = Ports::Persistence::Entry.new(operation: "delete", id: id.to_s, state: nil) append(entry) project(entry) end |
#entries ⇒ Object
80 |
# File 'lib/hecks/adapters/driven/memory.rb', line 80 def entries = @entries.dup |
#events ⇒ Object
78 |
# File 'lib/hecks/adapters/driven/memory.rb', line 78 def events = @events |
#find(id) ⇒ Object
27 |
# File 'lib/hecks/adapters/driven/memory.rb', line 27 def find(id) = @records[id.to_s] |
#persistence_capabilities ⇒ Object
16 |
# File 'lib/hecks/adapters/driven/memory.rb', line 16 def persistence_capabilities = [:atomic_put] |
#project(entry) ⇒ Object
43 44 45 46 47 48 49 |
# File 'lib/hecks/adapters/driven/memory.rb', line 43 def project(entry) if entry.save? @records[entry.id] = Runtime::Instance.new(aggregate: @aggregate, id: entry.id, state: entry.state.dup) else @records.delete(entry.id) end end |
#query(specification, args = {}, context: {}) ⇒ Object
34 35 36 |
# File 'lib/hecks/adapters/driven/memory.rb', line 34 def query(specification, args = {}, context: {}) Ports::Query::InMemory.execute(all, specification, args, registry: context[:registry]) end |
#record_event(event) ⇒ Object
76 |
# File 'lib/hecks/adapters/driven/memory.rb', line 76 def record_event(event) = @events << event |
#reset! ⇒ Object
Every other driven adapter (Postgres/PostgresEra/Sqlite/D1)
already implements this — Ports::Persistence::AppendOnly#reset!
forwards to it and only raises when the wrapped adapter doesn't
respond to reset! at all, which was always this adapter's own
gap, not a deliberate omission (nothing about "in memory" implies
"cannot be cleared"). Existing callers that fully re-Hecks.boot
a domain per test case don't need this — they get a brand new
Memory instance, with brand new empty @records/@events/
@entries, for free. This is for the other case: a caller that
deliberately keeps ONE booted runtime across many cases (to skip
load_domain's own per-boot parse/verify cost) and wants each
case to start from the same clean slate Hecks.boot would have
given it, without paying for a fresh boot to get there.
95 96 97 98 99 100 |
# File 'lib/hecks/adapters/driven/memory.rb', line 95 def reset! @records = {} @events = [] @entries = [] self end |
#save(instance) ⇒ Object
51 52 53 54 55 |
# File 'lib/hecks/adapters/driven/memory.rb', line 51 def save(instance) entry = Ports::Persistence::Entry.new(operation: "save", id: instance.id.to_s, state: instance.state.dup) append(entry) project(entry) end |