rails_event_store_active_record 0.23.0 → 0.24.0

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: 06ea3fef184541012ee334e70e402adf48805ece
4
- data.tar.gz: ebe5b085930e57e45abbe1015e6cd31ca84c0650
3
+ metadata.gz: aa7cbc8a46e69a907a86eb49221525581ced5792
4
+ data.tar.gz: e585c4784333d52636512824facd16ebc5b09657
5
5
  SHA512:
6
- metadata.gz: bc05259c542106541612cc624832e3f2b475e579a510396b28e32adde6652e663151a2eb1ee5c8dd3f9f8e73340ae41c931482722d755b8513e8565b34ead33c
7
- data.tar.gz: df3e1ce033b90271cdb4b0a77bef69455ac807b176b73ffae84fe380bd7964c8265729203180a781fcdac3d04b09c1a26b0fcf9f7b76d54f59f1ac1d5c8dfca3
6
+ metadata.gz: 919a3e5a8715712d4a4750d7885a8889cacf8acca6abb23f1e975f797149a10df2cd4f5971cd406d6ff9a46972fae6890d648dd17d06d50c4cc2dccf728678e0
7
+ data.tar.gz: 00da8c71db44a47186acd50b1d99dcca82646d47777cdcb22d39cee96f15734c57babb722cdc73d0fffa4c0d1e04e8b7f68ed9bc3e5ce391ad5e5a40ee9eec5e
data/Makefile CHANGED
@@ -13,9 +13,7 @@ test: ## Run tests
13
13
  mutate: test ## Run mutation tests
14
14
  @echo "Running mutation tests - only 100% free mutation will be accepted"
15
15
  @bundle exec mutant --include lib --require ruby_event_store --use rspec "RailsEventStoreActiveRecord*" \
16
- --ignore-subject "RailsEventStoreActiveRecord::EventRepository#normalize_to_array" \
17
- --ignore-subject "RailsEventStoreActiveRecord::LegacyEventRepository#normalize_to_array" \
18
- --ignore-subject "RailsEventStoreActiveRecord::EventRepository#detect_index_violated"
16
+ --ignore-subject "RailsEventStoreActiveRecord::IndexViolationDetector#detect"
19
17
 
20
18
  build:
21
19
  @gem build -V rails_event_store_active_record.gemspec
@@ -2,5 +2,8 @@ require 'rails_event_store_active_record/generators/migration_generator'
2
2
  require 'rails_event_store_active_record/generators/v1_v2_migration_generator'
3
3
  require 'rails_event_store_active_record/event'
4
4
  require 'rails_event_store_active_record/event_repository'
5
+ require 'rails_event_store_active_record/event_repository_reader'
6
+ require 'rails_event_store_active_record/correct_schema_verifier'
7
+ require 'rails_event_store_active_record/index_violation_detector'
5
8
  require 'rails_event_store_active_record/legacy_event_repository'
6
9
  require 'rails_event_store_active_record/version'
@@ -0,0 +1,65 @@
1
+ module RailsEventStoreActiveRecord
2
+
3
+ class EventRepository
4
+ InvalidDatabaseSchema = Class.new(StandardError)
5
+ end
6
+
7
+ class CorrectSchemaVerifier
8
+ def verify
9
+ return unless ActiveRecord::Base.connected?
10
+ raise_invalid_db_schema if legacy_columns.eql?(current_columns)
11
+ end
12
+
13
+ private
14
+
15
+ def raise_invalid_db_schema
16
+ raise EventRepository::InvalidDatabaseSchema.new(incorrect_schema_message)
17
+ end
18
+
19
+ def legacy_columns
20
+ [
21
+ "id",
22
+ "stream",
23
+ "event_type",
24
+ "event_id",
25
+ "metadata",
26
+ "data",
27
+ "created_at"
28
+ ]
29
+ end
30
+
31
+ def current_columns
32
+ ActiveRecord::Base.connection.columns("event_store_events").map(&:name)
33
+ end
34
+
35
+ def incorrect_schema_message
36
+ <<-MESSAGE
37
+ Oh no!
38
+
39
+ It seems you're using RailsEventStoreActiveRecord::EventRepository
40
+ with incompaible database schema.
41
+
42
+ We've redesigned database structure in order to fix several concurrency-related
43
+ bugs. This repository is intended to work on that improved data layout.
44
+
45
+ We've prepared migration that would take you from old schema to new one.
46
+ This migration must be run offline -- take that into consideration:
47
+
48
+ rails g rails_event_store_active_record:v1_v2_migration
49
+ rake db:migrate
50
+
51
+
52
+ If you cannot migrate right now -- you can for some time continue using
53
+ old repository. In order to do so, change configuration accordingly:
54
+
55
+ config.event_store = RailsEventStore::Client.new(
56
+ repository: RailsEventStoreActiveRecord::LegacyEventRepository.new
57
+ )
58
+
59
+
60
+ MESSAGE
61
+ end
62
+ end
63
+
64
+ private_constant(:CorrectSchemaVerifier)
65
+ end
@@ -2,17 +2,17 @@ require 'activerecord-import'
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
4
  class EventRepository
5
- InvalidDatabaseSchema = Class.new(StandardError)
6
5
 
7
6
  POSITION_SHIFT = 1
8
7
 
9
8
  def initialize(mapper: RubyEventStore::Mappers::Default.new)
10
9
  verify_correct_schema_present
11
- @mapper = mapper
10
+ @mapper = mapper
11
+ @repo_reader = EventRepositoryReader.new(mapper)
12
12
  end
13
13
 
14
14
  def append_to_stream(events, stream_name, expected_version)
15
- add_to_stream(events, stream_name, expected_version, true) do |event|
15
+ add_to_stream(normalize_to_array(events), stream_name, expected_version, true) do |event|
16
16
  build_event_record(event).save!
17
17
  event.event_id
18
18
  end
@@ -22,7 +22,7 @@ module RailsEventStoreActiveRecord
22
22
  (normalize_to_array(event_ids) - Event.where(id: event_ids).pluck(:id)).each do |id|
23
23
  raise RubyEventStore::EventNotFound.new(id)
24
24
  end
25
- add_to_stream(event_ids, stream_name, expected_version, nil) do |event_id|
25
+ add_to_stream(normalize_to_array(event_ids), stream_name, expected_version, nil) do |event_id|
26
26
  event_id
27
27
  end
28
28
  end
@@ -32,85 +32,43 @@ module RailsEventStoreActiveRecord
32
32
  end
33
33
 
34
34
  def has_event?(event_id)
35
- Event.exists?(id: event_id)
35
+ @repo_reader.has_event?(event_id)
36
36
  end
37
37
 
38
38
  def last_stream_event(stream_name)
39
- record = EventInStream.where(stream: stream_name).order('position DESC, id DESC').first
40
- record && build_event_instance(record)
39
+ @repo_reader.last_stream_event(stream_name)
41
40
  end
42
41
 
43
42
  def read_events_forward(stream_name, after_event_id, count)
44
- stream = EventInStream.where(stream: stream_name)
45
- unless after_event_id.equal?(:head)
46
- after_event = stream.find_by!(event_id: after_event_id)
47
- stream = stream.where('id > ?', after_event)
48
- end
49
-
50
- stream.preload(:event).order('position ASC, id ASC').limit(count)
51
- .map(&method(:build_event_instance))
43
+ @repo_reader.read_events_forward(stream_name, after_event_id, count)
52
44
  end
53
45
 
54
46
  def read_events_backward(stream_name, before_event_id, count)
55
- stream = EventInStream.where(stream: stream_name)
56
- unless before_event_id.equal?(:head)
57
- before_event = stream.find_by!(event_id: before_event_id)
58
- stream = stream.where('id < ?', before_event)
59
- end
60
-
61
- stream.preload(:event).order('position DESC, id DESC').limit(count)
62
- .map(&method(:build_event_instance))
47
+ @repo_reader.read_events_backward(stream_name, before_event_id, count)
63
48
  end
64
49
 
65
50
  def read_stream_events_forward(stream_name)
66
- EventInStream.preload(:event).where(stream: stream_name).order('position ASC, id ASC')
67
- .map(&method(:build_event_instance))
51
+ @repo_reader.read_stream_events_forward(stream_name)
68
52
  end
69
53
 
70
54
  def read_stream_events_backward(stream_name)
71
- EventInStream.preload(:event).where(stream: stream_name).order('position DESC, id DESC')
72
- .map(&method(:build_event_instance))
55
+ @repo_reader.read_stream_events_backward(stream_name)
73
56
  end
74
57
 
75
58
  def read_all_streams_forward(after_event_id, count)
76
- stream = EventInStream.where(stream: RubyEventStore::GLOBAL_STREAM)
77
- unless after_event_id.equal?(:head)
78
- after_event = stream.find_by!(event_id: after_event_id)
79
- stream = stream.where('id > ?', after_event)
80
- end
81
-
82
- stream.preload(:event).order('id ASC').limit(count)
83
- .map(&method(:build_event_instance))
59
+ @repo_reader.read_all_streams_forward(after_event_id, count)
84
60
  end
85
61
 
86
62
  def read_all_streams_backward(before_event_id, count)
87
- stream = EventInStream.where(stream: RubyEventStore::GLOBAL_STREAM)
88
- unless before_event_id.equal?(:head)
89
- before_event = stream.find_by!(event_id: before_event_id)
90
- stream = stream.where('id < ?', before_event)
91
- end
92
-
93
- stream.preload(:event).order('id DESC').limit(count)
94
- .map(&method(:build_event_instance))
63
+ @repo_reader.read_all_streams_backward(before_event_id, count)
95
64
  end
96
65
 
97
66
  def read_event(event_id)
98
- event = Event.find(event_id)
99
- serialized_record = RubyEventStore::SerializedRecord.new(
100
- event_id: event.id,
101
- metadata: event.metadata,
102
- data: event.data,
103
- event_type: event.event_type
104
- )
105
- mapper.serialized_record_to_event(serialized_record)
106
- rescue ActiveRecord::RecordNotFound
107
- raise RubyEventStore::EventNotFound.new(event_id)
67
+ @repo_reader.read_event(event_id)
108
68
  end
109
69
 
110
70
  def get_all_streams
111
- (["all"] + EventInStream.pluck(:stream))
112
- .uniq
113
- .map { |name| RubyEventStore::Stream.new(name) }
71
+ @repo_reader.get_all_streams
114
72
  end
115
73
 
116
74
  private
@@ -120,7 +78,6 @@ module RailsEventStoreActiveRecord
120
78
  def add_to_stream(collection, stream_name, expected_version, include_global, &to_event_id)
121
79
  raise RubyEventStore::InvalidExpectedVersion if stream_name.eql?(RubyEventStore::GLOBAL_STREAM) && !expected_version.equal?(:any)
122
80
 
123
- collection = normalize_to_array(collection)
124
81
  expected_version = normalize_expected_version(expected_version, stream_name)
125
82
 
126
83
  ActiveRecord::Base.transaction(requires_new: true) do
@@ -148,7 +105,7 @@ module RailsEventStoreActiveRecord
148
105
  end
149
106
 
150
107
  def raise_error(e)
151
- if detect_index_violated(e)
108
+ if detect_index_violated(e.message)
152
109
  raise RubyEventStore::EventDuplicatedInStream
153
110
  end
154
111
  raise RubyEventStore::WrongExpectedEventVersion
@@ -174,23 +131,8 @@ module RailsEventStoreActiveRecord
174
131
  end
175
132
  end
176
133
 
177
- MYSQL_PKEY_ERROR = "for key 'PRIMARY'"
178
- POSTGRES_PKEY_ERROR = "event_store_events_pkey"
179
- SQLITE3_PKEY_ERROR = "event_store_events.id"
180
-
181
- MYSQL_INDEX_ERROR = "for key 'index_event_store_events_in_streams_on_stream_and_event_id'"
182
- POSTGRES_INDEX_ERROR = "Key (stream, event_id)"
183
- SQLITE3_INDEX_ERROR = "event_store_events_in_streams.stream, event_store_events_in_streams.event_id"
184
-
185
- def detect_index_violated(e)
186
- m = e.message
187
- m.include?(MYSQL_PKEY_ERROR) ||
188
- m.include?(POSTGRES_PKEY_ERROR) ||
189
- m.include?(SQLITE3_PKEY_ERROR) ||
190
-
191
- m.include?(MYSQL_INDEX_ERROR) ||
192
- m.include?(POSTGRES_INDEX_ERROR) ||
193
- m.include?(SQLITE3_INDEX_ERROR)
134
+ def detect_index_violated(message)
135
+ IndexViolationDetector.new.detect(message)
194
136
  end
195
137
 
196
138
  def build_event_record(event)
@@ -203,53 +145,14 @@ module RailsEventStoreActiveRecord
203
145
  )
204
146
  end
205
147
 
206
- def build_event_instance(record)
207
- serialized_record = RubyEventStore::SerializedRecord.new(
208
- event_id: record.event.id,
209
- metadata: record.event.metadata,
210
- data: record.event.data,
211
- event_type: record.event.event_type
212
- )
213
- mapper.serialized_record_to_event(serialized_record)
214
- end
215
-
216
148
  def normalize_to_array(events)
217
- [*events]
218
- end
219
-
220
- def incorrect_schema_message
221
- <<-MESSAGE
222
- Oh no!
223
-
224
- It seems you're using RailsEventStoreActiveRecord::EventRepository
225
- with incompaible database schema.
226
-
227
- We've redesigned database structure in order to fix several concurrency-related
228
- bugs. This repository is intended to work on that improved data layout.
229
-
230
- We've prepared migration that would take you from old schema to new one.
231
- This migration must be run offline -- take that into consideration:
232
-
233
- rails g rails_event_store_active_record:v1_v2_migration
234
- rake db:migrate
235
-
236
-
237
- If you cannot migrate right now -- you can for some time continue using
238
- old repository. In order to do so, change configuration accordingly:
239
-
240
- config.event_store = RailsEventStore::Client.new(
241
- repository: RailsEventStoreActiveRecord::LegacyEventRepository.new
242
- )
243
-
244
-
245
- MESSAGE
149
+ return events if events.is_a?(Enumerable)
150
+ [events]
246
151
  end
247
152
 
248
153
  def verify_correct_schema_present
249
- return unless ActiveRecord::Base.connected?
250
- legacy_columns = ["id", "stream", "event_type", "event_id", "metadata", "data", "created_at"]
251
- current_columns = ActiveRecord::Base.connection.columns("event_store_events").map(&:name)
252
- raise InvalidDatabaseSchema.new(incorrect_schema_message) if legacy_columns.eql?(current_columns)
154
+ CorrectSchemaVerifier.new.verify
253
155
  end
254
156
  end
157
+
255
158
  end
@@ -0,0 +1,104 @@
1
+ module RailsEventStoreActiveRecord
2
+ class EventRepositoryReader
3
+
4
+ def initialize(mapper)
5
+ @mapper = mapper
6
+ end
7
+
8
+ def has_event?(event_id)
9
+ Event.exists?(id: event_id)
10
+ end
11
+
12
+ def last_stream_event(stream_name)
13
+ record = EventInStream.where(stream: stream_name).order('position DESC, id DESC').first
14
+ record && build_event_instance(record)
15
+ end
16
+
17
+ def read_events_forward(stream_name, after_event_id, count)
18
+ stream = EventInStream.where(stream: stream_name)
19
+ unless after_event_id.equal?(:head)
20
+ after_event = stream.find_by!(event_id: after_event_id)
21
+ stream = stream.where('id > ?', after_event)
22
+ end
23
+
24
+ stream.preload(:event).order('position ASC, id ASC').limit(count)
25
+ .map(&method(:build_event_instance))
26
+ end
27
+
28
+ def read_events_backward(stream_name, before_event_id, count)
29
+ stream = EventInStream.where(stream: stream_name)
30
+ unless before_event_id.equal?(:head)
31
+ before_event = stream.find_by!(event_id: before_event_id)
32
+ stream = stream.where('id < ?', before_event)
33
+ end
34
+
35
+ stream.preload(:event).order('position DESC, id DESC').limit(count)
36
+ .map(&method(:build_event_instance))
37
+ end
38
+
39
+ def read_stream_events_forward(stream_name)
40
+ EventInStream.preload(:event).where(stream: stream_name).order('position ASC, id ASC')
41
+ .map(&method(:build_event_instance))
42
+ end
43
+
44
+ def read_stream_events_backward(stream_name)
45
+ EventInStream.preload(:event).where(stream: stream_name).order('position DESC, id DESC')
46
+ .map(&method(:build_event_instance))
47
+ end
48
+
49
+ def read_all_streams_forward(after_event_id, count)
50
+ stream = EventInStream.where(stream: RubyEventStore::GLOBAL_STREAM)
51
+ unless after_event_id.equal?(:head)
52
+ after_event = stream.find_by!(event_id: after_event_id)
53
+ stream = stream.where('id > ?', after_event)
54
+ end
55
+
56
+ stream.preload(:event).order('id ASC').limit(count)
57
+ .map(&method(:build_event_instance))
58
+ end
59
+
60
+ def read_all_streams_backward(before_event_id, count)
61
+ stream = EventInStream.where(stream: RubyEventStore::GLOBAL_STREAM)
62
+ unless before_event_id.equal?(:head)
63
+ before_event = stream.find_by!(event_id: before_event_id)
64
+ stream = stream.where('id < ?', before_event)
65
+ end
66
+
67
+ stream.preload(:event).order('id DESC').limit(count)
68
+ .map(&method(:build_event_instance))
69
+ end
70
+
71
+ def read_event(event_id)
72
+ event = Event.find(event_id)
73
+ serialized_record = RubyEventStore::SerializedRecord.new(
74
+ event_id: event.id,
75
+ metadata: event.metadata,
76
+ data: event.data,
77
+ event_type: event.event_type
78
+ )
79
+ @mapper.serialized_record_to_event(serialized_record)
80
+ rescue ActiveRecord::RecordNotFound
81
+ raise RubyEventStore::EventNotFound.new(event_id)
82
+ end
83
+
84
+ def get_all_streams
85
+ (["all"] + EventInStream.pluck(:stream))
86
+ .uniq
87
+ .map { |name| RubyEventStore::Stream.new(name) }
88
+ end
89
+
90
+ private
91
+
92
+ def build_event_instance(record)
93
+ serialized_record = RubyEventStore::SerializedRecord.new(
94
+ event_id: record.event.id,
95
+ metadata: record.event.metadata,
96
+ data: record.event.data,
97
+ event_type: record.event.event_type
98
+ )
99
+ @mapper.serialized_record_to_event(serialized_record)
100
+ end
101
+ end
102
+
103
+ private_constant(:EventRepositoryReader)
104
+ end
@@ -0,0 +1,24 @@
1
+ module RailsEventStoreActiveRecord
2
+ class IndexViolationDetector
3
+
4
+ MYSQL_PKEY_ERROR = "for key 'PRIMARY'"
5
+ POSTGRES_PKEY_ERROR = "event_store_events_pkey"
6
+ SQLITE3_PKEY_ERROR = "event_store_events.id"
7
+
8
+ MYSQL_INDEX_ERROR = "for key 'index_event_store_events_in_streams_on_stream_and_event_id'"
9
+ POSTGRES_INDEX_ERROR = "Key (stream, event_id)"
10
+ SQLITE3_INDEX_ERROR = "event_store_events_in_streams.stream, event_store_events_in_streams.event_id"
11
+
12
+ def detect(message)
13
+ message.include?(MYSQL_PKEY_ERROR) ||
14
+ message.include?(POSTGRES_PKEY_ERROR) ||
15
+ message.include?(SQLITE3_PKEY_ERROR) ||
16
+
17
+ message.include?(MYSQL_INDEX_ERROR) ||
18
+ message.include?(POSTGRES_INDEX_ERROR) ||
19
+ message.include?(SQLITE3_INDEX_ERROR)
20
+ end
21
+ end
22
+
23
+ private_constant(:IndexViolationDetector)
24
+ end
@@ -129,7 +129,8 @@ instead:
129
129
  private
130
130
 
131
131
  def normalize_to_array(events)
132
- [*events]
132
+ return events if events.is_a?(Enumerable)
133
+ [events]
133
134
  end
134
135
 
135
136
  def build_event_entity(record)
@@ -1,3 +1,3 @@
1
1
  module RailsEventStoreActiveRecord
2
- VERSION = "0.23.0"
2
+ VERSION = "0.24.0"
3
3
  end
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'fakefs', '~> 0.11.2'
31
31
  spec.add_development_dependency 'childprocess'
32
32
 
33
- spec.add_dependency 'ruby_event_store', '= 0.23.0'
33
+ spec.add_dependency 'ruby_event_store', '= 0.24.0'
34
34
  spec.add_dependency 'activesupport', '>= 3.0'
35
35
  spec.add_dependency 'activemodel', '>= 3.0'
36
36
  spec.add_dependency 'activerecord-import', '~> 0.21'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_event_store_active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkency
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-11 00:00:00.000000000 Z
11
+ date: 2018-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -156,14 +156,14 @@ dependencies:
156
156
  requirements:
157
157
  - - '='
158
158
  - !ruby/object:Gem::Version
159
- version: 0.23.0
159
+ version: 0.24.0
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
- version: 0.23.0
166
+ version: 0.24.0
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: activesupport
169
169
  requirement: !ruby/object:Gem::Requirement
@@ -221,12 +221,15 @@ files:
221
221
  - bin/console
222
222
  - bin/setup
223
223
  - lib/rails_event_store_active_record.rb
224
+ - lib/rails_event_store_active_record/correct_schema_verifier.rb
224
225
  - lib/rails_event_store_active_record/event.rb
225
226
  - lib/rails_event_store_active_record/event_repository.rb
227
+ - lib/rails_event_store_active_record/event_repository_reader.rb
226
228
  - lib/rails_event_store_active_record/generators/migration_generator.rb
227
229
  - lib/rails_event_store_active_record/generators/templates/migration_template.rb
228
230
  - lib/rails_event_store_active_record/generators/templates/v1_v2_migration_template.rb
229
231
  - lib/rails_event_store_active_record/generators/v1_v2_migration_generator.rb
232
+ - lib/rails_event_store_active_record/index_violation_detector.rb
230
233
  - lib/rails_event_store_active_record/legacy_event_repository.rb
231
234
  - lib/rails_event_store_active_record/version.rb
232
235
  - rails_event_store_active_record.gemspec