ruby_event_store-active_record 2.17.1 → 2.18.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 +4 -4
- data/lib/ruby_event_store/active_record/event_repository.rb +65 -55
- data/lib/ruby_event_store/active_record/generators/rails_migration_generator.rb +1 -1
- data/lib/ruby_event_store/active_record/railtie.rb +6 -0
- data/lib/ruby_event_store/active_record/version.rb +1 -1
- data/lib/ruby_event_store/active_record.rb +6 -3
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b1a98f057ae20e009d0e1939e1ae406b99e87584ddd5bfdcb54206ea3224ec6
|
|
4
|
+
data.tar.gz: fb2d8ed0c5fe1016d7bb51e73ebbc67a86306ddfb0c54867d8574bc88186d033
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99df7fd77ccf209de25cc81b8e81fdafaee33acf0ef329f8cd541e8332f8819632d630cc62afd403c0672ee76ae8159e14fefa1b518639b6e2e5b555b4beb979
|
|
7
|
+
data.tar.gz: 60f305f44dcea39d1408a1776e902f9812b44244b20ee046f115521c34a74864e3e481e53853ab005dbf802cea1570aba9b90bc28afc08b5800cc402ee9df2cc
|
|
@@ -7,48 +7,23 @@ module RubyEventStore
|
|
|
7
7
|
|
|
8
8
|
def initialize(model_factory: WithDefaultModels.new, serializer:)
|
|
9
9
|
@serializer = serializer
|
|
10
|
-
@
|
|
11
|
-
if serializer == NULL && json_data_type?
|
|
12
|
-
warn <<~MSG
|
|
13
|
-
The data or metadata column is of a JSON/B type and expects a JSON string.
|
|
14
|
-
|
|
15
|
-
Yet the repository serializer is configured as #{serializer} and it would not
|
|
16
|
-
produce the expected JSON string.
|
|
17
|
-
|
|
18
|
-
In ActiveRecord there's an implicit serialization to JSON for JSON/B column types
|
|
19
|
-
that made it work so far. This behaviour is unfortunately also a source of undesired
|
|
20
|
-
double serialization — first in the EventRepository, second in the ActiveRecord.
|
|
21
|
-
|
|
22
|
-
In the past we've advised workarounds that introduced configuration incosistency
|
|
23
|
-
with other data types and serialization formats, i.e. explicitly passing NULL serializer
|
|
24
|
-
just for the JSON/B data types.
|
|
25
|
-
|
|
26
|
-
As of now this special ActiveRecord behaviour is disabled. You should be using JSON
|
|
27
|
-
serializer back again:
|
|
28
|
-
|
|
29
|
-
RubyEventStore::ActiveRecord::EventRepository.new(serializer: JSON)
|
|
30
|
-
MSG
|
|
31
|
-
else
|
|
32
|
-
@event_klass.include(SkipJsonSerialization)
|
|
33
|
-
end
|
|
34
|
-
@repo_reader = EventRepositoryReader.new(@event_klass, @stream_klass, serializer)
|
|
35
|
-
@index_violation_detector = IndexViolationDetector.new(@event_klass.table_name, @stream_klass.table_name)
|
|
10
|
+
@model_factory = model_factory
|
|
36
11
|
end
|
|
37
12
|
|
|
38
13
|
def rescue_from_double_json_serialization!
|
|
39
|
-
if serializer == JSON && json_data_type?
|
|
40
|
-
|
|
14
|
+
if @serializer == JSON && json_data_type?(event_klass)
|
|
15
|
+
repo_reader.instance_eval { alias __record__ record }
|
|
41
16
|
|
|
42
|
-
|
|
17
|
+
repo_reader.define_singleton_method :unwrap do |column_name, payload|
|
|
43
18
|
if String === payload && payload.start_with?("\{")
|
|
44
19
|
warn "Double serialization of #{column_name} column detected"
|
|
45
|
-
serializer.load(payload)
|
|
20
|
+
@serializer.load(payload)
|
|
46
21
|
else
|
|
47
22
|
payload
|
|
48
23
|
end
|
|
49
24
|
end
|
|
50
25
|
|
|
51
|
-
|
|
26
|
+
repo_reader.define_singleton_method :record do |record|
|
|
52
27
|
r = __record__(record)
|
|
53
28
|
|
|
54
29
|
Record.new(
|
|
@@ -76,31 +51,31 @@ module RubyEventStore
|
|
|
76
51
|
end
|
|
77
52
|
|
|
78
53
|
def delete_stream(stream)
|
|
79
|
-
|
|
54
|
+
stream_klass.where(stream: stream.name).delete_all
|
|
80
55
|
end
|
|
81
56
|
|
|
82
57
|
def has_event?(event_id)
|
|
83
|
-
|
|
58
|
+
repo_reader.has_event?(event_id)
|
|
84
59
|
end
|
|
85
60
|
|
|
86
61
|
def last_stream_event(stream)
|
|
87
|
-
|
|
62
|
+
repo_reader.last_stream_event(stream)
|
|
88
63
|
end
|
|
89
64
|
|
|
90
65
|
def read(specification)
|
|
91
|
-
|
|
66
|
+
repo_reader.read(specification)
|
|
92
67
|
end
|
|
93
68
|
|
|
94
69
|
def count(specification)
|
|
95
|
-
|
|
70
|
+
repo_reader.count(specification)
|
|
96
71
|
end
|
|
97
72
|
|
|
98
73
|
def update_messages(records)
|
|
99
|
-
hashes = records.map { |record| upsert_hash(record, record.serialize(serializer)) }
|
|
74
|
+
hashes = records.map { |record| upsert_hash(record, record.serialize(@serializer)) }
|
|
100
75
|
for_update = records.map(&:event_id)
|
|
101
76
|
start_transaction do
|
|
102
77
|
existing =
|
|
103
|
-
|
|
78
|
+
event_klass
|
|
104
79
|
.where(event_id: for_update)
|
|
105
80
|
.pluck(:event_id, :id, :created_at)
|
|
106
81
|
.reduce({}) { |acc, (event_id, id, created_at)| acc.merge(event_id => [id, created_at]) }
|
|
@@ -109,33 +84,31 @@ module RubyEventStore
|
|
|
109
84
|
h[:id] = existing.fetch(h.fetch(:event_id)).at(0)
|
|
110
85
|
h[:created_at] = existing.fetch(h.fetch(:event_id)).at(1)
|
|
111
86
|
end
|
|
112
|
-
|
|
87
|
+
event_klass.upsert_all(hashes)
|
|
113
88
|
end
|
|
114
89
|
end
|
|
115
90
|
|
|
116
91
|
def streams_of(event_id)
|
|
117
|
-
|
|
92
|
+
repo_reader.streams_of(event_id)
|
|
118
93
|
end
|
|
119
94
|
|
|
120
95
|
def position_in_stream(event_id, stream)
|
|
121
|
-
|
|
96
|
+
repo_reader.position_in_stream(event_id, stream)
|
|
122
97
|
end
|
|
123
98
|
|
|
124
99
|
def global_position(event_id)
|
|
125
|
-
|
|
100
|
+
repo_reader.global_position(event_id)
|
|
126
101
|
end
|
|
127
102
|
|
|
128
103
|
def event_in_stream?(event_id, stream)
|
|
129
|
-
|
|
104
|
+
repo_reader.event_in_stream?(event_id, stream)
|
|
130
105
|
end
|
|
131
106
|
|
|
132
107
|
private
|
|
133
108
|
|
|
134
|
-
attr_reader :serializer
|
|
135
|
-
|
|
136
109
|
def add_to_stream(event_ids, stream, expected_version)
|
|
137
110
|
last_stream_version = ->(stream_) do
|
|
138
|
-
|
|
111
|
+
stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position)
|
|
139
112
|
end
|
|
140
113
|
resolved_version = expected_version.resolve_for(stream, last_stream_version)
|
|
141
114
|
|
|
@@ -150,7 +123,7 @@ module RubyEventStore
|
|
|
150
123
|
created_at: Time.now.utc,
|
|
151
124
|
}
|
|
152
125
|
end
|
|
153
|
-
|
|
126
|
+
stream_klass.insert_all!(in_stream) unless stream.global?
|
|
154
127
|
end
|
|
155
128
|
self
|
|
156
129
|
rescue ::ActiveRecord::RecordNotUnique => e
|
|
@@ -167,7 +140,7 @@ module RubyEventStore
|
|
|
167
140
|
end
|
|
168
141
|
|
|
169
142
|
def detect_index_violated(message)
|
|
170
|
-
|
|
143
|
+
index_violation_detector.detect(message)
|
|
171
144
|
end
|
|
172
145
|
|
|
173
146
|
def insert_hash(record, serialized_record)
|
|
@@ -196,11 +169,11 @@ module RubyEventStore
|
|
|
196
169
|
end
|
|
197
170
|
|
|
198
171
|
def start_transaction(&block)
|
|
199
|
-
|
|
172
|
+
event_klass.transaction(requires_new: true, &block)
|
|
200
173
|
end
|
|
201
174
|
|
|
202
175
|
def link_to_stream_(event_ids, stream, expected_version)
|
|
203
|
-
(event_ids -
|
|
176
|
+
(event_ids - event_klass.where(event_id: event_ids).pluck(:event_id)).each { |id| raise EventNotFound.new(id) }
|
|
204
177
|
add_to_stream(event_ids, stream, expected_version)
|
|
205
178
|
end
|
|
206
179
|
|
|
@@ -208,16 +181,53 @@ module RubyEventStore
|
|
|
208
181
|
hashes = []
|
|
209
182
|
event_ids = []
|
|
210
183
|
records.each do |record|
|
|
211
|
-
hashes << insert_hash(record, record.serialize(serializer))
|
|
184
|
+
hashes << insert_hash(record, record.serialize(@serializer))
|
|
212
185
|
event_ids << record.event_id
|
|
213
186
|
end
|
|
214
|
-
add_to_stream(event_ids, stream, expected_version) {
|
|
187
|
+
add_to_stream(event_ids, stream, expected_version) { event_klass.insert_all!(hashes) }
|
|
215
188
|
end
|
|
216
189
|
|
|
217
|
-
|
|
190
|
+
def model_klasses
|
|
191
|
+
@model_klasses ||= @model_factory.call.tap do |event_model, stream_model|
|
|
192
|
+
if @serializer == NULL && json_data_type?(event_model)
|
|
193
|
+
warn <<~MSG
|
|
194
|
+
The data or metadata column is of a JSON/B type and expects a JSON string.
|
|
195
|
+
|
|
196
|
+
Yet the repository serializer is configured as #{@serializer} and it would not
|
|
197
|
+
produce the expected JSON string.
|
|
198
|
+
|
|
199
|
+
In ActiveRecord there's an implicit serialization to JSON for JSON/B column types
|
|
200
|
+
that made it work so far. This behaviour is unfortunately also a source of undesired
|
|
201
|
+
double serialization — first in the EventRepository, second in the ActiveRecord.
|
|
202
|
+
|
|
203
|
+
In the past we've advised workarounds that introduced configuration incosistency
|
|
204
|
+
with other data types and serialization formats, i.e. explicitly passing NULL serializer
|
|
205
|
+
just for the JSON/B data types.
|
|
206
|
+
|
|
207
|
+
As of now this special ActiveRecord behaviour is disabled. You should be using JSON
|
|
208
|
+
serializer back again:
|
|
209
|
+
|
|
210
|
+
RubyEventStore::ActiveRecord::EventRepository.new(serializer: JSON)
|
|
211
|
+
MSG
|
|
212
|
+
else
|
|
213
|
+
event_model.include(SkipJsonSerialization)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def event_klass = model_klasses.first
|
|
219
|
+
def stream_klass = model_klasses.last
|
|
220
|
+
|
|
221
|
+
def repo_reader
|
|
222
|
+
@repo_reader ||= EventRepositoryReader.new(event_klass, stream_klass, @serializer)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def index_violation_detector
|
|
226
|
+
@index_violation_detector ||= IndexViolationDetector.new(event_klass.table_name, stream_klass.table_name)
|
|
227
|
+
end
|
|
218
228
|
|
|
219
|
-
def json_data_type?
|
|
220
|
-
%i[data metadata].any? { |attr|
|
|
229
|
+
def json_data_type?(klass)
|
|
230
|
+
%i[data metadata].any? { |attr| klass.column_for_attribute(attr).type.start_with?("json") }
|
|
221
231
|
end
|
|
222
232
|
end
|
|
223
233
|
end
|
|
@@ -27,7 +27,7 @@ module RubyEventStore
|
|
|
27
27
|
|
|
28
28
|
@database_adapter = DatabaseAdapter.from_string(adapter_name, data_type)
|
|
29
29
|
rescue UnsupportedAdapter => e
|
|
30
|
-
raise Error, e
|
|
30
|
+
raise Error, e
|
|
31
31
|
rescue InvalidDataTypeForAdapter
|
|
32
32
|
raise Error,
|
|
33
33
|
"Invalid value for --data-type option. Supported for options are: #{DatabaseAdapter.from_string(adapter_name).supported_data_types.join(", ")}."
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
module RubyEventStore
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
|
6
|
+
initializer "ruby_event_store-active_record" do
|
|
7
|
+
ActiveSupport.on_load(:active_record) do
|
|
8
|
+
require_relative "../active_record/skip_json_serialization"
|
|
9
|
+
require_relative "../active_record/event"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
6
12
|
end
|
|
7
13
|
end
|
|
8
14
|
end
|
|
@@ -15,6 +15,9 @@ require_relative "active_record/event_repository_reader"
|
|
|
15
15
|
require_relative "active_record/index_violation_detector"
|
|
16
16
|
require_relative "active_record/pg_linearized_event_repository"
|
|
17
17
|
require_relative "active_record/version"
|
|
18
|
-
|
|
19
|
-
require_relative "active_record/
|
|
20
|
-
|
|
18
|
+
if defined?(Rails::Engine)
|
|
19
|
+
require_relative "active_record/railtie"
|
|
20
|
+
else
|
|
21
|
+
require_relative "active_record/skip_json_serialization"
|
|
22
|
+
require_relative "active_record/event"
|
|
23
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_event_store-active_record
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.18.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Arkency
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 2.
|
|
18
|
+
version: 2.18.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 2.
|
|
25
|
+
version: 2.18.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: activerecord
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
103
103
|
- !ruby/object:Gem::Version
|
|
104
104
|
version: '0'
|
|
105
105
|
requirements: []
|
|
106
|
-
rubygems_version: 3.
|
|
106
|
+
rubygems_version: 3.7.2
|
|
107
107
|
specification_version: 4
|
|
108
108
|
summary: Persistent event repository implementation for RubyEventStore based on ActiveRecord
|
|
109
109
|
test_files: []
|