rails_event_store_active_record 2.1.0 → 2.4.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
  SHA256:
3
- metadata.gz: 291ce390bf636caf06d9949f79aa697799079a547b282095afe8f40f27d6c84a
4
- data.tar.gz: ea74678de5019d72b1c82779815f12778e01871695aeeed3d704835ea64a9120
3
+ metadata.gz: b146f907eef70a988c0949381dbf897a4f93bd7aa9e1ccf8346559c2656feb80
4
+ data.tar.gz: 46b6f4ce8d62b7386d72a1219a375e012bd3d15b33b16fe552cb8adee9f4f6e4
5
5
  SHA512:
6
- metadata.gz: ae73534ca38d6ecb19bc599aa8ceb0b4e3705a20b38b3981637e0f7a313b3b3e29adb2bffc1048afb4b8c41733a41e0ca51030835271ddcb79d30aae1a8e4204
7
- data.tar.gz: 881dd61f6e62165dd76112b8852a20a84283d1de2fa6d601b92a8e859aab9267d55b58e8ee65cb90e04ec0c08d91f3de75c4d05bc35ecc1441443fed879c17a3
6
+ metadata.gz: 0be237c7518c776a5ee19e8625f39966a20f255b0076839695957df0aa337c181bc7c85351afb2a1fbffdd6b0fd75fa50217482c30d1aa82437b242a32552e8d
7
+ data.tar.gz: 32aa1160ba4de4081357319e25012330249b6e946d0e0b558452fe41e7a30aa25e70d65faf9897ba6b7afac841c6b2ea6011117a892a272179da58b38a96bbb4
data/README.md CHANGED
@@ -4,4 +4,4 @@ Persistent event repository implementation for RubyEventStore based on ActiveRec
4
4
 
5
5
  Includes repository implementation with linearized writes to achieve log-like properties of streams on top of SQL database engine.
6
6
 
7
- Find out more at [https://railseventstore.org](https://railseventstore.org/)
7
+ Find out more at [https://railseventstore.org](https://railseventstore.org/)
@@ -3,9 +3,9 @@
3
3
  module RailsEventStoreActiveRecord
4
4
  class BatchEnumerator
5
5
  def initialize(batch_size, total_limit, reader)
6
- @batch_size = batch_size
6
+ @batch_size = batch_size
7
7
  @total_limit = total_limit
8
- @reader = reader
8
+ @reader = reader
9
9
  end
10
10
 
11
11
  def each
@@ -13,7 +13,7 @@ module RailsEventStoreActiveRecord
13
13
  offset_id = nil
14
14
 
15
15
  0.step(total_limit - 1, batch_size) do |batch_offset|
16
- batch_limit = [batch_size, total_limit - batch_offset].min
16
+ batch_limit = [batch_size, total_limit - batch_offset].min
17
17
  results, offset_id = reader.call(offset_id, batch_limit)
18
18
 
19
19
  break if results.empty?
@@ -34,4 +34,3 @@ module RailsEventStoreActiveRecord
34
34
  attr_reader :batch_size, :total_limit, :reader
35
35
  end
36
36
  end
37
-
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_record'
3
+ require "active_record"
4
4
 
5
5
  module RailsEventStoreActiveRecord
6
6
  class Event < ::ActiveRecord::Base
7
7
  self.primary_key = :id
8
- self.table_name = 'event_store_events'
8
+ self.table_name = "event_store_events"
9
9
  end
10
10
 
11
11
  class EventInStream < ::ActiveRecord::Base
12
12
  self.primary_key = :id
13
- self.table_name = 'event_store_events_in_streams'
13
+ self.table_name = "event_store_events_in_streams"
14
14
  belongs_to :event, primary_key: :event_id
15
15
  end
16
16
  end
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/array'
4
- require 'activerecord-import'
3
+ require "active_support/core_ext/array"
5
4
 
6
5
  module RailsEventStoreActiveRecord
7
6
  class EventRepository
8
7
  POSITION_SHIFT = 1
9
8
 
10
9
  def initialize(model_factory: WithDefaultModels.new, serializer:)
11
- @serializer = serializer
10
+ @serializer = serializer
12
11
 
13
12
  @event_klass, @stream_klass = model_factory.call
14
13
  @repo_reader = EventRepositoryReader.new(@event_klass, @stream_klass, serializer)
@@ -16,15 +15,13 @@ module RailsEventStoreActiveRecord
16
15
  end
17
16
 
18
17
  def append_to_stream(records, stream, expected_version)
19
- hashes = []
18
+ hashes = []
20
19
  event_ids = []
21
20
  records.each do |record|
22
- hashes << import_hash(record, record.serialize(serializer))
21
+ hashes << insert_hash(record, record.serialize(serializer))
23
22
  event_ids << record.event_id
24
23
  end
25
- add_to_stream(event_ids, stream, expected_version) do
26
- @event_klass.import(hashes)
27
- end
24
+ add_to_stream(event_ids, stream, expected_version) { @event_klass.insert_all!(hashes) }
28
25
  end
29
26
 
30
27
  def link_to_stream(event_ids, stream, expected_version)
@@ -55,39 +52,61 @@ module RailsEventStoreActiveRecord
55
52
  end
56
53
 
57
54
  def update_messages(records)
58
- hashes = records.map { |record| import_hash(record, record.serialize(serializer)) }
55
+ hashes = records.map { |record| upsert_hash(record, record.serialize(serializer)) }
59
56
  for_update = records.map(&:event_id)
60
57
  start_transaction do
61
- existing = @event_klass.where(event_id: for_update).pluck(:event_id, :id).to_h
62
- (for_update - existing.keys).each{|id| raise RubyEventStore::EventNotFound.new(id) }
63
- hashes.each { |h| h[:id] = existing.fetch(h.fetch(:event_id)) }
64
- @event_klass.import(hashes, on_duplicate_key_update: [:data, :metadata, :event_type, :valid_at])
58
+ existing =
59
+ @event_klass
60
+ .where(event_id: for_update)
61
+ .pluck(:event_id, :id, :created_at)
62
+ .reduce({}) { |acc, (event_id, id, created_at)| acc.merge(event_id => [id, created_at]) }
63
+ (for_update - existing.keys).each { |id| raise RubyEventStore::EventNotFound.new(id) }
64
+ hashes.each do |h|
65
+ h[:id] = existing.fetch(h.fetch(:event_id)).at(0)
66
+ h[:created_at] = existing.fetch(h.fetch(:event_id)).at(1)
67
+ end
68
+ @event_klass.upsert_all(hashes)
65
69
  end
66
70
  end
67
71
 
68
72
  def streams_of(event_id)
69
- @stream_klass.where(event_id: event_id)
70
- .pluck(:stream)
71
- .map { |name| RubyEventStore::Stream.new(name) }
73
+ @repo_reader.streams_of(event_id)
74
+ end
75
+
76
+ def position_in_stream(event_id, stream)
77
+ @repo_reader.position_in_stream(event_id, stream)
78
+ end
79
+
80
+ def global_position(event_id)
81
+ @repo_reader.global_position(event_id)
82
+ end
83
+
84
+ def event_in_stream?(event_id, stream)
85
+ @repo_reader.event_in_stream?(event_id, stream)
72
86
  end
73
87
 
74
88
  private
89
+
75
90
  attr_reader :serializer
76
91
 
77
92
  def add_to_stream(event_ids, stream, expected_version)
78
- last_stream_version = ->(stream_) { @stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position) }
93
+ last_stream_version = ->(stream_) do
94
+ @stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position)
95
+ end
79
96
  resolved_version = expected_version.resolve_for(stream, last_stream_version)
80
97
 
81
98
  start_transaction do
82
99
  yield if block_given?
83
- in_stream = event_ids.map.with_index do |event_id, index|
84
- {
85
- stream: stream.name,
86
- position: compute_position(resolved_version, index),
87
- event_id: event_id,
88
- }
89
- end
90
- @stream_klass.import(in_stream) unless stream.global?
100
+ in_stream =
101
+ event_ids.map.with_index do |event_id, index|
102
+ {
103
+ stream: stream.name,
104
+ position: compute_position(resolved_version, index),
105
+ event_id: event_id,
106
+ created_at: Time.now.utc
107
+ }
108
+ end
109
+ @stream_klass.insert_all!(in_stream) unless stream.global?
91
110
  end
92
111
  self
93
112
  rescue ActiveRecord::RecordNotUnique => e
@@ -95,30 +114,36 @@ module RailsEventStoreActiveRecord
95
114
  end
96
115
 
97
116
  def raise_error(e)
98
- if detect_index_violated(e.message)
99
- raise RubyEventStore::EventDuplicatedInStream
100
- end
117
+ raise RubyEventStore::EventDuplicatedInStream if detect_index_violated(e.message)
101
118
  raise RubyEventStore::WrongExpectedEventVersion
102
119
  end
103
120
 
104
121
  def compute_position(resolved_version, index)
105
- unless resolved_version.nil?
106
- resolved_version + index + POSITION_SHIFT
107
- end
122
+ resolved_version + index + POSITION_SHIFT unless resolved_version.nil?
108
123
  end
109
124
 
110
125
  def detect_index_violated(message)
111
126
  @index_violation_detector.detect(message)
112
127
  end
113
128
 
114
- def import_hash(record, serialized_record)
129
+ def insert_hash(record, serialized_record)
115
130
  {
116
- event_id: serialized_record.event_id,
117
- data: serialized_record.data,
118
- metadata: serialized_record.metadata,
131
+ event_id: serialized_record.event_id,
132
+ data: serialized_record.data,
133
+ metadata: serialized_record.metadata,
119
134
  event_type: serialized_record.event_type,
120
135
  created_at: record.timestamp,
121
- valid_at: optimize_timestamp(record.valid_at, record.timestamp),
136
+ valid_at: optimize_timestamp(record.valid_at, record.timestamp)
137
+ }
138
+ end
139
+
140
+ def upsert_hash(record, serialized_record)
141
+ {
142
+ event_id: serialized_record.event_id,
143
+ data: serialized_record.data,
144
+ metadata: serialized_record.metadata,
145
+ event_type: serialized_record.event_type,
146
+ valid_at: optimize_timestamp(record.valid_at, record.timestamp)
122
147
  }
123
148
  end
124
149
 
@@ -130,5 +155,4 @@ module RailsEventStoreActiveRecord
130
155
  @event_klass.transaction(requires_new: true, &block)
131
156
  end
132
157
  end
133
-
134
158
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
4
  class EventRepositoryReader
5
-
6
5
  def initialize(event_klass, stream_klass, serializer)
7
6
  @event_klass = event_klass
8
7
  @stream_klass = stream_klass
@@ -14,20 +13,14 @@ module RailsEventStoreActiveRecord
14
13
  end
15
14
 
16
15
  def last_stream_event(stream)
17
- record_ = @stream_klass.where(stream: stream.name).order('position DESC, id DESC').first
16
+ record_ = @stream_klass.where(stream: stream.name).order("position DESC, id DESC").first
18
17
  record(record_) if record_
19
18
  end
20
19
 
21
20
  def read(spec)
22
21
  stream = read_scope(spec)
23
-
24
22
  if spec.batched?
25
- batch_reader = ->(offset_id, limit) do
26
- search_in = spec.stream.global? ? @event_klass.table_name : @stream_klass.table_name
27
- records = offset_id.nil? ? stream.limit(limit) : stream.where(start_offset_condition(spec, offset_id, search_in)).limit(limit)
28
- [records.map(&method(:record)), records.last]
29
- end
30
- BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
23
+ spec.time_sort_by ? offset_limit_batch_reader(spec, stream) : monotonic_id_batch_reader(spec, stream)
31
24
  elsif spec.first?
32
25
  record_ = stream.first
33
26
  record(record_) if record_
@@ -43,35 +36,75 @@ module RailsEventStoreActiveRecord
43
36
  read_scope(spec).count
44
37
  end
45
38
 
39
+ def streams_of(event_id)
40
+ @stream_klass.where(event_id: event_id).pluck(:stream).map { |name| RubyEventStore::Stream.new(name) }
41
+ end
42
+
43
+ def position_in_stream(event_id, stream)
44
+ record = @stream_klass.select("position").where(stream: stream.name).find_by(event_id: event_id)
45
+ raise RubyEventStore::EventNotFoundInStream if record.nil?
46
+ record.position
47
+ end
48
+
49
+ def global_position(event_id)
50
+ record = @event_klass.select("id").find_by(event_id: event_id)
51
+ raise RubyEventStore::EventNotFound.new(event_id) if record.nil?
52
+ record.id - 1
53
+ end
54
+
55
+ def event_in_stream?(event_id, stream)
56
+ @stream_klass.where(event_id: event_id, stream: stream.name).exists?
57
+ end
58
+
46
59
  private
60
+
47
61
  attr_reader :serializer
48
62
 
63
+ def offset_limit_batch_reader(spec, stream)
64
+ batch_reader = ->(offset, limit) { stream.offset(offset).limit(limit).map(&method(:record)) }
65
+ RubyEventStore::BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
66
+ end
67
+
68
+ def monotonic_id_batch_reader(spec, stream)
69
+ batch_reader = ->(offset_id, limit) do
70
+ search_in = spec.stream.global? ? @event_klass.table_name : @stream_klass.table_name
71
+ records =
72
+ if offset_id.nil?
73
+ stream.limit(limit)
74
+ else
75
+ stream.where(start_offset_condition(spec, offset_id, search_in)).limit(limit)
76
+ end
77
+ [records.map(&method(:record)), records.last]
78
+ end
79
+ BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
80
+ end
81
+
49
82
  def read_scope(spec)
50
83
  if spec.stream.global?
51
84
  stream = @event_klass
52
- stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
53
- stream = stream.where(event_type: spec.with_types) if spec.with_types?
85
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
86
+ stream = stream.where(event_type: spec.with_types) if spec.with_types?
54
87
  stream = ordered(stream, spec)
55
- stream = stream.limit(spec.limit) if spec.limit?
56
- stream = stream.where(start_condition_in_global_stream(spec)) if spec.start
57
- stream = stream.where(stop_condition_in_global_stream(spec)) if spec.stop
58
- stream = stream.where(older_than_condition(spec)) if spec.older_than
88
+ stream = stream.limit(spec.limit) if spec.limit?
89
+ stream = stream.where(start_condition_in_global_stream(spec)) if spec.start
90
+ stream = stream.where(stop_condition_in_global_stream(spec)) if spec.stop
91
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
59
92
  stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
60
- stream = stream.where(newer_than_condition(spec)) if spec.newer_than
93
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
61
94
  stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
62
95
  stream.order(id: order(spec))
63
96
  else
64
97
  stream = @stream_klass.preload(:event).where(stream: spec.stream.name)
65
- stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
66
- stream = stream.where(@event_klass.table_name => {event_type: spec.with_types}) if spec.with_types?
98
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
99
+ stream = stream.where(@event_klass.table_name => { event_type: spec.with_types }) if spec.with_types?
67
100
  stream = ordered(stream.joins(:event), spec)
68
- stream = stream.order(position: order(spec), id: order(spec))
69
- stream = stream.limit(spec.limit) if spec.limit?
70
- stream = stream.where(start_condition(spec)) if spec.start
71
- stream = stream.where(stop_condition(spec)) if spec.stop
72
- stream = stream.where(older_than_condition(spec)) if spec.older_than
101
+ stream = stream.order(id: order(spec))
102
+ stream = stream.limit(spec.limit) if spec.limit?
103
+ stream = stream.where(start_condition(spec)) if spec.start
104
+ stream = stream.where(stop_condition(spec)) if spec.stop
105
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
73
106
  stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
74
- stream = stream.where(newer_than_condition(spec)) if spec.newer_than
107
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
75
108
  stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
76
109
  stream
77
110
  end
@@ -89,37 +122,41 @@ module RailsEventStoreActiveRecord
89
122
  end
90
123
 
91
124
  def start_offset_condition(specification, record_id, search_in)
92
- condition = "#{search_in}.id #{specification.forward? ? '>' : '<'} ?"
125
+ condition = "#{search_in}.id #{specification.forward? ? ">" : "<"} ?"
93
126
  [condition, record_id]
94
127
  end
95
128
 
96
129
  def stop_offset_condition(specification, record_id, search_in)
97
- condition = "#{search_in}.id #{specification.forward? ? '<' : '>'} ?"
130
+ condition = "#{search_in}.id #{specification.forward? ? "<" : ">"} ?"
98
131
  [condition, record_id]
99
132
  end
100
133
 
101
134
  def start_condition(specification)
102
- start_offset_condition(specification,
135
+ start_offset_condition(
136
+ specification,
103
137
  @stream_klass.find_by!(event_id: specification.start, stream: specification.stream.name),
104
- @stream_klass.table_name)
138
+ @stream_klass.table_name
139
+ )
105
140
  end
106
141
 
107
142
  def stop_condition(specification)
108
- stop_offset_condition(specification,
143
+ stop_offset_condition(
144
+ specification,
109
145
  @stream_klass.find_by!(event_id: specification.stop, stream: specification.stream.name),
110
- @stream_klass.table_name)
146
+ @stream_klass.table_name
147
+ )
111
148
  end
112
149
 
113
150
  def start_condition_in_global_stream(specification)
114
- start_offset_condition(specification,
151
+ start_offset_condition(
152
+ specification,
115
153
  @event_klass.find_by!(event_id: specification.start),
116
- @event_klass.table_name)
154
+ @event_klass.table_name
155
+ )
117
156
  end
118
157
 
119
158
  def stop_condition_in_global_stream(specification)
120
- stop_offset_condition(specification,
121
- @event_klass.find_by!(event_id: specification.stop),
122
- @event_klass.table_name)
159
+ stop_offset_condition(specification, @event_klass.find_by!(event_id: specification.stop), @event_klass.table_name)
123
160
  end
124
161
 
125
162
  def older_than_condition(specification)
@@ -139,20 +176,22 @@ module RailsEventStoreActiveRecord
139
176
  end
140
177
 
141
178
  def order(spec)
142
- spec.forward? ? 'ASC' : 'DESC'
179
+ spec.forward? ? "ASC" : "DESC"
143
180
  end
144
181
 
145
182
  def record(record)
146
183
  record = record.event if @stream_klass === record
147
184
 
148
- RubyEventStore::SerializedRecord.new(
149
- event_id: record.event_id,
150
- metadata: record.metadata,
151
- data: record.data,
152
- event_type: record.event_type,
153
- timestamp: record.created_at.iso8601(RubyEventStore::TIMESTAMP_PRECISION),
154
- valid_at: (record.valid_at || record.created_at).iso8601(RubyEventStore::TIMESTAMP_PRECISION),
155
- ).deserialize(serializer)
185
+ RubyEventStore::SerializedRecord
186
+ .new(
187
+ event_id: record.event_id,
188
+ metadata: record.metadata,
189
+ data: record.data,
190
+ event_type: record.event_type,
191
+ timestamp: record.created_at.iso8601(RubyEventStore::TIMESTAMP_PRECISION),
192
+ valid_at: (record.valid_at || record.created_at).iso8601(RubyEventStore::TIMESTAMP_PRECISION)
193
+ )
194
+ .deserialize(serializer)
156
195
  end
157
196
  end
158
197
 
@@ -1,22 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'rails/generators'
4
+ require "rails/generators"
5
5
  rescue LoadError
6
6
  end
7
7
 
8
8
  module RailsEventStoreActiveRecord
9
9
  class MigrationGenerator < Rails::Generators::Base
10
- class Error < Thor::Error; end
10
+ class Error < Thor::Error
11
+ end
11
12
 
12
- DATA_TYPES = %w(binary json jsonb).freeze
13
+ DATA_TYPES = %w[binary json jsonb].freeze
13
14
 
14
- source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
15
+ source_root File.expand_path(File.join(File.dirname(__FILE__), "../generators/templates"))
15
16
  class_option(
16
17
  :data_type,
17
18
  type: :string,
18
- default: 'binary',
19
- desc: "Configure the data type for `data` and `meta data` fields in Postgres migration (options: #{DATA_TYPES.join('/')})"
19
+ default: "binary",
20
+ desc:
21
+ "Configure the data type for `data` and `meta data` fields in Postgres migration (options: #{DATA_TYPES.join("/")})"
20
22
  )
21
23
 
22
24
  def initialize(*args)
@@ -34,7 +36,7 @@ module RailsEventStoreActiveRecord
34
36
  private
35
37
 
36
38
  def data_type
37
- options.fetch('data_type')
39
+ options.fetch("data_type")
38
40
  end
39
41
 
40
42
  def migration_version
@@ -45,4 +47,4 @@ module RailsEventStoreActiveRecord
45
47
  Time.now.strftime("%Y%m%d%H%M%S")
46
48
  end
47
49
  end
48
- end if defined?(Rails::Generators::Base)
50
+ end if defined?(Rails::Generators::Base)
@@ -2,38 +2,42 @@
2
2
 
3
3
  class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
4
4
  def change
5
- postgres = ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
6
- sqlite = ActiveRecord::Base.connection.adapter_name == "SQLite"
7
-
8
- enable_extension "pgcrypto" if postgres
9
- create_table(:event_store_events_in_streams, force: false) do |t|
10
- t.string :stream, null: false
11
- t.integer :position, null: true
12
- if postgres
13
- t.references :event, null: false, type: :uuid
14
- else
15
- t.references :event, null: false, type: :string, limit: 36
16
- end
17
- if postgres
5
+ postgres =
6
+ ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
7
+ if postgres
8
+ create_table(:event_store_events_in_streams, id: :bigserial, force: false) do |t|
9
+ t.string :stream, null: false
10
+ t.integer :position, null: true
11
+ t.references :event, null: false, type: :uuid
18
12
  t.datetime :created_at, null: false
19
- else
20
- t.datetime :created_at, null: false, precision: 6
21
13
  end
22
- end
23
- add_index :event_store_events_in_streams, [:stream, :position], unique: true
24
- add_index :event_store_events_in_streams, [:created_at]
25
- add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
14
+ add_index :event_store_events_in_streams, [:stream, :position], unique: true
15
+ add_index :event_store_events_in_streams, [:created_at]
16
+ add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
26
17
 
27
- if postgres
28
- create_table(:event_store_events, force: false) do |t|
18
+ create_table(:event_store_events, id: :bigserial, force: false) do |t|
29
19
  t.references :event, null: false, type: :uuid
30
20
  t.string :event_type, null: false
31
21
  t.<%= data_type %> :metadata
32
- t.<%= data_type %> :data, null: false
22
+ t.<%= data_type %> :data, null: false
33
23
  t.datetime :created_at, null: false
34
24
  t.datetime :valid_at, null: true
35
25
  end
26
+ add_index :event_store_events, :event_id, unique: true
27
+ add_index :event_store_events, :created_at
28
+ add_index :event_store_events, :valid_at
29
+ add_index :event_store_events, :event_type
36
30
  else
31
+ create_table(:event_store_events_in_streams, force: false) do |t|
32
+ t.string :stream, null: false
33
+ t.integer :position, null: true
34
+ t.references :event, null: false, type: :string, limit: 36
35
+ t.datetime :created_at, null: false, precision: 6
36
+ end
37
+ add_index :event_store_events_in_streams, [:stream, :position], unique: true
38
+ add_index :event_store_events_in_streams, [:created_at]
39
+ add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
40
+
37
41
  create_table(:event_store_events, force: false) do |t|
38
42
  t.references :event, null: false, type: :string, limit: 36
39
43
  t.string :event_type, null: false
@@ -42,10 +46,10 @@ class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
42
46
  t.datetime :created_at, null: false, precision: 6
43
47
  t.datetime :valid_at, null: true, precision: 6
44
48
  end
49
+ add_index :event_store_events, :event_id, unique: true
50
+ add_index :event_store_events, :created_at
51
+ add_index :event_store_events, :valid_at
52
+ add_index :event_store_events, :event_type
45
53
  end
46
- add_index :event_store_events, :event_id, unique: true
47
- add_index :event_store_events, :created_at
48
- add_index :event_store_events, :valid_at
49
- add_index :event_store_events, :event_type
50
54
  end
51
55
  end
@@ -2,41 +2,37 @@
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
4
  class IndexViolationDetector
5
-
6
5
  def initialize(event_store_events, event_store_events_in_streams)
7
- @postgres_pkey_error = "Key (event_id)".freeze
6
+ @postgres_pkey_error = "Key (event_id)".freeze
8
7
  @postgres_index_error = "Key (stream, event_id)".freeze
9
- @mysql5_pkey_error = "for key 'index_#{event_store_events}_on_event_id'".freeze
10
- @mysql8_pkey_error = "for key '#{event_store_events}.index_#{event_store_events}_on_event_id'".freeze
11
- @mysql5_index_error = "for key 'index_#{event_store_events_in_streams}_on_stream_and_event_id'".freeze
12
- @mysql8_index_error = "for key '#{event_store_events_in_streams}.index_#{event_store_events_in_streams}_on_stream_and_event_id'".freeze
13
- @sqlite3_pkey_error = "constraint failed: #{event_store_events}.event_id".freeze
14
- @sqlite3_index_error = "constraint failed: #{event_store_events_in_streams}.stream, #{event_store_events_in_streams}.event_id".freeze
8
+ @mysql5_pkey_error = "for key 'index_#{event_store_events}_on_event_id'".freeze
9
+ @mysql8_pkey_error = "for key '#{event_store_events}.index_#{event_store_events}_on_event_id'".freeze
10
+ @mysql5_index_error = "for key 'index_#{event_store_events_in_streams}_on_stream_and_event_id'".freeze
11
+ @mysql8_index_error =
12
+ "for key '#{event_store_events_in_streams}.index_#{event_store_events_in_streams}_on_stream_and_event_id'"
13
+ .freeze
14
+ @sqlite3_pkey_error = "constraint failed: #{event_store_events}.event_id".freeze
15
+ @sqlite3_index_error =
16
+ "constraint failed: #{event_store_events_in_streams}.stream, #{event_store_events_in_streams}.event_id".freeze
15
17
  end
16
18
 
17
19
  def detect(message)
18
- detect_postgres(message) ||
19
- detect_mysql(message) ||
20
- detect_sqlite(message)
20
+ detect_postgres(message) || detect_mysql(message) || detect_sqlite(message)
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def detect_postgres(message)
26
- message.include?(@postgres_pkey_error) ||
27
- message.include?(@postgres_index_error)
26
+ message.include?(@postgres_pkey_error) || message.include?(@postgres_index_error)
28
27
  end
29
28
 
30
29
  def detect_mysql(message)
31
- message.include?(@mysql5_pkey_error) ||
32
- message.include?(@mysql8_pkey_error) ||
33
- message.include?(@mysql5_index_error) ||
34
- message.include?(@mysql8_index_error)
30
+ message.include?(@mysql5_pkey_error) || message.include?(@mysql8_pkey_error) ||
31
+ message.include?(@mysql5_index_error) || message.include?(@mysql8_index_error)
35
32
  end
36
33
 
37
34
  def detect_sqlite(message)
38
- message.include?(@sqlite3_pkey_error) ||
39
- message.include?(@sqlite3_index_error)
35
+ message.include?(@sqlite3_pkey_error) || message.include?(@sqlite3_index_error)
40
36
  end
41
37
  end
42
38
 
@@ -1,20 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'activerecord-import'
4
-
5
3
  module RailsEventStoreActiveRecord
6
4
  class PgLinearizedEventRepository < EventRepository
7
-
8
5
  def start_transaction(&proc)
9
6
  ActiveRecord::Base.transaction(requires_new: true) do
10
- ActiveRecord::Base
11
- .connection
12
- .execute("SELECT pg_advisory_xact_lock(1845240511599988039) as l")
13
- .each{}
7
+ ActiveRecord::Base.connection.execute("SELECT pg_advisory_xact_lock(1845240511599988039) as l").each {}
14
8
 
15
9
  proc.call
16
10
  end
17
11
  end
18
-
19
12
  end
20
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
- VERSION = "2.1.0"
4
+ VERSION = "2.4.0"
5
5
  end
@@ -3,34 +3,34 @@
3
3
  module RailsEventStoreActiveRecord
4
4
  class WithAbstractBaseClass
5
5
  def initialize(base_klass)
6
- raise ArgumentError.new(
7
- "#{base_klass} must be an abstract class that inherits from ActiveRecord::Base"
8
- ) unless base_klass < ActiveRecord::Base && base_klass.abstract_class?
6
+ unless base_klass < ActiveRecord::Base && base_klass.abstract_class?
7
+ raise ArgumentError.new("#{base_klass} must be an abstract class that inherits from ActiveRecord::Base")
8
+ end
9
9
  @base_klass = base_klass
10
10
  end
11
11
 
12
12
  def call(instance_id: SecureRandom.hex)
13
- [
14
- build_event_klass(instance_id),
15
- build_stream_klass(instance_id),
16
- ]
13
+ [build_event_klass(instance_id), build_stream_klass(instance_id)]
17
14
  end
18
15
 
19
16
  private
17
+
20
18
  def build_event_klass(instance_id)
21
- Object.const_set("Event_#{instance_id}",
19
+ Object.const_set(
20
+ "Event_#{instance_id}",
22
21
  Class.new(@base_klass) do
23
22
  self.primary_key = :id
24
- self.table_name = 'event_store_events'
23
+ self.table_name = "event_store_events"
25
24
  end
26
25
  )
27
26
  end
28
27
 
29
28
  def build_stream_klass(instance_id)
30
- Object.const_set("EventInStream_#{instance_id}",
29
+ Object.const_set(
30
+ "EventInStream_#{instance_id}",
31
31
  Class.new(@base_klass) do
32
32
  self.primary_key = :id
33
- self.table_name = 'event_store_events_in_streams'
33
+ self.table_name = "event_store_events_in_streams"
34
34
  belongs_to :event, primary_key: :event_id, class_name: "Event_#{instance_id}"
35
35
  end
36
36
  )
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_event_store_active_record/generators/migration_generator'
4
- require 'rails_event_store_active_record/event'
5
- require 'rails_event_store_active_record/with_default_models'
6
- require 'rails_event_store_active_record/with_abstract_base_class'
7
- require 'rails_event_store_active_record/event_repository'
8
- require 'rails_event_store_active_record/batch_enumerator'
9
- require 'rails_event_store_active_record/event_repository_reader'
10
- require 'rails_event_store_active_record/index_violation_detector'
11
- require 'rails_event_store_active_record/pg_linearized_event_repository'
12
- require 'rails_event_store_active_record/version'
3
+ require_relative "rails_event_store_active_record/generators/migration_generator"
4
+ require_relative "rails_event_store_active_record/event"
5
+ require_relative "rails_event_store_active_record/with_default_models"
6
+ require_relative "rails_event_store_active_record/with_abstract_base_class"
7
+ require_relative "rails_event_store_active_record/event_repository"
8
+ require_relative "rails_event_store_active_record/batch_enumerator"
9
+ require_relative "rails_event_store_active_record/event_repository_reader"
10
+ require_relative "rails_event_store_active_record/index_violation_detector"
11
+ require_relative "rails_event_store_active_record/pg_linearized_event_repository"
12
+ require_relative "rails_event_store_active_record/version"
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: 2.1.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkency
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-07 00:00:00.000000000 Z
11
+ date: 2022-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_event_store
@@ -16,42 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.0
19
+ version: 2.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 2.1.0
26
+ version: 2.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.0'
33
+ version: '6.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5.0'
41
- - !ruby/object:Gem::Dependency
42
- name: activerecord-import
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 1.0.2
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: 1.0.2
40
+ version: '6.0'
55
41
  description: |
56
42
  Persistent event repository implementation for RubyEventStore based on ActiveRecord. Ships with database schema
57
43
  and migrations suitable for PostgreSQL, MySQL ans SQLite database engines.
@@ -85,6 +71,7 @@ metadata:
85
71
  changelog_uri: https://github.com/RailsEventStore/rails_event_store/releases
86
72
  source_code_uri: https://github.com/RailsEventStore/rails_event_store
87
73
  bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
74
+ rubygems_mfa_required: 'true'
88
75
  post_install_message:
89
76
  rdoc_options: []
90
77
  require_paths:
@@ -93,14 +80,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
80
  requirements:
94
81
  - - ">="
95
82
  - !ruby/object:Gem::Version
96
- version: '2.5'
83
+ version: '2.7'
97
84
  required_rubygems_version: !ruby/object:Gem::Requirement
98
85
  requirements:
99
86
  - - ">="
100
87
  - !ruby/object:Gem::Version
101
88
  version: '0'
102
89
  requirements: []
103
- rubygems_version: 3.1.4
90
+ rubygems_version: 3.3.7
104
91
  signing_key:
105
92
  specification_version: 4
106
93
  summary: Persistent event repository implementation for RubyEventStore based on ActiveRecord