rails_event_store_active_record 2.6.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rails_event_store_active_record.rb +2 -11
- metadata +7 -34
- data/README.md +0 -7
- data/lib/rails_event_store_active_record/batch_enumerator.rb +0 -36
- data/lib/rails_event_store_active_record/event.rb +0 -18
- data/lib/rails_event_store_active_record/event_repository.rb +0 -162
- data/lib/rails_event_store_active_record/event_repository_reader.rb +0 -199
- data/lib/rails_event_store_active_record/generators/migration_generator.rb +0 -50
- data/lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb +0 -55
- data/lib/rails_event_store_active_record/index_violation_detector.rb +0 -40
- data/lib/rails_event_store_active_record/pg_linearized_event_repository.rb +0 -13
- data/lib/rails_event_store_active_record/version.rb +0 -5
- data/lib/rails_event_store_active_record/with_abstract_base_class.rb +0 -39
- data/lib/rails_event_store_active_record/with_default_models.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd05a165bf6e5f4b077c79cbb48f24533daf854acd024a6bb5bffec8c1698856
|
4
|
+
data.tar.gz: b0acdb12c48a3dc1c04952cf076bb76846bca9c889dd483098d8982cbdc347f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1e4460ec40756d126b685d6809f12538d5dfee910ee7fbb2f755276607d536cb4d1d58988cbe75903adebe985c258a73d3bce3dc9a68091313a898addb08570
|
7
|
+
data.tar.gz: b464d389f5b7af91647da038c2e4916e0c3c78345d4bd7dcac4ff61299733cc7418ae5394363bcadfbc16f5a6504fd09250b818253311767bad7071b3de74328
|
@@ -1,12 +1,3 @@
|
|
1
|
-
|
1
|
+
require "ruby_event_store/active_record"
|
2
2
|
|
3
|
-
|
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"
|
3
|
+
RailsEventStoreActiveRecord = RubyEventStore::ActiveRecord
|
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_event_store_active_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: ruby_event_store
|
14
|
+
name: ruby_event_store-active_record
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.8.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.
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: activerecord
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '6.0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '6.0'
|
26
|
+
version: 2.8.0
|
41
27
|
description: |
|
42
28
|
Persistent event repository implementation for RubyEventStore based on ActiveRecord. Ships with database schema
|
43
29
|
and migrations suitable for PostgreSQL, MySQL ans SQLite database engines.
|
@@ -47,22 +33,9 @@ description: |
|
|
47
33
|
email: dev@arkency.com
|
48
34
|
executables: []
|
49
35
|
extensions: []
|
50
|
-
extra_rdoc_files:
|
51
|
-
- README.md
|
36
|
+
extra_rdoc_files: []
|
52
37
|
files:
|
53
|
-
- README.md
|
54
38
|
- lib/rails_event_store_active_record.rb
|
55
|
-
- lib/rails_event_store_active_record/batch_enumerator.rb
|
56
|
-
- lib/rails_event_store_active_record/event.rb
|
57
|
-
- lib/rails_event_store_active_record/event_repository.rb
|
58
|
-
- lib/rails_event_store_active_record/event_repository_reader.rb
|
59
|
-
- lib/rails_event_store_active_record/generators/migration_generator.rb
|
60
|
-
- lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb
|
61
|
-
- lib/rails_event_store_active_record/index_violation_detector.rb
|
62
|
-
- lib/rails_event_store_active_record/pg_linearized_event_repository.rb
|
63
|
-
- lib/rails_event_store_active_record/version.rb
|
64
|
-
- lib/rails_event_store_active_record/with_abstract_base_class.rb
|
65
|
-
- lib/rails_event_store_active_record/with_default_models.rb
|
66
39
|
homepage: https://railseventstore.org
|
67
40
|
licenses:
|
68
41
|
- MIT
|
@@ -87,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
60
|
- !ruby/object:Gem::Version
|
88
61
|
version: '0'
|
89
62
|
requirements: []
|
90
|
-
rubygems_version: 3.3.
|
63
|
+
rubygems_version: 3.3.7
|
91
64
|
signing_key:
|
92
65
|
specification_version: 4
|
93
66
|
summary: Persistent event repository implementation for RubyEventStore based on ActiveRecord
|
data/README.md
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
# RailsEventStoreActiveRecord
|
2
|
-
|
3
|
-
Persistent event repository implementation for RubyEventStore based on ActiveRecord. Ships with database schema and migrations suitable for PostgreSQL, MySQL ans SQLite database engines.
|
4
|
-
|
5
|
-
Includes repository implementation with linearized writes to achieve log-like properties of streams on top of SQL database engine.
|
6
|
-
|
7
|
-
Find out more at [https://railseventstore.org](https://railseventstore.org/)
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStoreActiveRecord
|
4
|
-
class BatchEnumerator
|
5
|
-
def initialize(batch_size, total_limit, reader)
|
6
|
-
@batch_size = batch_size
|
7
|
-
@total_limit = total_limit
|
8
|
-
@reader = reader
|
9
|
-
end
|
10
|
-
|
11
|
-
def each
|
12
|
-
return to_enum unless block_given?
|
13
|
-
offset_id = nil
|
14
|
-
|
15
|
-
0.step(total_limit - 1, batch_size) do |batch_offset|
|
16
|
-
batch_limit = [batch_size, total_limit - batch_offset].min
|
17
|
-
results, offset_id = reader.call(offset_id, batch_limit)
|
18
|
-
|
19
|
-
break if results.empty?
|
20
|
-
yield results
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def first
|
25
|
-
each.first
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_a
|
29
|
-
each.to_a
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
attr_reader :batch_size, :total_limit, :reader
|
35
|
-
end
|
36
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_record"
|
4
|
-
|
5
|
-
module RailsEventStoreActiveRecord
|
6
|
-
class Event < ::ActiveRecord::Base
|
7
|
-
self.primary_key = :id
|
8
|
-
self.table_name = "event_store_events"
|
9
|
-
end
|
10
|
-
private_constant :Event
|
11
|
-
|
12
|
-
class EventInStream < ::ActiveRecord::Base
|
13
|
-
self.primary_key = :id
|
14
|
-
self.table_name = "event_store_events_in_streams"
|
15
|
-
belongs_to :event, primary_key: :event_id
|
16
|
-
end
|
17
|
-
private_constant :EventInStream
|
18
|
-
end
|
@@ -1,162 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_support/core_ext/array"
|
4
|
-
|
5
|
-
module RailsEventStoreActiveRecord
|
6
|
-
class EventRepository
|
7
|
-
POSITION_SHIFT = 1
|
8
|
-
|
9
|
-
def initialize(model_factory: WithDefaultModels.new, serializer:)
|
10
|
-
@serializer = serializer
|
11
|
-
|
12
|
-
@event_klass, @stream_klass = model_factory.call
|
13
|
-
@repo_reader = EventRepositoryReader.new(@event_klass, @stream_klass, serializer)
|
14
|
-
@index_violation_detector = IndexViolationDetector.new(@event_klass.table_name, @stream_klass.table_name)
|
15
|
-
end
|
16
|
-
|
17
|
-
def append_to_stream(records, stream, expected_version)
|
18
|
-
return if records.empty?
|
19
|
-
|
20
|
-
hashes = []
|
21
|
-
event_ids = []
|
22
|
-
records.each do |record|
|
23
|
-
hashes << insert_hash(record, record.serialize(serializer))
|
24
|
-
event_ids << record.event_id
|
25
|
-
end
|
26
|
-
add_to_stream(event_ids, stream, expected_version) { @event_klass.insert_all!(hashes) }
|
27
|
-
end
|
28
|
-
|
29
|
-
def link_to_stream(event_ids, stream, expected_version)
|
30
|
-
return if event_ids.empty?
|
31
|
-
|
32
|
-
(event_ids - @event_klass.where(event_id: event_ids).pluck(:event_id)).each do |id|
|
33
|
-
raise RubyEventStore::EventNotFound.new(id)
|
34
|
-
end
|
35
|
-
add_to_stream(event_ids, stream, expected_version)
|
36
|
-
end
|
37
|
-
|
38
|
-
def delete_stream(stream)
|
39
|
-
@stream_klass.where(stream: stream.name).delete_all
|
40
|
-
end
|
41
|
-
|
42
|
-
def has_event?(event_id)
|
43
|
-
@repo_reader.has_event?(event_id)
|
44
|
-
end
|
45
|
-
|
46
|
-
def last_stream_event(stream)
|
47
|
-
@repo_reader.last_stream_event(stream)
|
48
|
-
end
|
49
|
-
|
50
|
-
def read(specification)
|
51
|
-
@repo_reader.read(specification)
|
52
|
-
end
|
53
|
-
|
54
|
-
def count(specification)
|
55
|
-
@repo_reader.count(specification)
|
56
|
-
end
|
57
|
-
|
58
|
-
def update_messages(records)
|
59
|
-
hashes = records.map { |record| upsert_hash(record, record.serialize(serializer)) }
|
60
|
-
for_update = records.map(&:event_id)
|
61
|
-
start_transaction do
|
62
|
-
existing =
|
63
|
-
@event_klass
|
64
|
-
.where(event_id: for_update)
|
65
|
-
.pluck(:event_id, :id, :created_at)
|
66
|
-
.reduce({}) { |acc, (event_id, id, created_at)| acc.merge(event_id => [id, created_at]) }
|
67
|
-
(for_update - existing.keys).each { |id| raise RubyEventStore::EventNotFound.new(id) }
|
68
|
-
hashes.each do |h|
|
69
|
-
h[:id] = existing.fetch(h.fetch(:event_id)).at(0)
|
70
|
-
h[:created_at] = existing.fetch(h.fetch(:event_id)).at(1)
|
71
|
-
end
|
72
|
-
@event_klass.upsert_all(hashes)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def streams_of(event_id)
|
77
|
-
@repo_reader.streams_of(event_id)
|
78
|
-
end
|
79
|
-
|
80
|
-
def position_in_stream(event_id, stream)
|
81
|
-
@repo_reader.position_in_stream(event_id, stream)
|
82
|
-
end
|
83
|
-
|
84
|
-
def global_position(event_id)
|
85
|
-
@repo_reader.global_position(event_id)
|
86
|
-
end
|
87
|
-
|
88
|
-
def event_in_stream?(event_id, stream)
|
89
|
-
@repo_reader.event_in_stream?(event_id, stream)
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
attr_reader :serializer
|
95
|
-
|
96
|
-
def add_to_stream(event_ids, stream, expected_version)
|
97
|
-
last_stream_version = ->(stream_) do
|
98
|
-
@stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position)
|
99
|
-
end
|
100
|
-
resolved_version = expected_version.resolve_for(stream, last_stream_version)
|
101
|
-
|
102
|
-
start_transaction do
|
103
|
-
yield if block_given?
|
104
|
-
in_stream =
|
105
|
-
event_ids.map.with_index do |event_id, index|
|
106
|
-
{
|
107
|
-
stream: stream.name,
|
108
|
-
position: compute_position(resolved_version, index),
|
109
|
-
event_id: event_id,
|
110
|
-
created_at: Time.now.utc
|
111
|
-
}
|
112
|
-
end
|
113
|
-
@stream_klass.insert_all!(in_stream) unless stream.global?
|
114
|
-
end
|
115
|
-
self
|
116
|
-
rescue ActiveRecord::RecordNotUnique => e
|
117
|
-
raise_error(e)
|
118
|
-
end
|
119
|
-
|
120
|
-
def raise_error(e)
|
121
|
-
raise RubyEventStore::EventDuplicatedInStream if detect_index_violated(e.message)
|
122
|
-
raise RubyEventStore::WrongExpectedEventVersion
|
123
|
-
end
|
124
|
-
|
125
|
-
def compute_position(resolved_version, index)
|
126
|
-
resolved_version + index + POSITION_SHIFT unless resolved_version.nil?
|
127
|
-
end
|
128
|
-
|
129
|
-
def detect_index_violated(message)
|
130
|
-
@index_violation_detector.detect(message)
|
131
|
-
end
|
132
|
-
|
133
|
-
def insert_hash(record, serialized_record)
|
134
|
-
{
|
135
|
-
event_id: serialized_record.event_id,
|
136
|
-
data: serialized_record.data,
|
137
|
-
metadata: serialized_record.metadata,
|
138
|
-
event_type: serialized_record.event_type,
|
139
|
-
created_at: record.timestamp,
|
140
|
-
valid_at: optimize_timestamp(record.valid_at, record.timestamp)
|
141
|
-
}
|
142
|
-
end
|
143
|
-
|
144
|
-
def upsert_hash(record, serialized_record)
|
145
|
-
{
|
146
|
-
event_id: serialized_record.event_id,
|
147
|
-
data: serialized_record.data,
|
148
|
-
metadata: serialized_record.metadata,
|
149
|
-
event_type: serialized_record.event_type,
|
150
|
-
valid_at: optimize_timestamp(record.valid_at, record.timestamp)
|
151
|
-
}
|
152
|
-
end
|
153
|
-
|
154
|
-
def optimize_timestamp(valid_at, created_at)
|
155
|
-
valid_at unless valid_at.eql?(created_at)
|
156
|
-
end
|
157
|
-
|
158
|
-
def start_transaction(&block)
|
159
|
-
@event_klass.transaction(requires_new: true, &block)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
@@ -1,199 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStoreActiveRecord
|
4
|
-
class EventRepositoryReader
|
5
|
-
def initialize(event_klass, stream_klass, serializer)
|
6
|
-
@event_klass = event_klass
|
7
|
-
@stream_klass = stream_klass
|
8
|
-
@serializer = serializer
|
9
|
-
end
|
10
|
-
|
11
|
-
def has_event?(event_id)
|
12
|
-
@event_klass.exists?(event_id: event_id)
|
13
|
-
end
|
14
|
-
|
15
|
-
def last_stream_event(stream)
|
16
|
-
record_ = @stream_klass.where(stream: stream.name).order("position DESC, id DESC").first
|
17
|
-
record(record_) if record_
|
18
|
-
end
|
19
|
-
|
20
|
-
def read(spec)
|
21
|
-
stream = read_scope(spec)
|
22
|
-
if spec.batched?
|
23
|
-
spec.time_sort_by ? offset_limit_batch_reader(spec, stream) : monotonic_id_batch_reader(spec, stream)
|
24
|
-
elsif spec.first?
|
25
|
-
record_ = stream.first
|
26
|
-
record(record_) if record_
|
27
|
-
elsif spec.last?
|
28
|
-
record_ = stream.last
|
29
|
-
record(record_) if record_
|
30
|
-
else
|
31
|
-
stream.map(&method(:record)).each
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def count(spec)
|
36
|
-
read_scope(spec).count
|
37
|
-
end
|
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
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
attr_reader :serializer
|
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
|
-
|
82
|
-
def read_scope(spec)
|
83
|
-
if spec.stream.global?
|
84
|
-
stream = @event_klass
|
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?
|
87
|
-
stream = ordered(stream, spec)
|
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
|
92
|
-
stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
|
93
|
-
stream = stream.where(newer_than_condition(spec)) if spec.newer_than
|
94
|
-
stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
|
95
|
-
stream.order(id: order(spec))
|
96
|
-
else
|
97
|
-
stream = @stream_klass.preload(:event).where(stream: spec.stream.name)
|
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?
|
100
|
-
stream = ordered(stream.joins(:event), spec)
|
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
|
106
|
-
stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
|
107
|
-
stream = stream.where(newer_than_condition(spec)) if spec.newer_than
|
108
|
-
stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
|
109
|
-
stream
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def ordered(stream, spec)
|
114
|
-
case spec.time_sort_by
|
115
|
-
when :as_at
|
116
|
-
stream.order("#{@event_klass.table_name}.created_at #{order(spec)}")
|
117
|
-
when :as_of
|
118
|
-
stream.order("#{@event_klass.table_name}.valid_at #{order(spec)}")
|
119
|
-
else
|
120
|
-
stream
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def start_offset_condition(specification, record_id, search_in)
|
125
|
-
condition = "#{search_in}.id #{specification.forward? ? ">" : "<"} ?"
|
126
|
-
[condition, record_id]
|
127
|
-
end
|
128
|
-
|
129
|
-
def stop_offset_condition(specification, record_id, search_in)
|
130
|
-
condition = "#{search_in}.id #{specification.forward? ? "<" : ">"} ?"
|
131
|
-
[condition, record_id]
|
132
|
-
end
|
133
|
-
|
134
|
-
def start_condition(specification)
|
135
|
-
start_offset_condition(
|
136
|
-
specification,
|
137
|
-
@stream_klass.find_by!(event_id: specification.start, stream: specification.stream.name),
|
138
|
-
@stream_klass.table_name
|
139
|
-
)
|
140
|
-
end
|
141
|
-
|
142
|
-
def stop_condition(specification)
|
143
|
-
stop_offset_condition(
|
144
|
-
specification,
|
145
|
-
@stream_klass.find_by!(event_id: specification.stop, stream: specification.stream.name),
|
146
|
-
@stream_klass.table_name
|
147
|
-
)
|
148
|
-
end
|
149
|
-
|
150
|
-
def start_condition_in_global_stream(specification)
|
151
|
-
start_offset_condition(
|
152
|
-
specification,
|
153
|
-
@event_klass.find_by!(event_id: specification.start),
|
154
|
-
@event_klass.table_name
|
155
|
-
)
|
156
|
-
end
|
157
|
-
|
158
|
-
def stop_condition_in_global_stream(specification)
|
159
|
-
stop_offset_condition(specification, @event_klass.find_by!(event_id: specification.stop), @event_klass.table_name)
|
160
|
-
end
|
161
|
-
|
162
|
-
def older_than_condition(specification)
|
163
|
-
["#{@event_klass.table_name}.created_at < ?", specification.older_than]
|
164
|
-
end
|
165
|
-
|
166
|
-
def older_than_or_equal_condition(specification)
|
167
|
-
["#{@event_klass.table_name}.created_at <= ?", specification.older_than_or_equal]
|
168
|
-
end
|
169
|
-
|
170
|
-
def newer_than_condition(specification)
|
171
|
-
["#{@event_klass.table_name}.created_at > ?", specification.newer_than]
|
172
|
-
end
|
173
|
-
|
174
|
-
def newer_than_or_equal_condition(specification)
|
175
|
-
["#{@event_klass.table_name}.created_at >= ?", specification.newer_than_or_equal]
|
176
|
-
end
|
177
|
-
|
178
|
-
def order(spec)
|
179
|
-
spec.forward? ? "ASC" : "DESC"
|
180
|
-
end
|
181
|
-
|
182
|
-
def record(record)
|
183
|
-
record = record.event if @stream_klass === record
|
184
|
-
|
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)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
private_constant(:EventRepositoryReader)
|
199
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
begin
|
4
|
-
require "rails/generators"
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
|
-
module RailsEventStoreActiveRecord
|
9
|
-
class MigrationGenerator < Rails::Generators::Base
|
10
|
-
class Error < Thor::Error
|
11
|
-
end
|
12
|
-
|
13
|
-
DATA_TYPES = %w[binary json jsonb].freeze
|
14
|
-
|
15
|
-
source_root File.expand_path(File.join(File.dirname(__FILE__), "../generators/templates"))
|
16
|
-
class_option(
|
17
|
-
:data_type,
|
18
|
-
type: :string,
|
19
|
-
default: "binary",
|
20
|
-
desc:
|
21
|
-
"Configure the data type for `data` and `meta data` fields in Postgres migration (options: #{DATA_TYPES.join("/")})"
|
22
|
-
)
|
23
|
-
|
24
|
-
def initialize(*args)
|
25
|
-
super
|
26
|
-
|
27
|
-
if DATA_TYPES.exclude?(options.fetch(:data_type))
|
28
|
-
raise Error, "Invalid value for --data-type option. Supported for options are: #{DATA_TYPES.join(", ")}."
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def create_migration
|
33
|
-
template "create_event_store_events_template.rb", "db/migrate/#{timestamp}_create_event_store_events.rb"
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def data_type
|
39
|
-
options.fetch("data_type")
|
40
|
-
end
|
41
|
-
|
42
|
-
def migration_version
|
43
|
-
"[4.2]"
|
44
|
-
end
|
45
|
-
|
46
|
-
def timestamp
|
47
|
-
Time.now.strftime("%Y%m%d%H%M%S")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end if defined?(Rails::Generators::Base)
|
data/lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
|
4
|
-
def change
|
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
|
12
|
-
t.datetime :created_at, null: false
|
13
|
-
end
|
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
|
17
|
-
|
18
|
-
create_table(:event_store_events, id: :bigserial, force: false) do |t|
|
19
|
-
t.references :event, null: false, type: :uuid
|
20
|
-
t.string :event_type, null: false
|
21
|
-
t.<%= data_type %> :metadata
|
22
|
-
t.<%= data_type %> :data, null: false
|
23
|
-
t.datetime :created_at, null: false
|
24
|
-
t.datetime :valid_at, null: true
|
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
|
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
|
-
|
41
|
-
create_table(:event_store_events, force: false) do |t|
|
42
|
-
t.references :event, null: false, type: :string, limit: 36
|
43
|
-
t.string :event_type, null: false
|
44
|
-
t.binary :metadata
|
45
|
-
t.binary :data, null: false
|
46
|
-
t.datetime :created_at, null: false, precision: 6
|
47
|
-
t.datetime :valid_at, null: true, precision: 6
|
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
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStoreActiveRecord
|
4
|
-
class IndexViolationDetector
|
5
|
-
def initialize(event_store_events, event_store_events_in_streams)
|
6
|
-
@postgres_pkey_error = "Key (event_id)".freeze
|
7
|
-
@postgres_index_error = "Key (stream, 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
|
17
|
-
end
|
18
|
-
|
19
|
-
def detect(message)
|
20
|
-
detect_postgres(message) || detect_mysql(message) || detect_sqlite(message)
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def detect_postgres(message)
|
26
|
-
message.include?(@postgres_pkey_error) || message.include?(@postgres_index_error)
|
27
|
-
end
|
28
|
-
|
29
|
-
def detect_mysql(message)
|
30
|
-
message.include?(@mysql5_pkey_error) || message.include?(@mysql8_pkey_error) ||
|
31
|
-
message.include?(@mysql5_index_error) || message.include?(@mysql8_index_error)
|
32
|
-
end
|
33
|
-
|
34
|
-
def detect_sqlite(message)
|
35
|
-
message.include?(@sqlite3_pkey_error) || message.include?(@sqlite3_index_error)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private_constant(:IndexViolationDetector)
|
40
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStoreActiveRecord
|
4
|
-
class PgLinearizedEventRepository < EventRepository
|
5
|
-
def start_transaction(&proc)
|
6
|
-
ActiveRecord::Base.transaction(requires_new: true) do
|
7
|
-
ActiveRecord::Base.connection.execute("SELECT pg_advisory_xact_lock(1845240511599988039) as l").each {}
|
8
|
-
|
9
|
-
proc.call
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStoreActiveRecord
|
4
|
-
class WithAbstractBaseClass
|
5
|
-
def initialize(base_klass)
|
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
|
-
@base_klass = base_klass
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(instance_id: SecureRandom.hex)
|
13
|
-
[build_event_klass(instance_id), build_stream_klass(instance_id)]
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def build_event_klass(instance_id)
|
19
|
-
Object.const_set(
|
20
|
-
"Event_#{instance_id}",
|
21
|
-
Class.new(@base_klass) do
|
22
|
-
self.primary_key = :id
|
23
|
-
self.table_name = "event_store_events"
|
24
|
-
end
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
def build_stream_klass(instance_id)
|
29
|
-
Object.const_set(
|
30
|
-
"EventInStream_#{instance_id}",
|
31
|
-
Class.new(@base_klass) do
|
32
|
-
self.primary_key = :id
|
33
|
-
self.table_name = "event_store_events_in_streams"
|
34
|
-
belongs_to :event, primary_key: :event_id, class_name: "Event_#{instance_id}"
|
35
|
-
end
|
36
|
-
)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|