pg_eventstore 1.13.1 → 1.13.2

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +126 -0
  3. data/CHANGELOG.md +4 -0
  4. data/exe/pg-eventstore +6 -6
  5. data/lib/pg_eventstore/abstract_command.rb +1 -1
  6. data/lib/pg_eventstore/callbacks.rb +7 -2
  7. data/lib/pg_eventstore/cli/commands/callback_handlers/start_cmd_handlers.rb +1 -0
  8. data/lib/pg_eventstore/cli/commands/start_subscriptions_command.rb +5 -4
  9. data/lib/pg_eventstore/cli/parser_options/metadata.rb +4 -4
  10. data/lib/pg_eventstore/cli/parsers/default_parser.rb +8 -8
  11. data/lib/pg_eventstore/cli/parsers/subscription_parser.rb +2 -2
  12. data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +4 -1
  13. data/lib/pg_eventstore/cli.rb +4 -4
  14. data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +2 -2
  15. data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +1 -0
  16. data/lib/pg_eventstore/commands/link_to.rb +4 -5
  17. data/lib/pg_eventstore/commands/multiple.rb +1 -3
  18. data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +1 -1
  19. data/lib/pg_eventstore/config.rb +1 -1
  20. data/lib/pg_eventstore/connection.rb +4 -1
  21. data/lib/pg_eventstore/errors.rb +3 -1
  22. data/lib/pg_eventstore/extensions/callbacks_extension.rb +2 -0
  23. data/lib/pg_eventstore/extensions/options_extension.rb +10 -10
  24. data/lib/pg_eventstore/extensions/using_connection_extension.rb +1 -1
  25. data/lib/pg_eventstore/pg_connection.rb +7 -5
  26. data/lib/pg_eventstore/queries/event_queries.rb +11 -10
  27. data/lib/pg_eventstore/queries/partition_queries.rb +4 -4
  28. data/lib/pg_eventstore/queries/transaction_queries.rb +5 -9
  29. data/lib/pg_eventstore/query_builders/events_filtering.rb +13 -13
  30. data/lib/pg_eventstore/query_builders/partitions_filtering.rb +6 -8
  31. data/lib/pg_eventstore/rspec/has_option_matcher.rb +12 -13
  32. data/lib/pg_eventstore/rspec/test_helpers.rb +4 -3
  33. data/lib/pg_eventstore/sql_builder.rb +9 -13
  34. data/lib/pg_eventstore/stream.rb +8 -8
  35. data/lib/pg_eventstore/subscriptions/basic_runner.rb +4 -3
  36. data/lib/pg_eventstore/subscriptions/commands_handler.rb +1 -1
  37. data/lib/pg_eventstore/subscriptions/events_processor.rb +1 -1
  38. data/lib/pg_eventstore/subscriptions/extensions/base_command_extension.rb +10 -8
  39. data/lib/pg_eventstore/subscriptions/queries/subscription_command_queries.rb +23 -21
  40. data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +11 -8
  41. data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_command_queries.rb +8 -13
  42. data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +7 -6
  43. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_connection.rb +3 -1
  44. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_runner.rb +1 -0
  45. data/lib/pg_eventstore/subscriptions/runner_state.rb +3 -1
  46. data/lib/pg_eventstore/subscriptions/subscription.rb +11 -10
  47. data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +1 -1
  48. data/lib/pg_eventstore/subscriptions/subscription_runner.rb +1 -1
  49. data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +5 -7
  50. data/lib/pg_eventstore/subscriptions/subscriptions_set.rb +8 -8
  51. data/lib/pg_eventstore/subscriptions/subscriptions_set_lifecycle.rb +2 -0
  52. data/lib/pg_eventstore/tasks/setup.rake +7 -6
  53. data/lib/pg_eventstore/utils.rb +8 -4
  54. data/lib/pg_eventstore/version.rb +1 -1
  55. data/lib/pg_eventstore/web/application.rb +22 -15
  56. data/lib/pg_eventstore/web/paginator/event_types_collection.rb +9 -11
  57. data/lib/pg_eventstore/web/paginator/events_collection.rb +6 -7
  58. data/lib/pg_eventstore/web/paginator/helpers.rb +19 -19
  59. data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +9 -9
  60. data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +9 -10
  61. data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +9 -11
  62. data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
  63. data/lib/pg_eventstore/web/subscriptions/subscriptions_to_set_association.rb +2 -0
  64. data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
  65. data/lib/pg_eventstore.rb +3 -11
  66. data/pg_eventstore.gemspec +19 -19
  67. data/sig/pg_eventstore/client.rbs +4 -8
  68. data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +2 -0
  69. data/sig/pg_eventstore/web/application.rbs +2 -0
  70. metadata +8 -7
@@ -7,7 +7,7 @@ module PgEventstore
7
7
  ISOLATION_LEVELS = {
8
8
  read_committed: 'READ COMMITTED',
9
9
  repeatable_read: 'REPEATABLE READ',
10
- serializable: 'SERIALIZABLE'
10
+ serializable: 'SERIALIZABLE',
11
11
  }.tap do |h|
12
12
  h.default = h[:serializable]
13
13
  end.freeze
@@ -24,16 +24,12 @@ module PgEventstore
24
24
 
25
25
  # @param level [Symbol] transaction isolation level
26
26
  # @return [void]
27
- def transaction(level = :serializable)
27
+ def transaction(level = :serializable, &blk)
28
28
  connection.with do |conn|
29
29
  # We are inside a transaction already - no need to start another one
30
- if [PG::PQTRANS_ACTIVE, PG::PQTRANS_INTRANS].include?(conn.transaction_status)
31
- next yield
32
- end
30
+ next yield if [PG::PQTRANS_ACTIVE, PG::PQTRANS_INTRANS].include?(conn.transaction_status)
33
31
 
34
- pg_transaction(ISOLATION_LEVELS[level], conn) do
35
- yield
36
- end
32
+ pg_transaction(ISOLATION_LEVELS[level], conn, &blk)
37
33
  end
38
34
  end
39
35
 
@@ -42,7 +38,7 @@ module PgEventstore
42
38
  # @param level [String] PostgreSQL transaction isolation level
43
39
  # @param pg_connection [PG::Connection]
44
40
  # @return [void]
45
- def pg_transaction(level, pg_connection)
41
+ def pg_transaction(level, pg_connection, &_blk)
46
42
  pg_connection.transaction do
47
43
  pg_connection.exec("SET TRANSACTION ISOLATION LEVEL #{level}")
48
44
  yield
@@ -17,7 +17,7 @@ module PgEventstore
17
17
  :asc => 'ASC',
18
18
  :desc => 'DESC',
19
19
  'Forwards' => 'ASC',
20
- 'Backwards' => 'DESC'
20
+ 'Backwards' => 'DESC',
21
21
  }.tap do |directions|
22
22
  directions.default = 'ASC'
23
23
  end.freeze
@@ -82,9 +82,7 @@ module PgEventstore
82
82
  # @return [Array<String>]
83
83
  def extract_event_types_filter(options)
84
84
  options in { filter: { event_types: Array => event_types } }
85
- event_types = event_types&.select do
86
- _1.is_a?(String)
87
- end
85
+ event_types = event_types&.select { _1.is_a?(String) }
88
86
  event_types || []
89
87
  end
90
88
 
@@ -92,10 +90,10 @@ module PgEventstore
92
90
  # @return [Array<Hash[Symbol, String]>]
93
91
  def extract_streams_filter(options)
94
92
  options in { filter: { streams: Array => streams } }
95
- streams = streams&.map do
96
- _1 in { context: String | NilClass => context }
97
- _1 in { stream_name: String | NilClass => stream_name }
98
- _1 in { stream_id: String | NilClass => stream_id }
93
+ streams = streams&.map do |stream_attrs|
94
+ stream_attrs in { context: String | NilClass => context }
95
+ stream_attrs in { stream_name: String | NilClass => stream_name }
96
+ stream_attrs in { stream_id: String | NilClass => stream_id }
99
97
  { context: context, stream_name: stream_name, stream_id: stream_id }
100
98
  end
101
99
  streams || []
@@ -123,7 +121,7 @@ module PgEventstore
123
121
  stream_attrs.compact!
124
122
  sql = stream_attrs.map do |attr, _|
125
123
  "#{to_table_name}.#{attr} = ?"
126
- end.join(" AND ")
124
+ end.join(' AND ')
127
125
  @sql_builder.where_or(sql, *stream_attrs.values)
128
126
  end
129
127
 
@@ -133,8 +131,8 @@ module PgEventstore
133
131
  return if event_types.empty?
134
132
 
135
133
  sql = event_types.size.times.map do
136
- "?"
137
- end.join(", ")
134
+ '?'
135
+ end.join(', ')
138
136
  @sql_builder.where("#{to_table_name}.type IN (#{sql})", *event_types)
139
137
  end
140
138
 
@@ -178,9 +176,11 @@ module PgEventstore
178
176
 
179
177
  # @param table_name [String] system stream view name
180
178
  # @return [void]
179
+ # rubocop:disable Naming/AccessorMethodName
181
180
  def set_source(table_name)
182
- @sql_builder.from(%{ "#{PG::Connection.escape(table_name)}" #{to_table_name} })
181
+ @sql_builder.from(%( "#{PG::Connection.escape(table_name)}" #{to_table_name} ))
183
182
  end
183
+ # rubocop:enable Naming/AccessorMethodName
184
184
 
185
185
  private
186
186
 
@@ -192,7 +192,7 @@ module PgEventstore
192
192
  { context: String, stream_name: nil, stream_id: nil })
193
193
  return true if result
194
194
 
195
- PgEventstore&.logger&.debug(<<~TEXT)
195
+ PgEventstore.logger&.debug(<<~TEXT)
196
196
  Ignoring unsupported stream filter format for searching #{stream_attrs.compact.inspect}. \
197
197
  See docs/reading_events.md docs for supported formats.
198
198
  TEXT
@@ -13,9 +13,7 @@ module PgEventstore
13
13
  # @return [Array<String>]
14
14
  def extract_event_types_filter(options)
15
15
  options in { filter: { event_types: Array => event_types } }
16
- event_types = event_types&.select do
17
- _1.is_a?(String)
18
- end
16
+ event_types = event_types&.select { _1.is_a?(String) }
19
17
  event_types || []
20
18
  end
21
19
 
@@ -23,9 +21,9 @@ module PgEventstore
23
21
  # @return [Array<Hash[Symbol, String]>]
24
22
  def extract_streams_filter(options)
25
23
  options in { filter: { streams: Array => streams } }
26
- streams = streams&.map do
27
- _1 in { context: String | NilClass => context }
28
- _1 in { stream_name: String | NilClass => stream_name }
24
+ streams = streams&.map do |stream_attrs|
25
+ stream_attrs in { context: String | NilClass => context }
26
+ stream_attrs in { stream_name: String | NilClass => stream_name }
29
27
  { context: context, stream_name: stream_name }
30
28
  end
31
29
  streams || []
@@ -47,7 +45,7 @@ module PgEventstore
47
45
  stream_attrs.compact!
48
46
  sql = stream_attrs.map do |attr, _|
49
47
  "#{to_table_name}.#{attr} = ?"
50
- end.join(" AND ")
48
+ end.join(' AND ')
51
49
  @sql_builder.where_or(sql, *stream_attrs.values)
52
50
  end
53
51
 
@@ -72,7 +70,7 @@ module PgEventstore
72
70
  result = (stream_attrs in { context: String, stream_name: String } | { context: String, stream_name: nil })
73
71
  return true if result
74
72
 
75
- PgEventstore&.logger&.debug(<<~TEXT)
73
+ PgEventstore.logger&.debug(<<~TEXT)
76
74
  Ignoring unsupported stream filter format for grouped read #{stream_attrs.compact.inspect}. \
77
75
  See docs/reading_events.md docs for supported formats.
78
76
  TEXT
@@ -27,9 +27,7 @@ RSpec::Matchers.define :has_option do |option_name|
27
27
  is_correct &&=
28
28
  RSpec::Matchers::BuiltIn::Match.new(@default_value).matches?(obj.class.allocate.public_send(option_name))
29
29
  end
30
- if defined?(@metadata)
31
- is_correct &&= RSpec::Matchers::BuiltIn::Match.new(@metadata).matches?(option.metadata)
32
- end
30
+ is_correct &&= RSpec::Matchers::BuiltIn::Match.new(@metadata).matches?(option.metadata) if defined?(@metadata)
33
31
  is_correct
34
32
  end
35
33
 
@@ -42,23 +40,24 @@ RSpec::Matchers.define :has_option do |option_name|
42
40
  message = "Expected #{obj.class} to have `#{option_name.inspect}' option"
43
41
  message += " #{default_value_message}," if defined?(@default_value)
44
42
  message += " #{metadata_message}," if defined?(@metadata)
45
- message += "," unless defined?(@metadata) || defined?(@default_value)
43
+ message += ',' unless defined?(@metadata) || defined?(@default_value)
46
44
  if option_presence
47
45
  actual_default_value = obj.class.allocate.public_send(option_name)
48
46
  actual_metadata = option.metadata
49
47
  default_value_matches = RSpec::Matchers::BuiltIn::Match.new(@default_value).matches?(actual_default_value)
50
48
  metadata_matches = RSpec::Matchers::BuiltIn::Match.new(@metadata).matches?(actual_metadata)
51
49
 
52
- case [default_value_matches, metadata_matches]
53
- when [false, true]
54
- message += " but default value is #{actual_default_value.inspect}"
55
- when [true, false]
56
- message += " but metadata is #{actual_metadata.inspect}"
57
- else
58
- message += " but default value is #{actual_default_value.inspect} and metadata is #{actual_metadata.inspect}"
59
- end
50
+ message +=
51
+ case [default_value_matches, metadata_matches]
52
+ when [false, true]
53
+ " but default value is #{actual_default_value.inspect}"
54
+ when [true, false]
55
+ " but metadata is #{actual_metadata.inspect}"
56
+ else
57
+ " but default value is #{actual_default_value.inspect} and metadata is #{actual_metadata.inspect}"
58
+ end
60
59
  else
61
- message += " but there is no option found with the given name"
60
+ message += ' but there is no option found with the given name'
62
61
  end
63
62
  message
64
63
  end
@@ -20,11 +20,12 @@ module PgEventstore
20
20
  def clean_up_data
21
21
  tables_to_purge = PgEventstore.connection.with do |conn|
22
22
  conn.exec(<<~SQL)
23
- SELECT tablename
24
- FROM pg_catalog.pg_tables
23
+ SELECT tablename
24
+ FROM pg_catalog.pg_tables
25
25
  WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND tablename != 'migrations'
26
26
  SQL
27
- end.map { |attrs| attrs['tablename'] }
27
+ end
28
+ tables_to_purge = tables_to_purge.map { |attrs| attrs['tablename'] }
28
29
  tables_to_purge.each do |table_name|
29
30
  PgEventstore.connection.with { |c| c.exec("DELETE FROM #{table_name}") }
30
31
  end
@@ -14,6 +14,13 @@ module PgEventstore
14
14
  end
15
15
  end
16
16
 
17
+ # @return [Array<Object>] sql positional values
18
+ attr_reader :positional_values
19
+ # @return [Integer]
20
+ attr_writer :positional_values_size
21
+
22
+ protected :positional_values, :positional_values_size=
23
+
17
24
  def initialize
18
25
  @select_values = []
19
26
  @from_value = nil
@@ -134,17 +141,6 @@ module PgEventstore
134
141
 
135
142
  protected
136
143
 
137
- # @return [Array<Object>] sql positional values
138
- def positional_values
139
- @positional_values
140
- end
141
-
142
- # @param val [Integer]
143
- # @return [Integer]
144
- def positional_values_size=(val)
145
- @positional_values_size = val
146
- end
147
-
148
144
  # @return [Array<String, Array<Object>>]
149
145
  def _to_exec_params
150
146
  return [single_query_sql, @positional_values] if @union_values.empty?
@@ -196,7 +192,7 @@ module PgEventstore
196
192
 
197
193
  # @return [String]
198
194
  def join_sql
199
- @join_values.map { |sql, args| extract_positional_args(sql, *args) }.join(" ")
195
+ @join_values.map { |sql, args| extract_positional_args(sql, *args) }.join(' ')
200
196
  end
201
197
 
202
198
  # @return [String]
@@ -208,7 +204,7 @@ module PgEventstore
208
204
  # @param sql [String]
209
205
  # @return [String]
210
206
  def extract_positional_args(sql, *arguments)
211
- sql.gsub("?").each_with_index do |_, index|
207
+ sql.gsub('?').each_with_index do |_, index|
212
208
  @positional_values.push(arguments[index])
213
209
  @positional_values_size += 1
214
210
  "$#{@positional_values_size}"
@@ -83,20 +83,20 @@ module PgEventstore
83
83
  to_hash.hash
84
84
  end
85
85
 
86
- # @param another [Object]
86
+ # @param other [Object]
87
87
  # @return [Boolean]
88
- def eql?(another)
89
- return false unless another.is_a?(Stream)
88
+ def eql?(other)
89
+ return false unless other.is_a?(Stream)
90
90
 
91
- hash == another.hash
91
+ hash == other.hash
92
92
  end
93
93
 
94
- # @param other_stream [Object]
94
+ # @param other [Object]
95
95
  # @return [Boolean]
96
- def ==(other_stream)
97
- return false unless other_stream.is_a?(Stream)
96
+ def ==(other)
97
+ return false unless other.is_a?(Stream)
98
98
 
99
- to_hash == other_stream.to_hash
99
+ to_hash == other.to_hash
100
100
  end
101
101
  end
102
102
  end
@@ -184,6 +184,7 @@ module PgEventstore
184
184
  halt = true
185
185
  end
186
186
  break if halt
187
+
187
188
  sleep 0.1
188
189
  end
189
190
  end
@@ -223,7 +224,7 @@ module PgEventstore
223
224
 
224
225
  # @param state [Symbol]
225
226
  # @return [Object, nil] a result of evaluating of passed block
226
- def within_state(state, &blk)
227
+ def within_state(state, &_blk)
227
228
  synchronize do
228
229
  return unless @state.public_send("#{RunnerState::STATES.fetch(state)}?")
229
230
 
@@ -247,8 +248,8 @@ module PgEventstore
247
248
 
248
249
  private
249
250
 
250
- def synchronize
251
- @mutex.synchronize { yield }
251
+ def synchronize(&blk)
252
+ @mutex.synchronize(&blk)
252
253
  end
253
254
 
254
255
  # @return [void]
@@ -35,7 +35,7 @@ module PgEventstore
35
35
  def attach_runner_callbacks
36
36
  @basic_runner.define_callback(
37
37
  :process_async, :before,
38
- CommandsHandlerHandlers.setup_handler(:process_feeder_commands, @config_name, @subscription_feeder)
38
+ CommandsHandlerHandlers.setup_handler(:process_feeder_commands, @config_name, @subscription_feeder)
39
39
  )
40
40
  @basic_runner.define_callback(
41
41
  :process_async, :before,
@@ -28,7 +28,7 @@ module PgEventstore
28
28
  # @param raw_events [Array<Hash>]
29
29
  # @return [void]
30
30
  def feed(raw_events)
31
- raise EmptyChunkFedError.new("Empty chunk was fed!") if raw_events.empty?
31
+ raise EmptyChunkFedError.new('Empty chunk was fed!') if raw_events.empty?
32
32
 
33
33
  within_state(:running) do
34
34
  callbacks.run_callbacks(:feed, Utils.original_global_position(raw_events.last))
@@ -18,9 +18,11 @@ module PgEventstore
18
18
  module ClassMethods
19
19
  # @param data [Hash]
20
20
  # @return [Hash]
21
+ # rubocop:disable Lint/UnusedMethodArgument
21
22
  def parse_data(data)
22
23
  {}
23
24
  end
25
+ # rubocop:enable Lint/UnusedMethodArgument
24
26
  end
25
27
 
26
28
  # @return [Integer]
@@ -28,20 +30,20 @@ module PgEventstore
28
30
  options_hash.hash
29
31
  end
30
32
 
31
- # @param another [Object]
33
+ # @param other [Object]
32
34
  # @return [Boolean]
33
- def eql?(another)
34
- return false unless another.is_a?(self.class)
35
+ def eql?(other)
36
+ return false unless other.is_a?(self.class)
35
37
 
36
- hash == another.hash
38
+ hash == other.hash
37
39
  end
38
40
 
39
- # @param another [Object]
41
+ # @param other [Object]
40
42
  # @return [Boolean]
41
- def ==(another)
42
- return false unless another.is_a?(self.class)
43
+ def ==(other)
44
+ return false unless other.is_a?(self.class)
43
45
 
44
- options_hash == another.options_hash
46
+ options_hash == other.options_hash
45
47
  end
46
48
  end
47
49
  end
@@ -20,8 +20,17 @@ module PgEventstore
20
20
  # @return [PgEventstore::SubscriptionRunnerCommands::Base]
21
21
  def find_or_create_by(subscription_id:, subscriptions_set_id:, command_name:, data:)
22
22
  transaction_queries.transaction do
23
- find_by(subscription_id: subscription_id, subscriptions_set_id: subscriptions_set_id, command_name: command_name) ||
24
- create(subscription_id: subscription_id, subscriptions_set_id: subscriptions_set_id, command_name: command_name, data: data)
23
+ existing = find_by(
24
+ subscription_id: subscription_id, subscriptions_set_id: subscriptions_set_id, command_name: command_name
25
+ )
26
+ next existing if existing
27
+
28
+ create(
29
+ subscription_id: subscription_id,
30
+ subscriptions_set_id: subscriptions_set_id,
31
+ command_name: command_name,
32
+ data: data
33
+ )
25
34
  end
26
35
  end
27
36
 
@@ -30,18 +39,15 @@ module PgEventstore
30
39
  # @param command_name [String]
31
40
  # @return [PgEventstore::SubscriptionRunnerCommands::Base, nil]
32
41
  def find_by(subscription_id:, subscriptions_set_id:, command_name:)
33
- sql_builder =
34
- SQLBuilder.new.
35
- select('*').
36
- from('subscription_commands').
37
- where(
38
- 'subscription_id = ? AND subscriptions_set_id = ? AND name = ?',
39
- subscription_id, subscriptions_set_id, command_name
40
- )
42
+ sql_builder = SQLBuilder.new.select('*').from('subscription_commands')
43
+ sql_builder.where(
44
+ 'subscription_id = ? AND subscriptions_set_id = ? AND name = ?',
45
+ subscription_id, subscriptions_set_id, command_name
46
+ )
41
47
  pg_result = connection.with do |conn|
42
48
  conn.exec_params(*sql_builder.to_exec_params)
43
49
  end
44
- return if pg_result.ntuples.zero?
50
+ return if pg_result.ntuples == 0
45
51
 
46
52
  deserialize(pg_result.to_a.first)
47
53
  end
@@ -53,7 +59,7 @@ module PgEventstore
53
59
  # @return [PgEventstore::SubscriptionRunnerCommands::Base]
54
60
  def create(subscription_id:, subscriptions_set_id:, command_name:, data:)
55
61
  sql = <<~SQL
56
- INSERT INTO subscription_commands (name, subscription_id, subscriptions_set_id, data)
62
+ INSERT INTO subscription_commands (name, subscription_id, subscriptions_set_id, data)
57
63
  VALUES ($1, $2, $3, $4)
58
64
  RETURNING *
59
65
  SQL
@@ -69,15 +75,11 @@ module PgEventstore
69
75
  def find_commands(subscription_ids, subscriptions_set_id:)
70
76
  return [] if subscription_ids.empty?
71
77
 
72
- sql = subscription_ids.size.times.map do
73
- "?"
74
- end.join(", ")
75
- sql_builder =
76
- SQLBuilder.new.select('*').
77
- from('subscription_commands').
78
- where("subscription_id IN (#{sql})", *subscription_ids).
79
- where("subscriptions_set_id = ?", subscriptions_set_id).
80
- order('id ASC')
78
+ sql = subscription_ids.size.times.map { '?' }.join(', ')
79
+ sql_builder = SQLBuilder.new.select('*').from('subscription_commands')
80
+ sql_builder.where("subscription_id IN (#{sql})", *subscription_ids)
81
+ sql_builder.where('subscriptions_set_id = ?', subscriptions_set_id)
82
+ sql_builder.order('id ASC')
81
83
  pg_result = connection.with do |conn|
82
84
  conn.exec_params(*sql_builder.to_exec_params)
83
85
  end
@@ -28,7 +28,7 @@ module PgEventstore
28
28
  pg_result = connection.with do |conn|
29
29
  conn.exec_params(*builder.to_exec_params)
30
30
  end
31
- return if pg_result.ntuples.zero?
31
+ return if pg_result.ntuples == 0
32
32
 
33
33
  deserialize(pg_result.to_a.first)
34
34
  end
@@ -40,7 +40,7 @@ module PgEventstore
40
40
  pg_result = connection.with do |conn|
41
41
  conn.exec_params(*builder.to_exec_params)
42
42
  end
43
- return [] if pg_result.ntuples.zero?
43
+ return [] if pg_result.ntuples == 0
44
44
 
45
45
  pg_result.map(&method(:deserialize))
46
46
  end
@@ -50,24 +50,25 @@ module PgEventstore
50
50
  def set_collection(state = nil)
51
51
  builder = SQLBuilder.new.from('subscriptions').select('set').group('set').order('set ASC')
52
52
  builder.where('state = ?', state) if state
53
- connection.with do |conn|
53
+ raw_subscriptions = connection.with do |conn|
54
54
  conn.exec_params(*builder.to_exec_params)
55
- end.map { |attrs| attrs['set'] }
55
+ end
56
+ raw_subscriptions.map { |attrs| attrs['set'] }
56
57
  end
57
58
 
58
59
  # @param id [Integer]
59
60
  # @return [Hash]
60
61
  # @raise [PgEventstore::RecordNotFound]
61
62
  def find!(id)
62
- find_by(id: id) || raise(RecordNotFound.new("subscriptions", id))
63
+ find_by(id: id) || raise(RecordNotFound.new('subscriptions', id))
63
64
  end
64
65
 
65
66
  # @param attrs [Hash]
66
67
  # @return [Hash]
67
68
  def create(attrs)
68
69
  sql = <<~SQL
69
- INSERT INTO subscriptions (#{attrs.keys.join(', ')})
70
- VALUES (#{Utils.positional_vars(attrs.values)})
70
+ INSERT INTO subscriptions (#{attrs.keys.join(', ')})
71
+ VALUES (#{Utils.positional_vars(attrs.values)})
71
72
  RETURNING *
72
73
  SQL
73
74
  pg_result = connection.with do |conn|
@@ -93,13 +94,14 @@ module PgEventstore
93
94
  pg_result = connection.with do |conn|
94
95
  conn.exec_params(sql, [*attrs.values, id])
95
96
  end
96
- raise(RecordNotFound.new("subscriptions", id)) if pg_result.ntuples.zero?
97
+ raise(RecordNotFound.new('subscriptions', id)) if pg_result.ntuples == 0
97
98
 
98
99
  updated_attrs = pg_result.to_a.first
99
100
  unless updated_attrs['locked_by'] == locked_by
100
101
  # Subscription is force-locked by someone else. We have to roll back such transaction
101
102
  raise(WrongLockIdError.new(updated_attrs['set'], updated_attrs['name'], updated_attrs['locked_by']))
102
103
  end
104
+
103
105
  updated_attrs
104
106
  end
105
107
 
@@ -152,6 +154,7 @@ module PgEventstore
152
154
  if attrs[:locked_by] && !force
153
155
  raise SubscriptionAlreadyLockedError.new(attrs[:set], attrs[:name], attrs[:locked_by])
154
156
  end
157
+
155
158
  connection.with do |conn|
156
159
  conn.exec_params('UPDATE subscriptions SET locked_by = $1 WHERE id = $2', [lock_id, id])
157
160
  end
@@ -28,15 +28,12 @@ module PgEventstore
28
28
  # @param command_name [String]
29
29
  # @return [PgEventstore::SubscriptionFeederCommands::Base, nil]
30
30
  def find_by(subscriptions_set_id:, command_name:)
31
- sql_builder =
32
- SQLBuilder.new.
33
- select('*').
34
- from('subscriptions_set_commands').
35
- where('subscriptions_set_id = ? AND name = ?', subscriptions_set_id, command_name)
31
+ sql_builder = SQLBuilder.new.select('*').from('subscriptions_set_commands')
32
+ sql_builder.where('subscriptions_set_id = ? AND name = ?', subscriptions_set_id, command_name)
36
33
  pg_result = connection.with do |conn|
37
34
  conn.exec_params(*sql_builder.to_exec_params)
38
35
  end
39
- return if pg_result.ntuples.zero?
36
+ return if pg_result.ntuples == 0
40
37
 
41
38
  deserialize(pg_result.to_a.first)
42
39
  end
@@ -47,7 +44,7 @@ module PgEventstore
47
44
  # @return [PgEventstore::SubscriptionFeederCommands::Base]
48
45
  def create(subscriptions_set_id:, command_name:, data:)
49
46
  sql = <<~SQL
50
- INSERT INTO subscriptions_set_commands (name, subscriptions_set_id, data)
47
+ INSERT INTO subscriptions_set_commands (name, subscriptions_set_id, data)
51
48
  VALUES ($1, $2, $3)
52
49
  RETURNING *
53
50
  SQL
@@ -56,17 +53,15 @@ module PgEventstore
56
53
  end
57
54
  deserialize(pg_result.to_a.first)
58
55
  rescue PG::ForeignKeyViolation
59
- raise RecordNotFound.new("subscriptions_set", subscriptions_set_id)
56
+ raise RecordNotFound.new('subscriptions_set', subscriptions_set_id)
60
57
  end
61
58
 
62
59
  # @param subscriptions_set_id [Integer, nil]
63
60
  # @return [Array<PgEventstore::SubscriptionFeederCommands::Base>]
64
61
  def find_commands(subscriptions_set_id)
65
- sql_builder =
66
- SQLBuilder.new.select('*').
67
- from('subscriptions_set_commands').
68
- where("subscriptions_set_id = ?", subscriptions_set_id).
69
- order('id ASC')
62
+ sql_builder = SQLBuilder.new.select('*').from('subscriptions_set_commands')
63
+ sql_builder.where('subscriptions_set_id = ?', subscriptions_set_id)
64
+ sql_builder.order('id ASC')
70
65
  pg_result = connection.with do |conn|
71
66
  conn.exec_params(*sql_builder.to_exec_params)
72
67
  end
@@ -46,9 +46,10 @@ module PgEventstore
46
46
  def set_names
47
47
  builder = SQLBuilder.new.select('name').from('subscriptions_set').group('name').order('name ASC')
48
48
 
49
- connection.with do |conn|
49
+ raw_set = connection.with do |conn|
50
50
  conn.exec_params(*builder.to_exec_params)
51
- end.map { |attrs| attrs['name'] }
51
+ end
52
+ raw_set.map { |attrs| attrs['name'] }
52
53
  end
53
54
 
54
55
  # The same as #find_all, but returns first result
@@ -61,15 +62,15 @@ module PgEventstore
61
62
  # @return [Hash]
62
63
  # @raise [PgEventstore::RecordNotFound]
63
64
  def find!(id)
64
- find_by(id: id) || raise(RecordNotFound.new("subscriptions_set", id))
65
+ find_by(id: id) || raise(RecordNotFound.new('subscriptions_set', id))
65
66
  end
66
67
 
67
68
  # @param attrs [Hash]
68
69
  # @return [Hash]
69
70
  def create(attrs)
70
71
  sql = <<~SQL
71
- INSERT INTO subscriptions_set (#{attrs.keys.join(', ')})
72
- VALUES (#{Utils.positional_vars(attrs.values)})
72
+ INSERT INTO subscriptions_set (#{attrs.keys.join(', ')})
73
+ VALUES (#{Utils.positional_vars(attrs.values)})
73
74
  RETURNING *
74
75
  SQL
75
76
  pg_result = connection.with do |conn|
@@ -92,7 +93,7 @@ module PgEventstore
92
93
  pg_result = connection.with do |conn|
93
94
  conn.exec_params(sql, [*attrs.values, id])
94
95
  end
95
- raise(RecordNotFound.new("subscriptions_set", id)) if pg_result.ntuples.zero?
96
+ raise(RecordNotFound.new('subscriptions_set', id)) if pg_result.ntuples == 0
96
97
 
97
98
  deserialize(pg_result.to_a.first)
98
99
  end
@@ -17,9 +17,10 @@ module PgEventstore
17
17
  end
18
18
 
19
19
  def recovers?(error)
20
- EXCEPTIONS_TO_HANDLE.any? {error.is_a?(_1) }
20
+ EXCEPTIONS_TO_HANDLE.any? { error.is_a?(_1) }
21
21
  end
22
22
 
23
+ # rubocop:disable Lint/SuppressedException
23
24
  def recover(_error)
24
25
  loop do
25
26
  sleep TIME_BETWEEN_RETRIES
@@ -32,6 +33,7 @@ module PgEventstore
32
33
  rescue *EXCEPTIONS_TO_HANDLE
33
34
  end
34
35
  end
36
+ # rubocop:enable Lint/SuppressedException
35
37
 
36
38
  private
37
39
 
@@ -21,6 +21,7 @@ module PgEventstore
21
21
 
22
22
  def recover(error)
23
23
  return false if @restart_terminator&.call(@subscription.dup)
24
+
24
25
  if @subscription.restart_count >= @subscription.max_restarts_number
25
26
  @failed_subscription_notifier&.call(@subscription.dup, Utils.unwrap_exception(error))
26
27
  return false