Class: Mxrb::Runtime::Native::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/mxrb/runtime/native.rb

Overview

Transactional in-memory persistence used by the Ruby model Runtime.

Constant Summary collapse

LIFECYCLE_EVENTS =
%i[
  before_create after_create before_update after_update
  before_commit after_commit before_delete after_delete
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(defaults: {}, hooks: {}, transient_entities: []) ⇒ Store

Returns a new instance of Store.



26
27
28
29
30
31
32
# File 'lib/mxrb/runtime/native.rb', line 26

def initialize(defaults: {}, hooks: {}, transient_entities: [])
  @records = Hash.new { |records, entity| records[entity] = [] }
  @defaults = defaults
  @committed = {}
  @hooks = hooks
  @transient_entities = Array(transient_entities).map(&:to_s).to_h { [_1, true] }.freeze
end

Instance Method Details

#closeObject



127
# File 'lib/mxrb/runtime/native.rb', line 127

def close; end

#commit(value, events: true) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/mxrb/runtime/native.rb', line 103

def commit(value, events: true)
  Array(value).each do |object|
    creating = !@committed.key?(record_key(object))
    run_hooks(creating ? :before_create : :before_update, object) if events
    run_hooks(:before_commit, object) if events
    @committed[record_key(object)] = object.members.dup
    run_hooks(:after_commit, object) if events
    run_hooks(creating ? :after_create : :after_update, object) if events
  end
  value
end

#count(entity, predicate = nil) ⇒ Object



75
76
77
78
# File 'lib/mxrb/runtime/native.rb', line 75

def count(entity, predicate = nil)
  values = retrieve(entity)
  predicate ? values.count { predicate.call(_1) } : values.size
end

#create(entity, events: true) ⇒ Object

Raises:

  • (ArgumentError)


44
45
46
47
48
49
50
51
# File 'lib/mxrb/runtime/native.rb', line 44

def create(entity, events: true)
  raise ArgumentError, 'events must be boolean' unless [true, false].include?(events)

  members = @defaults.fetch(entity, {}).dup
  ObjectValue.new(entity:, id: SecureRandom.uuid, members:).tap do |object|
    @records[entity] << object
  end
end

#delete(value, events: true) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/mxrb/runtime/native.rb', line 66

def delete(value, events: true)
  Array(value).each do |object|
    run_hooks(:before_delete, object) if events
    @records[object.entity].delete(object)
    @committed.delete(record_key(object))
    run_hooks(:after_delete, object) if events
  end
end

#find(entity, id) ⇒ Object



55
# File 'lib/mxrb/runtime/native.rb', line 55

def find(entity, id) = @records[entity].find { _1.id == id.to_s }

#on(entity, event, &callback) ⇒ Object

Raises:

  • (ArgumentError)


34
35
36
37
38
39
40
41
42
# File 'lib/mxrb/runtime/native.rb', line 34

def on(entity, event, &callback)
  raise ArgumentError, "unknown lifecycle event #{event}" unless LIFECYCLE_EVENTS.include?(event.to_sym)
  raise ArgumentError, 'lifecycle callback is required' unless callback

  @hooks[entity.to_s] ||= {}
  @hooks[entity.to_s][event.to_sym] ||= []
  @hooks[entity.to_s][event.to_sym] << callback
  self
end

#restore(snapshot) ⇒ Object



87
88
89
90
91
# File 'lib/mxrb/runtime/native.rb', line 87

def restore(snapshot)
  @records.clear
  snapshot.fetch(:records).each { |entity, values| @records[entity] = values }
  @committed = snapshot.fetch(:committed).transform_values(&:dup)
end

#retrieve(entity) ⇒ Object



53
# File 'lib/mxrb/runtime/native.rb', line 53

def retrieve(entity) = @records[entity].dup

#retrieve_association(association, start) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/mxrb/runtime/native.rb', line 57

def retrieve_association(association, start)
  member = association.to_s.split('.').last
  direct = Array(start&.members&.[](association) || start&.members&.[](member))
  inverse = @records.values.flatten.select do |object|
    Array(object.members[association] || object.members[member]).include?(start)
  end
  (direct + inverse).uniq
end

#rollback(value) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/mxrb/runtime/native.rb', line 115

def rollback(value)
  Array(value).each do |object|
    persisted = @committed[record_key(object)]
    if persisted
      object.members.replace(persisted.dup)
    else
      @records[object.entity].delete(object)
    end
  end
  value
end

#snapshotObject



80
81
82
83
84
85
# File 'lib/mxrb/runtime/native.rb', line 80

def snapshot
  {
    records: copy_records(@records),
    committed: @committed.transform_values(&:dup)
  }
end

#transactionObject



93
94
95
96
97
98
99
100
101
# File 'lib/mxrb/runtime/native.rb', line 93

def transaction
  state = snapshot
  result = yield
  discard_uncommitted
  result
rescue StandardError
  restore(state)
  raise
end