ruby_event_store-rom 1.3.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/ruby_event_store/rom/changesets/create_events.rb +10 -18
- data/lib/ruby_event_store/rom/changesets/create_stream_entries.rb +3 -12
- data/lib/ruby_event_store/rom/changesets/update_events.rb +33 -19
- data/lib/ruby_event_store/rom/event_repository.rb +65 -61
- data/lib/ruby_event_store/rom/index_violation_detector.rb +25 -0
- data/lib/ruby_event_store/rom/mappers/event_to_serialized_record.rb +10 -6
- data/lib/ruby_event_store/rom/mappers/stream_entry_to_serialized_record.rb +11 -6
- data/lib/ruby_event_store/rom/rake_task.rb +5 -0
- data/lib/ruby_event_store/rom/relations/events.rb +78 -0
- data/lib/ruby_event_store/rom/relations/stream_entries.rb +83 -0
- data/lib/ruby_event_store/rom/repositories/events.rb +55 -30
- data/lib/ruby_event_store/rom/repositories/stream_entries.rb +15 -16
- data/lib/ruby_event_store/rom/tasks/migration_tasks.rake +36 -0
- data/lib/ruby_event_store/rom/types.rb +16 -14
- data/lib/ruby_event_store/rom/unit_of_work.rb +28 -13
- data/lib/ruby_event_store/rom/version.rb +1 -1
- data/lib/ruby_event_store/rom.rb +28 -103
- data/lib/ruby_event_store-rom.rb +1 -1
- metadata +31 -49
- data/.rubocop.yml +0 -1
- data/.rubocop_todo.yml +0 -84
- data/CHANGELOG.md +0 -9
- data/Gemfile +0 -12
- data/Makefile +0 -57
- data/Rakefile +0 -20
- data/db/migrate/20180327044629_create_ruby_event_store_tables.rb +0 -54
- data/db/migrate/20181026152045_index_by_event_type.rb +0 -9
- data/lib/ruby_event_store/rom/adapters/memory/changesets/create_events.rb +0 -19
- data/lib/ruby_event_store/rom/adapters/memory/changesets/create_stream_entries.rb +0 -19
- data/lib/ruby_event_store/rom/adapters/memory/changesets/update_events.rb +0 -18
- data/lib/ruby_event_store/rom/adapters/memory/relations/events.rb +0 -56
- data/lib/ruby_event_store/rom/adapters/memory/relations/stream_entries.rb +0 -114
- data/lib/ruby_event_store/rom/adapters/memory/unit_of_work.rb +0 -36
- data/lib/ruby_event_store/rom/adapters/sql/changesets/create_events.rb +0 -15
- data/lib/ruby_event_store/rom/adapters/sql/changesets/update_events.rb +0 -41
- data/lib/ruby_event_store/rom/adapters/sql/index_violation_detector.rb +0 -31
- data/lib/ruby_event_store/rom/adapters/sql/rake_task.rb +0 -5
- data/lib/ruby_event_store/rom/adapters/sql/relations/events.rb +0 -27
- data/lib/ruby_event_store/rom/adapters/sql/relations/stream_entries.rb +0 -72
- data/lib/ruby_event_store/rom/adapters/sql/tasks/migration_tasks.rake +0 -36
- data/lib/ruby_event_store/rom/memory.rb +0 -82
- data/lib/ruby_event_store/rom/sql.rb +0 -169
- data/lib/ruby_event_store/rom/tuple_uniqueness_error.rb +0 -21
- data/lib/ruby_event_store/spec/rom/event_repository_lint.rb +0 -176
- data/lib/ruby_event_store/spec/rom/relations/events_lint.rb +0 -75
- data/lib/ruby_event_store/spec/rom/relations/stream_entries_lint.rb +0 -198
- data/lib/ruby_event_store/spec/rom/spec_helper_lint.rb +0 -15
- data/lib/ruby_event_store/spec/rom/unit_of_work_lint.rb +0 -37
- data/ruby_event_store-rom.gemspec +0 -37
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RubyEventStore
|
4
|
-
module ROM
|
5
|
-
module SQL
|
6
|
-
module Relations
|
7
|
-
class StreamEntries < ::ROM::Relation[:sql]
|
8
|
-
schema(:event_store_events_in_streams, as: :stream_entries, infer: true) do
|
9
|
-
attribute :created_at, RubyEventStore::ROM::Types::DateTime
|
10
|
-
|
11
|
-
associations do
|
12
|
-
belongs_to :events, as: :event, foreign_key: :event_id
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
alias take limit
|
17
|
-
|
18
|
-
SERIALIZED_GLOBAL_STREAM_NAME = 'all'.freeze
|
19
|
-
|
20
|
-
def create_changeset(tuples)
|
21
|
-
changeset(ROM::Changesets::CreateStreamEntries, tuples)
|
22
|
-
end
|
23
|
-
|
24
|
-
def by_stream(stream)
|
25
|
-
where(stream: normalize_stream_name(stream))
|
26
|
-
end
|
27
|
-
|
28
|
-
def by_event_id(event_id)
|
29
|
-
where(event_id: event_id)
|
30
|
-
end
|
31
|
-
|
32
|
-
def by_event_type(types)
|
33
|
-
join(:events).where(event_type: types)
|
34
|
-
end
|
35
|
-
|
36
|
-
def by_stream_and_event_id(stream, event_id)
|
37
|
-
where(stream: normalize_stream_name(stream), event_id: event_id).one!
|
38
|
-
end
|
39
|
-
|
40
|
-
def max_position(stream)
|
41
|
-
by_stream(stream).select(:position).order(Sequel.desc(:position)).first
|
42
|
-
end
|
43
|
-
|
44
|
-
DIRECTION_MAP = {
|
45
|
-
forward: %i[asc > <],
|
46
|
-
backward: %i[desc < >]
|
47
|
-
}.freeze
|
48
|
-
|
49
|
-
def ordered(direction, stream, offset_entry_id = nil, stop_entry_id = nil)
|
50
|
-
order, operator_offset, operator_stop = DIRECTION_MAP[direction]
|
51
|
-
|
52
|
-
raise ArgumentError, 'Direction must be :forward or :backward' if order.nil?
|
53
|
-
|
54
|
-
order_columns = %i[position id]
|
55
|
-
order_columns.delete(:position) if stream.global?
|
56
|
-
|
57
|
-
query = by_stream(stream)
|
58
|
-
query = query.where { id.public_send(operator_offset, offset_entry_id) } if offset_entry_id
|
59
|
-
query = query.where { id.public_send(operator_stop, stop_entry_id) } if stop_entry_id
|
60
|
-
query.order { |r| order_columns.map { |c| r[:stream_entries][c].public_send(order) } }
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def normalize_stream_name(stream)
|
66
|
-
stream.global? ? SERIALIZED_GLOBAL_STREAM_NAME : stream.name
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby_event_store/rom/sql'
|
4
|
-
|
5
|
-
MIGRATIONS_PATH = 'db/migrate'.freeze
|
6
|
-
|
7
|
-
desc 'Setup ROM EventRespository environment'
|
8
|
-
task 'db:setup' do
|
9
|
-
Dir.chdir(Dir.pwd)
|
10
|
-
ROM::SQL::RakeSupport.env = ::RubyEventStore::ROM.configure(:sql).rom_container
|
11
|
-
end
|
12
|
-
|
13
|
-
desc 'Copy RubyEventStore SQL migrations to db/migrate'
|
14
|
-
task 'db:migrations:copy' => 'db:setup' do
|
15
|
-
# Optional data type for `data` and `metadata`
|
16
|
-
data_type = ENV['DATA_TYPE']
|
17
|
-
|
18
|
-
Dir[File.join(File.dirname(__FILE__), '../../../../../../', MIGRATIONS_PATH, '/*.rb')].each do |input|
|
19
|
-
contents = File.read(input)
|
20
|
-
name = File.basename(input, '.*').sub(/\d+_/, '')
|
21
|
-
|
22
|
-
re_data_type = /(ENV.+?DATA_TYPE.+?\|\|=\s*)['"](jsonb?|text)['"]/
|
23
|
-
|
24
|
-
if data_type && contents =~ re_data_type
|
25
|
-
# Search/replace this string: ENV['DATA_TYPE'] ||= 'text'
|
26
|
-
contents = contents.sub(re_data_type, format('\1"%<data_type>s"', data_type: data_type))
|
27
|
-
name += "_with_#{data_type}"
|
28
|
-
end
|
29
|
-
|
30
|
-
output = ROM::SQL::RakeSupport.create_migration(name, path: File.join(Dir.pwd, MIGRATIONS_PATH))
|
31
|
-
|
32
|
-
File.write output, contents
|
33
|
-
|
34
|
-
puts "<= migration file created #{output}"
|
35
|
-
end
|
36
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby_event_store/rom'
|
4
|
-
require 'rom/memory'
|
5
|
-
require_relative 'adapters/memory/unit_of_work'
|
6
|
-
require_relative 'adapters/memory/relations/events'
|
7
|
-
require_relative 'adapters/memory/relations/stream_entries'
|
8
|
-
require_relative 'adapters/memory/changesets/create_events'
|
9
|
-
require_relative 'adapters/memory/changesets/update_events'
|
10
|
-
require_relative 'adapters/memory/changesets/create_stream_entries'
|
11
|
-
|
12
|
-
module RubyEventStore
|
13
|
-
module ROM
|
14
|
-
module Memory
|
15
|
-
class << self
|
16
|
-
def fetch_next_id
|
17
|
-
@last_id ||= 0
|
18
|
-
@mutex ||= Mutex.new
|
19
|
-
@mutex.synchronize { @last_id += 1 }
|
20
|
-
end
|
21
|
-
|
22
|
-
def setup(config)
|
23
|
-
config.register_relation Relations::Events
|
24
|
-
config.register_relation Relations::StreamEntries
|
25
|
-
end
|
26
|
-
|
27
|
-
def configure(env)
|
28
|
-
env.register_unit_of_work_options(class: UnitOfWork)
|
29
|
-
|
30
|
-
env.register_error_handler :unique_violation, lambda { |ex|
|
31
|
-
case ex
|
32
|
-
when TupleUniquenessError
|
33
|
-
raise EventDuplicatedInStream if ex.message =~ /event_id/
|
34
|
-
|
35
|
-
raise WrongExpectedEventVersion
|
36
|
-
end
|
37
|
-
}
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class SpecHelper
|
42
|
-
attr_reader :env
|
43
|
-
attr_reader :connection_pool_size, :close_pool_connection
|
44
|
-
|
45
|
-
def initialize
|
46
|
-
@connection_pool_size = 5
|
47
|
-
@env = ROM.setup(:memory)
|
48
|
-
end
|
49
|
-
|
50
|
-
def run_lifecycle
|
51
|
-
yield
|
52
|
-
ensure
|
53
|
-
drop_gateway_schema
|
54
|
-
end
|
55
|
-
|
56
|
-
def gateway
|
57
|
-
env.rom_container.gateways.fetch(:default)
|
58
|
-
end
|
59
|
-
|
60
|
-
def drop_gateway_schema
|
61
|
-
gateway.connection.data.values.each { |v| v.data.clear }
|
62
|
-
end
|
63
|
-
|
64
|
-
def close_gateway_connection
|
65
|
-
gateway.disconnect
|
66
|
-
end
|
67
|
-
|
68
|
-
def gateway_type?(name)
|
69
|
-
name == :memory
|
70
|
-
end
|
71
|
-
|
72
|
-
def has_connection_pooling?
|
73
|
-
true
|
74
|
-
end
|
75
|
-
|
76
|
-
def supports_upsert?
|
77
|
-
true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby_event_store/rom'
|
4
|
-
require 'rom/sql'
|
5
|
-
require_relative 'adapters/sql/index_violation_detector'
|
6
|
-
require_relative 'adapters/sql/relations/events'
|
7
|
-
require_relative 'adapters/sql/relations/stream_entries'
|
8
|
-
require_relative 'adapters/sql/changesets/create_events'
|
9
|
-
require_relative 'adapters/sql/changesets/update_events'
|
10
|
-
|
11
|
-
module RubyEventStore
|
12
|
-
module ROM
|
13
|
-
module SQL
|
14
|
-
class << self
|
15
|
-
def setup(config)
|
16
|
-
config.register_relation Relations::Events
|
17
|
-
config.register_relation Relations::StreamEntries
|
18
|
-
end
|
19
|
-
|
20
|
-
def configure(env)
|
21
|
-
# See: https://github.com/jeremyevans/sequel/blob/master/doc/transactions.rdoc
|
22
|
-
env.register_unit_of_work_options(
|
23
|
-
savepoint: true,
|
24
|
-
# Committing changesets concurrently causes MySQL deadlocks
|
25
|
-
# which are not caught and retried by Sequel's built-in
|
26
|
-
# :retry_on option. This appears to be a result of how ROM
|
27
|
-
# handles exceptions which don't bubble up so that Sequel
|
28
|
-
# can retry transactions with the :retry_on option when there's
|
29
|
-
# a deadlock.
|
30
|
-
#
|
31
|
-
# This is exacerbated by the fact that changesets insert multiple
|
32
|
-
# tuples with individual INSERT statements because ROM specifies
|
33
|
-
# to Sequel to return a list of primary keys created. The likelihood
|
34
|
-
# of a deadlock is reduced with batched INSERT statements.
|
35
|
-
#
|
36
|
-
# For this reason we need to manually insert changeset records to avoid
|
37
|
-
# MySQL deadlocks or to allow Sequel to retry transactions
|
38
|
-
# when the :retry_on option is specified.
|
39
|
-
retry_on: Sequel::SerializationFailure,
|
40
|
-
before_retry: lambda { |_num, ex|
|
41
|
-
env.logger.warn("RETRY TRANSACTION [#{self.class.name} => #{ex.class.name}] #{ex.message}")
|
42
|
-
}
|
43
|
-
)
|
44
|
-
|
45
|
-
env.register_error_handler :unique_violation, lambda { |ex|
|
46
|
-
case ex
|
47
|
-
when ::ROM::SQL::UniqueConstraintError, Sequel::UniqueConstraintViolation
|
48
|
-
raise EventDuplicatedInStream if IndexViolationDetector.new.detect(ex.message)
|
49
|
-
|
50
|
-
raise WrongExpectedEventVersion
|
51
|
-
end
|
52
|
-
}
|
53
|
-
|
54
|
-
env.register_error_handler :not_found, lambda { |ex, event_id|
|
55
|
-
case ex
|
56
|
-
when ::ROM::TupleCountMismatchError
|
57
|
-
raise EventNotFound, event_id
|
58
|
-
when Sequel::DatabaseError
|
59
|
-
raise ex unless ex.message =~ /PG::InvalidTextRepresentation.*uuid/
|
60
|
-
|
61
|
-
raise EventNotFound, event_id
|
62
|
-
end
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
def supports_upsert?(db)
|
67
|
-
supports_on_duplicate_key_update?(db) ||
|
68
|
-
supports_insert_conflict_update?(db)
|
69
|
-
end
|
70
|
-
|
71
|
-
def supports_on_duplicate_key_update?(db)
|
72
|
-
db.adapter_scheme =~ /mysql/
|
73
|
-
end
|
74
|
-
|
75
|
-
def supports_insert_conflict_update?(db)
|
76
|
-
case db.adapter_scheme
|
77
|
-
when :postgres
|
78
|
-
true
|
79
|
-
when :sqlite
|
80
|
-
# Sqlite 3.24.0+ supports PostgreSQL upsert syntax
|
81
|
-
db.sqlite_version >= 32_400
|
82
|
-
else
|
83
|
-
false
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class SpecHelper
|
89
|
-
attr_reader :env
|
90
|
-
|
91
|
-
def initialize(database_uri = ENV['DATABASE_URL'])
|
92
|
-
config = ::ROM::Configuration.new(
|
93
|
-
:sql,
|
94
|
-
database_uri,
|
95
|
-
max_connections: database_uri =~ /sqlite/ ? 1 : 5,
|
96
|
-
preconnect: :concurrently
|
97
|
-
# sql_mode: %w[NO_AUTO_VALUE_ON_ZERO STRICT_ALL_TABLES]
|
98
|
-
)
|
99
|
-
# $stdout.sync = true
|
100
|
-
# config.default.use_logger Logger.new(STDOUT)
|
101
|
-
# config.default.connection.pool.send(:preconnect, true)
|
102
|
-
config.default.run_migrations
|
103
|
-
|
104
|
-
@env = ROM.setup(config)
|
105
|
-
end
|
106
|
-
|
107
|
-
def run_lifecycle
|
108
|
-
establish_gateway_connection
|
109
|
-
load_gateway_schema
|
110
|
-
|
111
|
-
yield
|
112
|
-
ensure
|
113
|
-
drop_gateway_schema
|
114
|
-
close_gateway_connection
|
115
|
-
end
|
116
|
-
|
117
|
-
def gateway
|
118
|
-
env.rom_container.gateways.fetch(:default)
|
119
|
-
end
|
120
|
-
|
121
|
-
def gateway_type?(name)
|
122
|
-
gateway.connection.database_type.eql?(name)
|
123
|
-
end
|
124
|
-
|
125
|
-
def has_connection_pooling?
|
126
|
-
!gateway_type?(:sqlite)
|
127
|
-
end
|
128
|
-
|
129
|
-
def connection_pool_size
|
130
|
-
gateway.connection.pool.size
|
131
|
-
end
|
132
|
-
|
133
|
-
def close_pool_connection
|
134
|
-
gateway.connection.pool.disconnect
|
135
|
-
end
|
136
|
-
|
137
|
-
def supports_upsert?
|
138
|
-
SQL.supports_upsert?(gateway.connection)
|
139
|
-
end
|
140
|
-
|
141
|
-
protected
|
142
|
-
|
143
|
-
def establish_gateway_connection
|
144
|
-
# Manually preconnect because disconnecting and reconnecting
|
145
|
-
# seems to lose the "preconnect concurrently" setting
|
146
|
-
gateway.connection.pool.send(:preconnect, true)
|
147
|
-
end
|
148
|
-
|
149
|
-
def load_gateway_schema
|
150
|
-
gateway.run_migrations
|
151
|
-
end
|
152
|
-
|
153
|
-
def drop_gateway_schema
|
154
|
-
gateway.connection.drop_table?('event_store_events')
|
155
|
-
gateway.connection.drop_table?('event_store_events_in_streams')
|
156
|
-
gateway.connection.drop_table?('schema_migrations')
|
157
|
-
end
|
158
|
-
|
159
|
-
# See: https://github.com/rom-rb/rom-sql/blob/master/spec/shared/database_setup.rb
|
160
|
-
def close_gateway_connection
|
161
|
-
gateway.connection.disconnect
|
162
|
-
# Prevent the auto-reconnect when the test completed
|
163
|
-
# This will save from hardly reproducible connection run outs
|
164
|
-
gateway.connection.pool.available_connections.freeze
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RubyEventStore
|
4
|
-
module ROM
|
5
|
-
class TupleUniquenessError < StandardError
|
6
|
-
class << self
|
7
|
-
def for_event_id(event_id)
|
8
|
-
new "Uniquness violated for event_id (#{event_id.inspect})"
|
9
|
-
end
|
10
|
-
|
11
|
-
def for_stream_and_event_id(stream_name, event_id)
|
12
|
-
new "Uniquness violated for stream (#{stream_name.inspect}) and event_id (#{event_id.inspect})"
|
13
|
-
end
|
14
|
-
|
15
|
-
def for_stream_and_position(stream_name, position)
|
16
|
-
new "Uniquness violated for stream (#{stream_name.inspect}) and position (#{position.inspect})"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,176 +0,0 @@
|
|
1
|
-
require 'ruby_event_store/rom/event_repository'
|
2
|
-
require 'ruby_event_store/spec/event_repository_lint'
|
3
|
-
|
4
|
-
module RubyEventStore::ROM
|
5
|
-
RSpec.shared_examples :rom_event_repository do |repository_class|
|
6
|
-
subject(:repository) { repository_class.new(rom: env) }
|
7
|
-
|
8
|
-
let(:env) { rom_helper.env }
|
9
|
-
let(:rom_container) { env.rom_container }
|
10
|
-
let(:rom_db) { rom_container.gateways[:default] }
|
11
|
-
|
12
|
-
around(:each) do |example|
|
13
|
-
rom_helper.run_lifecycle { example.run }
|
14
|
-
end
|
15
|
-
|
16
|
-
let(:test_race_conditions_auto) { rom_helper.has_connection_pooling? }
|
17
|
-
let(:test_race_conditions_any) { rom_helper.has_connection_pooling? }
|
18
|
-
let(:test_binary) { false }
|
19
|
-
let(:test_change) { rom_helper.supports_upsert? }
|
20
|
-
|
21
|
-
let(:default_stream) { RubyEventStore::Stream.new('stream') }
|
22
|
-
let(:global_stream) { RubyEventStore::Stream.new('all') }
|
23
|
-
let(:mapper) { RubyEventStore::Mappers::NullMapper.new }
|
24
|
-
|
25
|
-
let(:reader) { RubyEventStore::SpecificationReader.new(repository, mapper) }
|
26
|
-
let(:specification) { RubyEventStore::Specification.new(reader) }
|
27
|
-
|
28
|
-
require 'ruby_event_store/rom/sql'
|
29
|
-
it_behaves_like :event_repository, repository_class, [ROM::SQL::Error]
|
30
|
-
|
31
|
-
specify '#initialize requires ROM::Env' do
|
32
|
-
expect { repository_class.new(rom: nil) }.to raise_error do |err|
|
33
|
-
expect(err).to be_a(ArgumentError)
|
34
|
-
expect(err.message).to eq('Must specify rom')
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
specify '#initialize uses ROM.env by default' do
|
39
|
-
expect { repository_class.new }.to raise_error(ArgumentError)
|
40
|
-
RubyEventStore::ROM.env = env
|
41
|
-
expect { repository_class.new }.not_to raise_error
|
42
|
-
RubyEventStore::ROM.env = nil
|
43
|
-
end
|
44
|
-
|
45
|
-
specify '#has_event? to raise exception for bad ID' do
|
46
|
-
expect(repository.has_event?('0')).to eq(false)
|
47
|
-
end
|
48
|
-
|
49
|
-
specify 'all considered internal detail' do
|
50
|
-
repository.append_to_stream(
|
51
|
-
[RubyEventStore::SRecord.new],
|
52
|
-
RubyEventStore::Stream.new(RubyEventStore::GLOBAL_STREAM),
|
53
|
-
RubyEventStore::ExpectedVersion.any
|
54
|
-
)
|
55
|
-
|
56
|
-
expect { repository.read(specification.stream('all').result) }.to raise_error(RubyEventStore::ReservedInternalName)
|
57
|
-
expect { repository.read(specification.stream('all').backward.result) }.to raise_error(RubyEventStore::ReservedInternalName)
|
58
|
-
expect { repository.read(specification.stream('all').limit(5).result) }.to raise_error(RubyEventStore::ReservedInternalName)
|
59
|
-
expect { repository.read(specification.stream('all').limit(5).backward.result) }.to raise_error(RubyEventStore::ReservedInternalName)
|
60
|
-
|
61
|
-
expect { repository.count(specification.stream('all').result) }.to raise_error(RubyEventStore::ReservedInternalName)
|
62
|
-
end
|
63
|
-
|
64
|
-
specify 'explicit sorting by position rather than accidental' do
|
65
|
-
events = [
|
66
|
-
RubyEventStore::SRecord.new(event_id: u1 = SecureRandom.uuid),
|
67
|
-
RubyEventStore::SRecord.new(event_id: u2 = SecureRandom.uuid),
|
68
|
-
RubyEventStore::SRecord.new(event_id: u3 = SecureRandom.uuid)
|
69
|
-
]
|
70
|
-
|
71
|
-
repo = Repositories::Events.new(rom_container)
|
72
|
-
repo.create_changeset(events).commit
|
73
|
-
|
74
|
-
expect(repo.events.to_a.size).to eq(3)
|
75
|
-
|
76
|
-
repo.stream_entries.changeset(Changesets::CreateStreamEntries, [
|
77
|
-
{ stream: default_stream.name, event_id: events[1].event_id, position: 1 },
|
78
|
-
{ stream: default_stream.name, event_id: events[0].event_id, position: 0 },
|
79
|
-
{ stream: default_stream.name, event_id: events[2].event_id, position: 2 }
|
80
|
-
]).commit
|
81
|
-
|
82
|
-
expect(repo.stream_entries.to_a.size).to eq(3)
|
83
|
-
|
84
|
-
# ActiveRecord::Schema.define do
|
85
|
-
# self.verbose = false
|
86
|
-
# remove_index :event_store_events_in_streams, [:stream, :position]
|
87
|
-
# end
|
88
|
-
|
89
|
-
expect(repository.read(specification.stream('stream').limit(3).result).map(&:event_id)).to eq([u1, u2, u3])
|
90
|
-
expect(repository.read(specification.stream('stream').result).map(&:event_id)).to eq([u1, u2, u3])
|
91
|
-
|
92
|
-
expect(repository.read(specification.stream('stream').backward.limit(3).result).map(&:event_id)).to eq([u3, u2, u1])
|
93
|
-
expect(repository.read(specification.stream('stream').backward.result).map(&:event_id)).to eq([u3, u2, u1])
|
94
|
-
end
|
95
|
-
|
96
|
-
specify 'explicit sorting by id rather than accidental for all events' do
|
97
|
-
events = [
|
98
|
-
RubyEventStore::SRecord.new(event_id: u1 = SecureRandom.uuid),
|
99
|
-
RubyEventStore::SRecord.new(event_id: u2 = SecureRandom.uuid),
|
100
|
-
RubyEventStore::SRecord.new(event_id: u3 = SecureRandom.uuid)
|
101
|
-
]
|
102
|
-
|
103
|
-
repo = Repositories::Events.new(rom_container)
|
104
|
-
repo.create_changeset(events).commit
|
105
|
-
|
106
|
-
expect(repo.events.to_a.size).to eq(3)
|
107
|
-
|
108
|
-
repo.stream_entries.changeset(Changesets::CreateStreamEntries, [
|
109
|
-
{ stream: global_stream.name, event_id: events[0].event_id, position: 1 },
|
110
|
-
{ stream: global_stream.name, event_id: events[1].event_id, position: 0 },
|
111
|
-
{ stream: global_stream.name, event_id: events[2].event_id, position: 2 }
|
112
|
-
]).commit
|
113
|
-
|
114
|
-
expect(repo.stream_entries.to_a.size).to eq(3)
|
115
|
-
|
116
|
-
expect(repository.read(specification.limit(3).result).map(&:event_id)).to eq([u1, u2, u3])
|
117
|
-
expect(repository.read(specification.limit(3).backward.result).map(&:event_id)).to eq([u3, u2, u1])
|
118
|
-
end
|
119
|
-
|
120
|
-
specify 'nested transaction - events still not persisted if append failed' do
|
121
|
-
repository.append_to_stream([
|
122
|
-
event = RubyEventStore::SRecord.new(event_id: SecureRandom.uuid)
|
123
|
-
], default_stream, RubyEventStore::ExpectedVersion.none)
|
124
|
-
|
125
|
-
env.unit_of_work do
|
126
|
-
expect do
|
127
|
-
repository.append_to_stream([
|
128
|
-
RubyEventStore::SRecord.new(event_id: '9bedf448-e4d0-41a3-a8cd-f94aec7aa763')
|
129
|
-
], default_stream, RubyEventStore::ExpectedVersion.none)
|
130
|
-
end.to raise_error(RubyEventStore::WrongExpectedEventVersion)
|
131
|
-
expect(repository.has_event?('9bedf448-e4d0-41a3-a8cd-f94aec7aa763')).to be_falsey
|
132
|
-
expect(repository.read(specification.limit(2).result).to_a).to eq([event])
|
133
|
-
end
|
134
|
-
expect(repository.has_event?('9bedf448-e4d0-41a3-a8cd-f94aec7aa763')).to be_falsey
|
135
|
-
expect(repository.read(specification.limit(2).result).to_a).to eq([event])
|
136
|
-
end
|
137
|
-
|
138
|
-
def cleanup_concurrency_test
|
139
|
-
rom_helper.close_pool_connection
|
140
|
-
end
|
141
|
-
|
142
|
-
def verify_conncurency_assumptions
|
143
|
-
expect(rom_helper.connection_pool_size).to eq(5)
|
144
|
-
end
|
145
|
-
|
146
|
-
# TODO: Port from AR to ROM
|
147
|
-
def additional_limited_concurrency_for_auto_check
|
148
|
-
positions = rom_container.relations[:stream_entries]
|
149
|
-
.ordered(:forward, default_stream)
|
150
|
-
.map { |entity| entity[:position] }
|
151
|
-
expect(positions).to eq((0..positions.size - 1).to_a)
|
152
|
-
end
|
153
|
-
|
154
|
-
private
|
155
|
-
|
156
|
-
# TODO: Port from AR to ROM
|
157
|
-
def count_queries
|
158
|
-
count = 0
|
159
|
-
# counter_f = lambda { |_name, _started, _finished, _unique_id, payload|
|
160
|
-
# count += 1 unless %w[CACHE SCHEMA].include?(payload[:name])
|
161
|
-
# }
|
162
|
-
# ActiveSupport::Notifications.subscribed(counter_f, "sql.active_record", &block)
|
163
|
-
count
|
164
|
-
end
|
165
|
-
|
166
|
-
# TODO: Port from AR to ROM
|
167
|
-
def expect_query(_match)
|
168
|
-
count = 0
|
169
|
-
# counter_f = lambda { |_name, _started, _finished, _unique_id, payload|
|
170
|
-
# count += 1 if match === payload[:sql]
|
171
|
-
# }
|
172
|
-
# ActiveSupport::Notifications.subscribed(counter_f, "sql.active_record", &block)
|
173
|
-
expect(count).to eq(1)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
RSpec.shared_examples :events_relation do |_relation_class|
|
2
|
-
subject(:relation) { rom_container.relations[:events] }
|
3
|
-
|
4
|
-
let(:env) { rom_helper.env }
|
5
|
-
let(:rom_container) { env.rom_container }
|
6
|
-
let(:rom_db) { rom_container.gateways[:default] }
|
7
|
-
|
8
|
-
around(:each) do |example|
|
9
|
-
rom_helper.run_lifecycle { example.run }
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'just created is empty' do
|
13
|
-
expect(relation.to_a).to be_empty
|
14
|
-
end
|
15
|
-
|
16
|
-
specify '#exist? indicates if one instance of the record exists by primary key' do
|
17
|
-
event = { id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now }
|
18
|
-
|
19
|
-
expect(relation.by_pk(event[:id]).exist?).to eq(false)
|
20
|
-
|
21
|
-
relation.insert(event)
|
22
|
-
|
23
|
-
expect(relation.by_pk(event[:id]).exist?).to eq(true)
|
24
|
-
end
|
25
|
-
|
26
|
-
specify '#insert verifies tuple is unique' do
|
27
|
-
events = [
|
28
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
29
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
30
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now }
|
31
|
-
]
|
32
|
-
|
33
|
-
relation.command(:create).call(events[0..1])
|
34
|
-
|
35
|
-
expect do
|
36
|
-
env.handle_error(:unique_violation) { relation.insert(events[0]) }
|
37
|
-
end.to raise_error(RubyEventStore::EventDuplicatedInStream)
|
38
|
-
expect do
|
39
|
-
env.handle_error(:unique_violation) { relation.insert(events[1]) }
|
40
|
-
end.to raise_error(RubyEventStore::EventDuplicatedInStream)
|
41
|
-
expect { relation.insert(events[2]) }.not_to raise_error
|
42
|
-
expect do
|
43
|
-
env.handle_error(:unique_violation) { relation.insert(events[2]) }
|
44
|
-
end.to raise_error(RubyEventStore::EventDuplicatedInStream)
|
45
|
-
end
|
46
|
-
|
47
|
-
specify '#by_pk finds tuples by ID' do
|
48
|
-
events = [
|
49
|
-
{ id: id = SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
50
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
51
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now }
|
52
|
-
]
|
53
|
-
|
54
|
-
relation.command(:create).call(events)
|
55
|
-
|
56
|
-
expect(relation.by_pk(id).to_a.size).to eq(1)
|
57
|
-
expect(relation.by_pk(id).to_a.map { |e| e[:id] }).to eq([id])
|
58
|
-
end
|
59
|
-
|
60
|
-
specify 'each method returns proper type' do
|
61
|
-
events = [
|
62
|
-
{ id: id = SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
63
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now },
|
64
|
-
{ id: SecureRandom.uuid, event_type: 'TestEvent', data: '{}', metadata: '{}', created_at: Time.now }
|
65
|
-
]
|
66
|
-
|
67
|
-
relation.command(:create).call(events)
|
68
|
-
|
69
|
-
expect(relation.by_pk(SecureRandom.uuid).exist?).to eq(false)
|
70
|
-
expect(relation.by_pk(id).exist?).to eq(true)
|
71
|
-
|
72
|
-
expect(relation.by_pk(id)).to be_a(relation.class)
|
73
|
-
# expect(relation.by_pk(id).first).to be_a(::ROM::Struct)
|
74
|
-
end
|
75
|
-
end
|