rails_event_store_active_record 2.1.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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