ruby_event_store-rom 0.30.0 → 0.31.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: 3f2cadf18b1a9e4c39002fd8d23c4d2b44a96f784eb4789d1e3faa972f3353af
4
- data.tar.gz: 259cdfd63aa4f52aeee63d5d1b0dbfc86f4d669f5a7794743c127d0b5f2b9767
3
+ metadata.gz: 578db4e9a6e68483348133d15dfee076b76a29a76ac6ae5ec6e7b94063bf7284
4
+ data.tar.gz: cb177a748a62f91911ace80e4c5175a5cc4cda773947eff6d855249d71a7b8e6
5
5
  SHA512:
6
- metadata.gz: e42552f06a8d409406f046385e70e4296048396bbe47d126b36d90280d41d50a62293d60e9ffc86bc8f7653a93118a13e615f46f941ba1b7e8a41189ee110c98
7
- data.tar.gz: 123ec9e8fafb080c5e48300b7f94c87a2c15a99bdf9cf898572767a43ffdd4ada396e87aa7621ed449df176ec0a6791954488f8fc0884dac0d711dd209ba1ab4
6
+ metadata.gz: b0124ece3841ae0774b5a758cf5c154d5406060dfeae4803072ad37d08ad56d0305d33a81fdbe3359e834fcc8412270e50176a39b49f3ca38ecf68283e8faa6a
7
+ data.tar.gz: f773ecdc66ee0ff1974ca9977ea9b003cf63b4ac8212ddfda997c8f7c13c76693c65281cf0684f35fb43290cb411b7e3b971780f6815480fb34a2c1dc871221f
data/Makefile CHANGED
@@ -1,25 +1,42 @@
1
1
  GEM_VERSION = $(shell cat ../RES_VERSION)
2
2
  GEM_NAME = ruby_event_store-rom
3
3
  REQUIRE = $(GEM_NAME)
4
- IGNORE = RubyEventStore::ROM::EventRepository\#handle_not_found_errors \
4
+ IGNORE = RubyEventStore::ROM::EventRepository\#initialize \
5
+ RubyEventStore::ROM::EventRepository\#handle_not_found_errors \
5
6
  RubyEventStore::ROM::EventRepository\#handle_unique_violation_errors \
6
7
  RubyEventStore::ROM::EventRepository\#has_event? \
7
8
  RubyEventStore::ROM::EventRepository\#last_stream_event \
8
9
  RubyEventStore::ROM::Repositories::Events\#find_nonexistent_pks \
10
+ RubyEventStore::ROM::Repositories::StreamEntries\#create_changeset \
9
11
  RubyEventStore::ROM::Env\#handle_error \
10
12
  RubyEventStore::ROM::Env\#initialize \
11
13
  RubyEventStore::ROM::Env\#register_error_handler \
12
14
  RubyEventStore::ROM::Env\#register_unit_of_work_options \
13
- RubyEventStore::ROM::Env\#transaction \
15
+ RubyEventStore::ROM::Env\#unit_of_work \
14
16
  RubyEventStore::ROM::UnitOfWork\#call \
15
17
  RubyEventStore::ROM::UnitOfWork\#commit! \
16
18
  RubyEventStore::ROM::SQL::Relations::StreamEntries\#normalize_stream_name \
17
19
  RubyEventStore::ROM::SQL::IndexViolationDetector\#detect \
20
+ RubyEventStore::ROM::SQL::SpecHelper\#initialize \
21
+ RubyEventStore::ROM::SQL::SpecHelper\#has_connection_pooling? \
22
+ RubyEventStore::ROM::SQL::SpecHelper\#close_pool_connection \
18
23
  RubyEventStore::ROM::SQL::SpecHelper\#load_gateway_schema \
19
24
  RubyEventStore::ROM::SQL::SpecHelper\#establish_gateway_connection \
20
25
  RubyEventStore::ROM::SQL::SpecHelper\#drop_gateway_schema \
21
26
  RubyEventStore::ROM::SQL::SpecHelper\#close_gateway_connection \
22
- RubyEventStore::ROM::SQL::UnitOfWork\#commit!
27
+ RubyEventStore::ROM::SQL::SpecHelper\#run_lifecycle \
28
+ RubyEventStore::ROM::SQL::UnitOfWork\#commit! \
29
+ RubyEventStore::ROM::Memory::SpecHelper\#initialize \
30
+ RubyEventStore::ROM::Memory::SpecHelper\#close_pool_connection \
31
+ RubyEventStore::ROM::Memory::SpecHelper\#load_gateway_schema \
32
+ RubyEventStore::ROM::Memory::SpecHelper\#establish_gateway_connection \
33
+ RubyEventStore::ROM::Memory::SpecHelper\#drop_gateway_schema \
34
+ RubyEventStore::ROM::Memory::SpecHelper\#close_gateway_connection \
35
+ RubyEventStore::ROM::Memory::SpecHelper\#run_lifecycle \
36
+ RubyEventStore::ROM::Memory::UnitOfWork\#commit! \
37
+ RubyEventStore::ROM::Memory::Relations::Events\#verify_uniquness! \
38
+ RubyEventStore::ROM::Memory::Relations::StreamEntries\#verify_uniquness! \
39
+ RubyEventStore::ROM::Memory::Relations::StreamEntries\#normalize_stream_name
23
40
  SUBJECT ?= RubyEventStore::ROM*
24
41
  DATABASE_URL ?= sqlite::memory:
25
42
 
@@ -0,0 +1,45 @@
1
+ module RubyEventStore
2
+ module ROM
3
+ module Memory
4
+ module Relations
5
+ class Events < ::ROM::Relation[:memory]
6
+ schema(:events) do
7
+ attribute :id, ::ROM::Types::Strict::String.meta(primary_key: true)
8
+ attribute :event_type, ::ROM::Types::Strict::String
9
+ attribute :metadata, ::ROM::Types::Strict::String.optional
10
+ attribute :data, ::ROM::Types::Strict::String
11
+ attribute :created_at, ::ROM::Types::Strict::Time.default { Time.now }
12
+ end
13
+
14
+ def insert(tuple)
15
+ verify_uniquness!(tuple)
16
+ super
17
+ end
18
+
19
+ def for_stream_entries(_assoc, stream_entries)
20
+ restrict(id: stream_entries.map { |e| e[:event_id] })
21
+ end
22
+
23
+ def by_pk(id)
24
+ restrict(id: id)
25
+ end
26
+
27
+ def exist?
28
+ one?
29
+ end
30
+
31
+ def pluck(name)
32
+ map { |e| e[name] }
33
+ end
34
+
35
+ private
36
+
37
+ def verify_uniquness!(tuple)
38
+ return unless by_pk(tuple[:id]).exist?
39
+ raise TupleUniquenessError.for_event_id(tuple[:id])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,95 @@
1
+ module RubyEventStore
2
+ module ROM
3
+ module Memory
4
+ module Relations
5
+ class StreamEntries < ::ROM::Relation[:memory]
6
+ schema(:stream_entries) do
7
+ attribute :id, ::ROM::Types::Strict::Int.meta(primary_key: true).default { RubyEventStore::ROM::Memory.fetch_next_id }
8
+ attribute :stream, ::ROM::Types::Strict::String
9
+ attribute :position, ::ROM::Types::Strict::Int.optional
10
+ attribute :event_id, ::ROM::Types::Strict::String.meta(foreign_key: true, relation: :events)
11
+ attribute :created_at, ::ROM::Types::Strict::Time.default { Time.now }
12
+
13
+ associations do
14
+ belongs_to :events, as: :event, foreign_key: :event_id, override: true, view: :for_stream_entries
15
+ end
16
+ end
17
+
18
+ auto_struct true
19
+
20
+ SERIALIZED_GLOBAL_STREAM_NAME = 'all'.freeze
21
+
22
+ def offset(num)
23
+ num.zero? ? self : new(dataset.slice(num..-1))
24
+ end
25
+
26
+ def take(num)
27
+ num.nil? ? self : super
28
+ end
29
+
30
+ def insert(tuple)
31
+ verify_uniquness!(tuple)
32
+ super
33
+ end
34
+
35
+ def delete(tuple)
36
+ super tuple.to_h
37
+ end
38
+
39
+ def by_stream(stream)
40
+ restrict(stream: normalize_stream_name(stream))
41
+ end
42
+
43
+ def by_stream_and_event_id(stream, event_id)
44
+ restrict(stream: normalize_stream_name(stream), event_id: event_id).one!
45
+ end
46
+
47
+ def max_position(stream)
48
+ new(by_stream(stream).order(:position).dataset.reverse).project(:position).take(1).one
49
+ end
50
+
51
+ DIRECTION_MAP = {
52
+ forward: [false, :>],
53
+ backward: [true, :<]
54
+ }.freeze
55
+
56
+ def ordered(direction, stream, offset_entry_id = nil)
57
+ reverse, operator = DIRECTION_MAP[direction]
58
+
59
+ raise ArgumentError, 'Direction must be :forward or :backward' if order.nil?
60
+
61
+ order_columns = %i[position id]
62
+ order_columns.delete(:position) if stream.global?
63
+
64
+ query = by_stream(stream)
65
+ query = query.restrict { |tuple| tuple[:id].public_send(operator, offset_entry_id) } if offset_entry_id
66
+ query = query.order(*order_columns)
67
+ query = new(query.dataset.reverse) if reverse
68
+
69
+ query
70
+ end
71
+
72
+ private
73
+
74
+ # Verifies uniqueness of [stream, event_id] and [stream, position]
75
+ def verify_uniquness!(tuple)
76
+ stream = tuple[:stream]
77
+ attrs = %i[position event_id]
78
+ attrs.delete(:position) if Stream.new(stream).global?
79
+
80
+ attrs.each do |key|
81
+ next if key == :position && tuple[key].nil?
82
+ next if restrict(:stream => stream, key => tuple.fetch(key)).none?
83
+
84
+ raise TupleUniquenessError.public_send(:"for_stream_and_#{key}", stream, tuple.fetch(key))
85
+ end
86
+ end
87
+
88
+ def normalize_stream_name(stream)
89
+ stream.global? ? SERIALIZED_GLOBAL_STREAM_NAME : stream.name
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,49 @@
1
+ module RubyEventStore
2
+ module ROM
3
+ module Memory
4
+ class UnitOfWork < ROM::UnitOfWork
5
+ def self.mutex
6
+ @mutex ||= Mutex.new
7
+ end
8
+
9
+ def commit!(gateway, changesets, **options)
10
+ self.class.mutex.synchronize do
11
+ committed = []
12
+
13
+ begin
14
+ while changesets.size > 0
15
+ changeset = changesets.shift
16
+ relation = env.container.relations[changeset.relation.name]
17
+
18
+ case changeset
19
+ when ROM::Repositories::Events::Create
20
+ relation.by_pk(changeset.to_a.map{ |e| e[:id] }).each do |tuple|
21
+ raise TupleUniquenessError.for_event_id(tuple[:id])
22
+ end
23
+ when ROM::Repositories::StreamEntries::Create
24
+ changeset.to_a.each do |tuple|
25
+ relation.send(:verify_uniquness!, tuple)
26
+ end
27
+ else
28
+ raise ArgumentError, 'Unknown changeset'
29
+ end
30
+
31
+ committed << [changeset, relation]
32
+
33
+ changeset.commit
34
+ end
35
+ rescue StandardError
36
+ committed.reverse.each do |changeset, relation|
37
+ relation
38
+ .restrict(id: changeset.to_a.map { |e| e[:id] })
39
+ .command(:delete, result: :many).call
40
+ end
41
+
42
+ raise
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -3,7 +3,9 @@ module RubyEventStore
3
3
  module SQL
4
4
  module Relations
5
5
  class Events < ::ROM::Relation[:sql]
6
- schema(:event_store_events, as: :events, infer: true)
6
+ schema(:event_store_events, as: :events, infer: true) do
7
+ attribute :created_at, ::ROM::Types::Strict::Time.default { Time.now }
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -4,6 +4,8 @@ module RubyEventStore
4
4
  module Relations
5
5
  class StreamEntries < ::ROM::Relation[:sql]
6
6
  schema(:event_store_events_in_streams, as: :stream_entries, infer: true) do
7
+ attribute :created_at, ::ROM::Types::Strict::Time.default { Time.now }
8
+
7
9
  associations do
8
10
  belongs_to :events, as: :event, foreign_key: :event_id
9
11
  end
@@ -11,10 +13,6 @@ module RubyEventStore
11
13
 
12
14
  alias_method :take, :limit
13
15
 
14
- def by_stream(stream)
15
- where(stream: stream.name)
16
- end
17
-
18
16
  SERIALIZED_GLOBAL_STREAM_NAME = 'all'.freeze
19
17
 
20
18
  def by_stream(stream)
@@ -47,8 +45,6 @@ module RubyEventStore
47
45
  query.order { |r| order_columns.map { |c| r[:stream_entries][c].public_send(order) } }
48
46
  end
49
47
 
50
- alias_method :take, :limit
51
-
52
48
  private
53
49
 
54
50
  def normalize_stream_name(stream)
@@ -1,15 +1,18 @@
1
1
  require 'ruby_event_store/rom/sql'
2
2
 
3
+ MIGRATIONS_PATH = 'db/migrate'
4
+
3
5
  desc 'Setup ROM EventRespository environment'
4
6
  task 'db:setup' do
7
+ Dir.chdir(Dir.pwd)
5
8
  ROM::SQL::RakeSupport.env = ::RubyEventStore::ROM.configure(:sql).container
6
9
  end
7
10
 
8
- desc "Copy RubyEventStore SQL migrations to db/migrate"
9
- task 'db:copy_migrations' => 'db:setup' do
10
- Dir[File.join(File.dirname(__FILE__), '../../../../../../db/migrate/*.rb')].each do |input|
11
+ desc 'Copy RubyEventStore SQL migrations to db/migrate'
12
+ task 'db:migrations:copy' => 'db:setup' do
13
+ Dir[File.join(File.dirname(__FILE__), '../../../../../../', MIGRATIONS_PATH, '/*.rb')].each do |input|
11
14
  name = File.basename(input, '.*').sub(/\d+_/, '')
12
- output = ROM::SQL::RakeSupport.create_migration(name)
15
+ output = ROM::SQL::RakeSupport.create_migration(name, path: File.join(Dir.pwd, MIGRATIONS_PATH))
13
16
 
14
17
  File.write output, File.read(input)
15
18
 
@@ -1,9 +1,17 @@
1
1
  require 'ruby_event_store/rom/unit_of_work'
2
+ require 'forwardable'
2
3
 
3
4
  module RubyEventStore
4
5
  module ROM
5
6
  class EventRepository
7
+ extend Forwardable
8
+
9
+ def_delegator :@rom, :handle_error, :guard_for
10
+ def_delegators :@rom, :unit_of_work
11
+
6
12
  def initialize(rom: ROM.env)
13
+ raise ArgumentError, "Must specify rom" unless rom && rom.instance_of?(Env)
14
+
7
15
  @rom = rom
8
16
  @events = Repositories::Events.new(rom.container)
9
17
  @stream_entries = Repositories::StreamEntries.new(rom.container)
@@ -13,31 +21,44 @@ module RubyEventStore
13
21
  events = normalize_to_array(events)
14
22
  event_ids = events.map(&:event_id)
15
23
 
16
- @rom.transaction do |changesets|
17
- # Create changesets inside transaction because
18
- # we want to find the last position (a.k.a. version)
19
- # again if the transaction is retried due to a
20
- # deadlock in MySQL
21
- changesets << @events.create_changeset(events)
22
- changesets << @stream_entries.create_changeset(event_ids, stream, expected_version, global_stream: true)
24
+ guard_for(:unique_violation) do
25
+ unit_of_work do |changesets|
26
+ # Create changesets inside transaction because
27
+ # we want to find the last position (a.k.a. version)
28
+ # again if the transaction is retried due to a
29
+ # deadlock in MySQL
30
+ changesets << @events.create_changeset(events)
31
+ changesets << @stream_entries.create_changeset(
32
+ event_ids,
33
+ stream,
34
+ @stream_entries.resolve_version(stream, expected_version),
35
+ global_stream: true
36
+ )
37
+ end
23
38
  end
24
39
 
25
40
  self
26
- rescue => ex
27
- @rom.handle_error(:unique_violation, ex)
28
41
  end
29
42
 
30
43
  def link_to_stream(event_ids, stream, expected_version)
31
44
  event_ids = normalize_to_array(event_ids)
32
- nonexistent_ids = @events.find_nonexistent_pks(event_ids)
33
-
34
- nonexistent_ids.each { |id| raise EventNotFound.new(id) }
35
45
 
36
- @stream_entries.create_changeset(event_ids, stream, expected_version).commit
46
+ # Validate event IDs
47
+ @events
48
+ .find_nonexistent_pks(event_ids)
49
+ .each { |id| raise EventNotFound.new(id) }
50
+
51
+ guard_for(:unique_violation) do
52
+ unit_of_work do |changesets|
53
+ changesets << @stream_entries.create_changeset(
54
+ event_ids,
55
+ stream,
56
+ @stream_entries.resolve_version(stream, expected_version)
57
+ )
58
+ end
59
+ end
37
60
 
38
61
  self
39
- rescue => ex
40
- @rom.handle_error(:unique_violation, ex)
41
62
  end
42
63
 
43
64
  def delete_stream(stream)
@@ -45,12 +66,8 @@ module RubyEventStore
45
66
  end
46
67
 
47
68
  def has_event?(event_id)
48
- @events.exist?(event_id)
49
- rescue => ex
50
- begin
51
- @rom.handle_error(:not_found, ex, event_id)
52
- rescue EventNotFound
53
- false
69
+ !! guard_for(:not_found, event_id, swallow: EventNotFound) do
70
+ @events.exist?(event_id)
54
71
  end
55
72
  end
56
73
 
@@ -65,9 +82,9 @@ module RubyEventStore
65
82
  end
66
83
 
67
84
  def read_event(event_id)
68
- @events.by_id(event_id)
69
- rescue => ex
70
- @rom.handle_error(:not_found, ex, event_id)
85
+ guard_for(:not_found, event_id) do
86
+ @events.by_id(event_id)
87
+ end
71
88
  end
72
89
 
73
90
  def read(specification)
@@ -0,0 +1,68 @@
1
+ require 'ruby_event_store/rom'
2
+ require 'rom/memory'
3
+ require_relative 'adapters/memory/unit_of_work'
4
+ require_relative 'adapters/memory/relations/events'
5
+ require_relative 'adapters/memory/relations/stream_entries'
6
+
7
+ module RubyEventStore
8
+ module ROM
9
+ module Memory
10
+ class << self
11
+ def fetch_next_id
12
+ @last_id ||= 0
13
+ @mutex ||= Mutex.new
14
+ @mutex.synchronize { @last_id += 1 }
15
+ end
16
+
17
+ def setup(config)
18
+ config.register_relation Relations::Events
19
+ config.register_relation Relations::StreamEntries
20
+ end
21
+
22
+ def configure(env)
23
+ env.register_unit_of_work_options(class: UnitOfWork)
24
+
25
+ env.register_error_handler :unique_violation, -> ex {
26
+ case ex
27
+ when TupleUniquenessError
28
+ raise EventDuplicatedInStream if ex.message =~ /event_id/
29
+ raise WrongExpectedEventVersion
30
+ end
31
+ }
32
+ end
33
+ end
34
+
35
+ class SpecHelper
36
+ attr_reader :env
37
+ attr_reader :connection_pool_size, :close_pool_connection
38
+
39
+ def initialize
40
+ @connection_pool_size = 5
41
+ @env = ROM.setup(:memory)
42
+ end
43
+
44
+ def run_lifecycle
45
+ yield
46
+ ensure
47
+ drop_gateway_schema
48
+ end
49
+
50
+ def gateway
51
+ env.container.gateways.fetch(:default)
52
+ end
53
+
54
+ def drop_gateway_schema
55
+ gateway.connection.data.values.each { |v| v.data.clear }
56
+ end
57
+
58
+ def close_gateway_connection
59
+ gateway.disconnect
60
+ end
61
+
62
+ def has_connection_pooling?
63
+ true
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -47,7 +47,7 @@ module RubyEventStore
47
47
  .offset(offset)
48
48
  .take(limit)
49
49
  .combine(:event)
50
- .map_with(:stream_entry_to_serialized_record) # Add `auto_struct: false` for Memory adapter
50
+ .map_with(:stream_entry_to_serialized_record, auto_struct: false)
51
51
  .to_ary
52
52
  end
53
53
  BatchEnumerator.new(batch_size, limit || Float::INFINITY, reader).each
@@ -56,7 +56,7 @@ module RubyEventStore
56
56
  .ordered(direction, stream, offset_entry_id)
57
57
  .take(limit)
58
58
  .combine(:event)
59
- .map_with(:stream_entry_to_serialized_record) # Add `auto_struct: false` for Memory adapter
59
+ .map_with(:stream_entry_to_serialized_record, auto_struct: false)
60
60
  .each
61
61
  end
62
62
  end
@@ -12,22 +12,19 @@ module RubyEventStore
12
12
 
13
13
  POSITION_SHIFT = 1.freeze
14
14
 
15
- def create_changeset(event_ids, stream, expected_version, global_stream: nil)
16
- resolved_version = expected_version.resolve_for(stream, ->(_stream) {
17
- (stream_entries.max_position(stream) || {})[:position]
18
- })
19
-
15
+ def create_changeset(event_ids, stream, resolved_version, global_stream: nil)
20
16
  tuples = []
21
-
17
+
22
18
  event_ids.each_with_index do |event_id, index|
23
19
  tuples << {
24
20
  stream: stream.name,
25
21
  position: resolved_version && resolved_version + index + POSITION_SHIFT,
26
22
  event_id: event_id
27
- } unless stream.global?
23
+ } unless stream.global?
28
24
 
29
- tuples << {
25
+ tuples << {
30
26
  stream: stream_entries.class::SERIALIZED_GLOBAL_STREAM_NAME,
27
+ position: nil,
31
28
  event_id: event_id
32
29
  } if global_stream
33
30
  end
@@ -36,11 +33,13 @@ module RubyEventStore
36
33
  end
37
34
 
38
35
  def delete(stream)
39
- delete_changeset(stream).commit
36
+ stream_entries.by_stream(stream).command(:delete).call
40
37
  end
41
38
 
42
- def delete_changeset(stream)
43
- stream_entries.by_stream(stream).changeset(:delete)
39
+ def resolve_version(stream, expected_version)
40
+ expected_version.resolve_for(stream, ->(_stream) {
41
+ (stream_entries.max_position(stream) || {})[:position]
42
+ })
44
43
  end
45
44
  end
46
45
  end
@@ -1,5 +1,5 @@
1
- require 'rom/sql'
2
1
  require 'ruby_event_store/rom'
2
+ require 'rom/sql'
3
3
  require_relative 'adapters/sql/index_violation_detector'
4
4
  require_relative 'adapters/sql/unit_of_work'
5
5
  require_relative 'adapters/sql/relations/events'
@@ -44,14 +44,50 @@ module RubyEventStore
44
44
  class SpecHelper
45
45
  attr_reader :env
46
46
 
47
- def initialize(rom: ROM.env)
48
- @env = rom
47
+ def initialize(database_uri = ENV['DATABASE_URL'])
48
+ config = ::ROM::Configuration.new(
49
+ :sql,
50
+ database_uri,
51
+ max_connections: database_uri =~ /sqlite/ ? 1 : 5,
52
+ preconnect: :concurrently,
53
+ # sql_mode: %w[NO_AUTO_VALUE_ON_ZERO STRICT_ALL_TABLES]
54
+ )
55
+ # $stdout.sync = true
56
+ # config.default.use_logger Logger.new(STDOUT)
57
+ # config.default.connection.pool.send(:preconnect, true)
58
+ config.default.run_migrations
59
+
60
+ @env = ROM.setup(config)
61
+ end
62
+
63
+ def run_lifecycle
64
+ establish_gateway_connection
65
+ load_gateway_schema
66
+
67
+ yield
68
+ ensure
69
+ drop_gateway_schema
70
+ close_gateway_connection
49
71
  end
50
72
 
51
73
  def gateway
52
74
  env.container.gateways.fetch(:default)
53
75
  end
54
76
 
77
+ def has_connection_pooling?
78
+ !gateway.connection.database_type.eql?(:sqlite)
79
+ end
80
+
81
+ def connection_pool_size
82
+ gateway.connection.pool.size
83
+ end
84
+
85
+ def close_pool_connection
86
+ gateway.connection.pool.disconnect
87
+ end
88
+
89
+ protected
90
+
55
91
  def establish_gateway_connection
56
92
  # Manually preconnect because disconnecting and reconnecting
57
93
  # seems to lose the "preconnect concurrently" setting
@@ -1,6 +1,19 @@
1
1
  module RubyEventStore
2
2
  module ROM
3
3
  class TupleUniquenessError < StandardError
4
+ class << self
5
+ def for_event_id(event_id)
6
+ new "Uniquness violated for event_id (#{event_id.inspect})"
7
+ end
8
+
9
+ def for_stream_and_event_id(stream_name, event_id)
10
+ new "Uniquness violated for stream (#{stream_name.inspect}) and event_id (#{event_id.inspect})"
11
+ end
12
+
13
+ def for_stream_and_position(stream_name, position)
14
+ new "Uniquness violated for stream (#{stream_name.inspect}) and position (#{position.inspect})"
15
+ end
16
+ end
4
17
  end
5
18
  end
6
19
  end
@@ -1,5 +1,5 @@
1
1
  module RubyEventStore
2
2
  module ROM
3
- VERSION = "0.30.0"
3
+ VERSION = "0.31.0"
4
4
  end
5
5
  end
@@ -24,7 +24,7 @@ module RubyEventStore
24
24
  container[:logger]
25
25
  end
26
26
 
27
- def transaction(&block)
27
+ def unit_of_work(&block)
28
28
  options = container[:unit_of_work_options].dup
29
29
  options.delete(:class){UnitOfWork}.new(rom: self).call(**options, &block)
30
30
  end
@@ -37,9 +37,15 @@ module RubyEventStore
37
37
  container[:"#{type}_error_handlers"] << handler
38
38
  end
39
39
 
40
- def handle_error(type, ex, *args)
41
- container[:"#{type}_error_handlers"].each{ |h| h.call(ex, *args) }
42
- raise ex
40
+ def handle_error(type, *args, swallow: [])
41
+ yield
42
+ rescue => ex
43
+ begin
44
+ container[:"#{type}_error_handlers"].each{ |h| h.call(ex, *args) }
45
+ raise ex
46
+ rescue *swallow
47
+ # swallow
48
+ end
43
49
  end
44
50
  end
45
51
 
@@ -51,8 +57,6 @@ module RubyEventStore
51
57
  if adapter_name.is_a?(::ROM::Configuration)
52
58
  # Call config block manually
53
59
  Env.new ::ROM.container(adapter_name.tap(&block), &block)
54
- elsif database_uri.nil?
55
- raise ArgumentError.new('Missing database URI argument or DATABASE_URL environment variable')
56
60
  else
57
61
  Env.new ::ROM.container(adapter_name, database_uri, &block)
58
62
  end