event_sorcerer 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a30a15c744e7f3f861840bbdc3cfb822a5b8a88
4
- data.tar.gz: 11012f39e7e59b80349a947f63216cec5f28657a
3
+ metadata.gz: 12872b11f0ed0ab93b3223cfc0c2e3ec9d03412d
4
+ data.tar.gz: 4e63ccf41e6f96e20c5852409ebe44371d0f6ecc
5
5
  SHA512:
6
- metadata.gz: 1a2db2aaa933ed7280f7cebe9d6544bcd767a605ddc78108ed2e1911481d2efb5f7ebf2b364358b82e8777357a01190dab8e3bc11371db3b6f81844287e3c0a9
7
- data.tar.gz: de9da895801ddd797276efdd48c55cccad6342a822eea80b6451a2e864f7b2c97bc59825c43f2387dc0137840639a65e1b31d2e92345f172a06949d2660b1d93
6
+ metadata.gz: 1e11b7fd1cca67145850336cfb78f04c910e316a2b0e820443bcc8e68dca3448635776fc5453bd1b3189f3ea64c34f974e6a33d2dddc41cb61412ef9f9c5df0e
7
+ data.tar.gz: d3006f46d56580237e33278ddfc86500ae57bdf0799846a781e919672d61dc2659b844ea2dd0676eb4915a06473a990927d9978aa11813dff188aa3355c14a0c
@@ -23,17 +23,25 @@ module EventSorcerer
23
23
  #
24
24
  # Returns an Array of AggregateProxy objects.
25
25
  def all
26
- with_all_loaders_for_type do |loaders|
27
- loaders.map(&:load).each do |aggregate|
26
+ all_loaders_for_type.map do |loader|
27
+ cached = unit_of_work.fetch_aggregate(to_s, loader.id)
28
+
29
+ next cached if cached
30
+
31
+ loader.load.tap do |aggregate|
28
32
  unit_of_work.store_aggregate(aggregate)
29
33
  end
30
34
  end
31
35
  end
32
36
 
33
37
  # Public: An array of symbols representing the names of the methods which
34
- # are events.
38
+ # are events. Includes event methods of superclass.
35
39
  def event_methods
36
- @event_methods ||= []
40
+ if superclass.respond_to? :event_methods
41
+ _event_methods.concat(superclass.event_methods).uniq
42
+ else
43
+ _event_methods
44
+ end
37
45
  end
38
46
 
39
47
  # Public: Methods defined within this block will have their method symbol
@@ -51,26 +59,26 @@ module EventSorcerer
51
59
  !starting_methods.include? method
52
60
  end
53
61
 
54
- event_methods.concat new_events
62
+ _event_methods.concat new_events
55
63
  class_eval(&block)
56
64
 
57
65
  self
58
66
  end
59
67
 
60
- # Public: Load an aggregate out of the event store.
68
+ # Public: Load an aggregate(s) out of the event store.
61
69
  #
62
- # id - the ID of the aggregate to load.
70
+ # id_or_ids - the ID of the aggregate to load or an array of the same.
63
71
  #
64
- # Returns an AggregateProxy object.
65
- def find(id)
66
- if unit_of_work.fetch_aggregate(id)
67
- return unit_of_work.fetch_aggregate(id)
72
+ # Returns an AggregateProxy object or an array of the same.
73
+ def find(id_or_ids)
74
+ return find_many(id_or_ids) if id_or_ids.respond_to?(:each)
75
+
76
+ if unit_of_work.fetch_aggregate(to_s, id_or_ids)
77
+ return unit_of_work.fetch_aggregate(to_s, id_or_ids)
68
78
  end
69
79
 
70
- with_loader_for_id(id) do |loader|
71
- loader.load.tap do |aggregate|
72
- unit_of_work.store_aggregate(aggregate)
73
- end
80
+ loader_for_id(id_or_ids).load.tap do |aggregate|
81
+ unit_of_work.store_aggregate(aggregate)
74
82
  end
75
83
  end
76
84
 
@@ -80,14 +88,12 @@ module EventSorcerer
80
88
  #
81
89
  # Returns an AggregateProxy object.
82
90
  def find_or_new(id)
83
- if unit_of_work.fetch_aggregate(id)
84
- return unit_of_work.fetch_aggregate(id)
91
+ if unit_of_work.fetch_aggregate(to_s, id)
92
+ return unit_of_work.fetch_aggregate(to_s, id)
85
93
  end
86
94
 
87
- with_loader_for_id(id, false) do |loader|
88
- loader.load.tap do |aggregate|
89
- unit_of_work.store_aggregate(aggregate)
90
- end
95
+ loader_for_id(id, false).load.tap do |aggregate|
96
+ unit_of_work.store_aggregate(aggregate)
91
97
  end
92
98
  end
93
99
 
@@ -104,56 +110,74 @@ module EventSorcerer
104
110
 
105
111
  private
106
112
 
107
- # Private: Grabs the event streams for the aggregate class and yields
108
- # them to a given block.
109
- #
110
- # block - the block to yield the event stream to.
113
+ # Private: An array of symbols representing the names of the methods
114
+ # which are events.
115
+ def _event_methods
116
+ @_event_methods ||= []
117
+ end
118
+
119
+ # Private: Creates an AggregateLoader for each persisted aggregate.
111
120
  #
112
121
  # Returns the return value of the given block.
113
- def with_all_event_streams_for_type
114
- yield event_store.read_event_streams_for_type(name)
122
+ def all_loaders_for_type
123
+ event_store.read_event_streams_for_type(name).map do |stream|
124
+ AggregateLoader.new(self, stream.id, stream.events,
125
+ stream.current_version, true)
126
+ end
115
127
  end
116
128
 
117
- # Private: Creates AggregateLoaders for an ID and yields it to a given
118
- # block.
129
+ # Private: Maps an array of IDs replacing with cached aggregate if
130
+ # available.
119
131
  #
120
- # prohibit_new - value of the prohibit_new flag to be passed to loaders.
121
- # block - the block to yield the event stream to.
132
+ # ids - the IDs of the aggregates to check the cache from.
122
133
  #
123
- # Returns the return value of the given block.
124
- def with_all_loaders_for_type(prohibit_new = true)
125
- with_all_event_streams_for_type do |streams|
126
- loaders = streams.map do |stream|
127
- AggregateLoader.new(self, stream.id, stream.events,
128
- stream.current_version, prohibit_new)
129
- end
134
+ # Returns a mixed Array of AggregateProxy objects and IDs.
135
+ def perform_cache_pass(ids)
136
+ ids.map do |id|
137
+ cached = unit_of_work.fetch_aggregate(to_s, id)
130
138
 
131
- yield loaders
139
+ cached ? cached : id
132
140
  end
133
141
  end
134
142
 
135
- # Private: Grabs the event stream for an ID and yields it to a given
136
- # block.
143
+ # Private: Loads an array of aggregates out of the event store.
137
144
  #
138
- # id - the ID of the aggregate to get the event stream for.
139
- # block - the block to yield the event stream to.
145
+ # ids - the IDs of the aggregates to load.
140
146
  #
141
- # Returns the return value of the given block.
142
- def with_event_stream_for_id(id)
143
- yield event_store.read_event_stream(id, name)
147
+ # Returns an Array of AggregateProxy objects.
148
+ def find_many(ids)
149
+ aggregates = perform_cache_pass(ids)
150
+
151
+ uncached_ids = aggregates.reject { |a| a.is_a? self }
152
+
153
+ uncached = loaders_for_ids(uncached_ids).reduce({}) do |hash, loader|
154
+ aggregate = loader.load
155
+ unit_of_work.store_aggregate(aggregate)
156
+
157
+ hash.merge aggregate.id => aggregate
158
+ end
159
+
160
+ aggregates.map do |id_or_agg|
161
+ uncached[id_or_agg] ? uncached[id_or_agg] : id_or_agg
162
+ end
144
163
  end
145
164
 
146
- # Private: Creates an AggregateLoader for an ID and yields it to a given
147
- # block.
165
+ def loader_for_id(id, prohibit_new = true)
166
+ stream = event_store.read_event_stream(id, name)
167
+
168
+ AggregateLoader.new(self, stream.id, stream.events,
169
+ stream.current_version, prohibit_new)
170
+ end
171
+
172
+ # Private: Creates an AggregateLoader for each given ID.
148
173
  #
149
174
  # id - the ID of the aggregate to get the event stream for.
150
- # block - the block to yield the event stream to.
151
175
  #
152
- # Returns the return value of the given block.
153
- def with_loader_for_id(id, prohibit_new = true)
154
- with_event_stream_for_id(id) do |stream|
155
- yield AggregateLoader.new(self, stream.id, stream.events,
156
- stream.current_version, prohibit_new)
176
+ # Returns an Array of AggregateLoader instances.
177
+ def loaders_for_ids(ids, prohibit_new = true)
178
+ event_store.read_multiple_event_streams(ids, name).map do |stream|
179
+ AggregateLoader.new(self, stream.id, stream.events,
180
+ stream.current_version, prohibit_new)
157
181
  end
158
182
  end
159
183
  end
@@ -1,6 +1,9 @@
1
1
  module EventSorcerer
2
2
  # Public: Service class for loading aggregates from the event store.
3
3
  class AggregateLoader
4
+ # Public: Returns the id for the aggregate to be loaded.
5
+ attr_reader :id
6
+
4
7
  # Public: Creates a new AggregateLoader instance.
5
8
  #
6
9
  # klass - class for the aggregate to be loaded.
@@ -29,9 +32,6 @@ module EventSorcerer
29
32
  # Private: Returns array of Events to hydrate with.
30
33
  attr_reader :events
31
34
 
32
- # Private: Returns the id for the aggregate to be loaded.
33
- attr_reader :id
34
-
35
35
  # Private: Returns the class for the aggregate to be loaded.3
36
36
  attr_reader :klass
37
37
 
@@ -60,6 +60,8 @@ module EventSorcerer
60
60
  # Private: Handles the serialization of event arguments and pushes the
61
61
  # Event object onto the _dirty_events array. Increments the local
62
62
  # version number for the aggregate.
63
+ #
64
+ # Returns argument hash.
63
65
  def add_dirty_event!(time, method_sym, *arguments)
64
66
  increment_version!
65
67
 
@@ -69,7 +71,7 @@ module EventSorcerer
69
71
  details = ArgumentHashifier.hashify(method.parameters, arguments.dup)
70
72
  @_dirty_events << Event.new(method_sym, time, details)
71
73
 
72
- self
74
+ details
73
75
  end
74
76
 
75
77
  # Private: Decrements the wrapped aggregates local version by one.
@@ -104,12 +106,10 @@ module EventSorcerer
104
106
  fail EventArgumentError if block
105
107
 
106
108
  time = Time.now
107
- add_dirty_event!(time, method_sym, *arguments)
108
-
109
- expected_args = arguments.slice(0, @_aggregate.method(method_sym).arity)
109
+ details = add_dirty_event!(time, method_sym, *arguments)
110
110
 
111
111
  EventSorcerer.with_time(time) do
112
- @_aggregate.send method_sym, *expected_args
112
+ Invokr.invoke method: method_sym, on: @_aggregate, using: details
113
113
  end
114
114
  rescue StandardError => e
115
115
  undo_dirty_event!
@@ -8,7 +8,7 @@ module EventSorcerer
8
8
  delegates :EventSorcerer, :message_bus
9
9
 
10
10
  # Public: Returns nil.
11
- def fetch_aggregate(_id)
11
+ def fetch_aggregate(_type, _id)
12
12
  nil
13
13
  end
14
14
 
@@ -41,12 +41,15 @@ module EventSorcerer
41
41
 
42
42
  # Public: Fetches an aggregate via it's ID from the identity map.
43
43
  #
44
- # id - the ID for the aggregate.
44
+ # type - the type for the aggregate.
45
+ # id - the ID for the aggregate.
45
46
  #
46
47
  # Returns nil if not found.
47
48
  # Returns Aggregate if found.
48
- def fetch_aggregate(id)
49
- identity_map[id]
49
+ def fetch_aggregate(type, id)
50
+ return unless identity_map[type]
51
+
52
+ identity_map[type][id]
50
53
  end
51
54
 
52
55
  def handle_save(save)
@@ -61,9 +64,9 @@ module EventSorcerer
61
64
  #
62
65
  # Returns self.
63
66
  def store_aggregate(aggregate)
64
- return self if fetch_aggregate(aggregate.id)
65
-
66
- identity_map[aggregate.id] = aggregate
67
+ type = aggregate.class.to_s
68
+ identity_map[type] ||= {}
69
+ identity_map[type][aggregate.id] = aggregate
67
70
 
68
71
  self
69
72
  end
@@ -1,4 +1,4 @@
1
1
  # Public: Defines a constant for the current version number.
2
2
  module EventSorcerer
3
- VERSION = '0.1.2'
3
+ VERSION = '0.1.3'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_sorcerer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Edwards
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-04 00:00:00.000000000 Z
11
+ date: 2014-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler