pg_eventstore 1.11.0 → 1.13.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/docs/reading_events.md +98 -0
  4. data/lib/pg_eventstore/cli/commands/base_command.rb +2 -0
  5. data/lib/pg_eventstore/cli/commands/callback_handlers/start_cmd_handlers.rb +1 -0
  6. data/lib/pg_eventstore/cli/commands/help_command.rb +1 -0
  7. data/lib/pg_eventstore/cli/commands/start_subscriptions_command.rb +3 -1
  8. data/lib/pg_eventstore/cli/commands/stop_subscriptions_command.rb +1 -0
  9. data/lib/pg_eventstore/cli/exit_codes.rb +1 -0
  10. data/lib/pg_eventstore/cli/parser_options/base_options.rb +1 -0
  11. data/lib/pg_eventstore/cli/parser_options/default_options.rb +1 -0
  12. data/lib/pg_eventstore/cli/parser_options/metadata.rb +1 -0
  13. data/lib/pg_eventstore/cli/parser_options/subscription_options.rb +1 -0
  14. data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +2 -1
  15. data/lib/pg_eventstore/cli/try_unlock_subscriptions_set.rb +1 -0
  16. data/lib/pg_eventstore/cli/wait_for_subscriptions_set_shutdown.rb +1 -0
  17. data/lib/pg_eventstore/client.rb +22 -4
  18. data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +69 -0
  19. data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +31 -0
  20. data/lib/pg_eventstore/commands.rb +2 -0
  21. data/lib/pg_eventstore/connection.rb +8 -3
  22. data/lib/pg_eventstore/extensions/callback_handlers_extension.rb +1 -0
  23. data/lib/pg_eventstore/partition.rb +23 -0
  24. data/lib/pg_eventstore/pg_connection.rb +1 -0
  25. data/lib/pg_eventstore/queries/event_queries.rb +18 -0
  26. data/lib/pg_eventstore/queries/partition_queries.rb +21 -0
  27. data/lib/pg_eventstore/queries.rb +2 -0
  28. data/lib/pg_eventstore/query_builders/basic_filtering.rb +27 -0
  29. data/lib/pg_eventstore/query_builders/events_filtering.rb +47 -31
  30. data/lib/pg_eventstore/query_builders/partitions_filtering.rb +83 -0
  31. data/lib/pg_eventstore/sql_builder.rb +10 -0
  32. data/lib/pg_eventstore/subscriptions/basic_runner.rb +122 -35
  33. data/lib/pg_eventstore/subscriptions/callback_handlers/commands_handler_handlers.rb +1 -14
  34. data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +4 -3
  35. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +1 -14
  36. data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +1 -19
  37. data/lib/pg_eventstore/subscriptions/command_handlers/subscription_feeder_commands.rb +1 -0
  38. data/lib/pg_eventstore/subscriptions/command_handlers/subscription_runners_commands.rb +1 -0
  39. data/lib/pg_eventstore/subscriptions/commands_handler.rb +5 -8
  40. data/lib/pg_eventstore/subscriptions/events_processor.rb +7 -2
  41. data/lib/pg_eventstore/subscriptions/extensions/base_command_extension.rb +1 -0
  42. data/lib/pg_eventstore/subscriptions/extensions/command_class_lookup_extension.rb +1 -0
  43. data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +1 -9
  44. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_connection.rb +44 -0
  45. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_feeder.rb +27 -0
  46. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_runner.rb +34 -0
  47. data/lib/pg_eventstore/subscriptions/runner_recovery_strategies.rb +5 -0
  48. data/lib/pg_eventstore/subscriptions/runner_recovery_strategy.rb +21 -0
  49. data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +18 -5
  50. data/lib/pg_eventstore/subscriptions/subscription_runner.rb +1 -13
  51. data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +1 -0
  52. data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +20 -3
  53. data/lib/pg_eventstore/subscriptions/subscriptions_set_lifecycle.rb +1 -0
  54. data/lib/pg_eventstore/utils.rb +5 -4
  55. data/lib/pg_eventstore/version.rb +1 -1
  56. data/lib/pg_eventstore/web/application.rb +5 -3
  57. data/lib/pg_eventstore.rb +3 -1
  58. data/sig/pg_eventstore/client.rbs +2 -0
  59. data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +16 -0
  60. data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +8 -0
  61. data/sig/pg_eventstore/connection.rbs +2 -0
  62. data/sig/pg_eventstore/partition.rbs +15 -0
  63. data/sig/pg_eventstore/queries/event_queries.rbs +2 -0
  64. data/sig/pg_eventstore/queries/partition_queries.rbs +6 -0
  65. data/sig/pg_eventstore/query_builders/basic_filtering.rbs +15 -0
  66. data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +17 -17
  67. data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +21 -0
  68. data/sig/pg_eventstore/sql_builder.rbs +1 -1
  69. data/sig/pg_eventstore/subscriptions/basic_runner.rbs +26 -10
  70. data/sig/pg_eventstore/subscriptions/callback_handlers/commands_handler_handlers.rbs +5 -5
  71. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +1 -3
  72. data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +0 -4
  73. data/sig/pg_eventstore/subscriptions/commands_handler.rbs +8 -11
  74. data/sig/pg_eventstore/subscriptions/events_processor.rbs +5 -17
  75. data/sig/pg_eventstore/subscriptions/runner_recovery_strategies/restore_connection.rbs +18 -0
  76. data/sig/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_feeder.rbs +11 -0
  77. data/sig/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_runner.rbs +17 -0
  78. data/sig/pg_eventstore/subscriptions/runner_recovery_strategy.rbs +7 -0
  79. data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +6 -8
  80. data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +6 -35
  81. data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +8 -0
  82. metadata +22 -6
@@ -13,10 +13,15 @@ module PgEventstore
13
13
  # @param handler [#call]
14
14
  # @param graceful_shutdown_timeout [Integer, Float] seconds. Determines how long to wait before force-shutdown
15
15
  # the runner when stopping it using #stop_async
16
- def initialize(handler, graceful_shutdown_timeout:)
16
+ # @param recovery_strategies [Array<PgEventstore::RunnerRecoveryStrategy>]
17
+ def initialize(handler, graceful_shutdown_timeout:, recovery_strategies: [])
17
18
  @handler = handler
18
19
  @raw_events = []
19
- @basic_runner = BasicRunner.new(0, graceful_shutdown_timeout)
20
+ @basic_runner = BasicRunner.new(
21
+ run_interval: 0,
22
+ async_shutdown_time: graceful_shutdown_timeout,
23
+ recovery_strategies: recovery_strategies
24
+ )
20
25
  attach_runner_callbacks
21
26
  end
22
27
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module PgEventstore
4
4
  module Extensions
5
+ # @!visibility private
5
6
  module BaseCommandExtension
6
7
  def self.included(klass)
7
8
  super
@@ -2,6 +2,7 @@
2
2
 
3
3
  module PgEventstore
4
4
  module Extensions
5
+ # @!visibility private
5
6
  module CommandClassLookupExtension
6
7
  # @param cmd_name [String, Symbol]
7
8
  # @return [Class]
@@ -127,7 +127,7 @@ module PgEventstore
127
127
  def subscriptions_events(query_options)
128
128
  return {} if query_options.empty?
129
129
 
130
- final_builder = union_builders(query_options.map { |id, opts| query_builder(id, opts) })
130
+ final_builder = SQLBuilder.union_builders(query_options.map { |id, opts| query_builder(id, opts) })
131
131
  raw_events = connection.with do |conn|
132
132
  conn.exec_params(*final_builder.to_exec_params)
133
133
  end.to_a
@@ -177,14 +177,6 @@ module PgEventstore
177
177
  builder.select("#{id} as runner_id")
178
178
  end
179
179
 
180
- # @param builders [Array<PgEventstore::SQLBuilder>]
181
- # @return [PgEventstore::SQLBuilder]
182
- def union_builders(builders)
183
- builders[1..].each_with_object(builders[0]) do |builder, first_builder|
184
- first_builder.union(builder)
185
- end
186
- end
187
-
188
180
  # @return [PgEventstore::TransactionQueries]
189
181
  def transaction_queries
190
182
  TransactionQueries.new(connection)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module RunnerRecoveryStrategies
5
+ # @!visibility private
6
+ class RestoreConnection
7
+ # @return [Integer] seconds
8
+ TIME_BETWEEN_RETRIES = 5
9
+ # @return [Array<StandardError>]
10
+ EXCEPTIONS_TO_HANDLE = [PG::ConnectionBad, PG::UnableToSend, ConnectionPool::TimeoutError].freeze
11
+
12
+ include RunnerRecoveryStrategy
13
+
14
+ # @param config_name [Symbol]
15
+ def initialize(config_name)
16
+ @config_name = config_name
17
+ end
18
+
19
+ def recovers?(error)
20
+ EXCEPTIONS_TO_HANDLE.any? {error.is_a?(_1) }
21
+ end
22
+
23
+ def recover(_error)
24
+ loop do
25
+ sleep TIME_BETWEEN_RETRIES
26
+
27
+ connection.with do |conn|
28
+ conn.exec('select version()')
29
+ # No error was raised during the request. We are good to recover!
30
+ return true
31
+ end
32
+ rescue *EXCEPTIONS_TO_HANDLE
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ # @return [PgEventstore::Connection]
39
+ def connection
40
+ PgEventstore.connection(@config_name)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module RunnerRecoveryStrategies
5
+ # @!visibility private
6
+ class RestoreSubscriptionFeeder
7
+ include RunnerRecoveryStrategy
8
+
9
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
10
+ def initialize(subscriptions_set_lifecycle:)
11
+ @subscriptions_set_lifecycle = subscriptions_set_lifecycle
12
+ end
13
+
14
+ def recovers?(_error)
15
+ true
16
+ end
17
+
18
+ def recover(_error)
19
+ subscriptions_set = @subscriptions_set_lifecycle.persisted_subscriptions_set
20
+ return false if subscriptions_set.restart_count >= subscriptions_set.max_restarts_number
21
+
22
+ sleep subscriptions_set.time_between_restarts
23
+ true
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ module RunnerRecoveryStrategies
5
+ # @!visibility private
6
+ class RestoreSubscriptionRunner
7
+ include RunnerRecoveryStrategy
8
+
9
+ # @param subscription [PgEventstore::Subscription]
10
+ # @param restart_terminator [#call, nil]
11
+ # @param failed_subscription_notifier [#call, nil]
12
+ def initialize(subscription:, restart_terminator:, failed_subscription_notifier:)
13
+ @subscription = subscription
14
+ @restart_terminator = restart_terminator
15
+ @failed_subscription_notifier = failed_subscription_notifier
16
+ end
17
+
18
+ def recovers?(error)
19
+ error.is_a?(WrappedException)
20
+ end
21
+
22
+ def recover(error)
23
+ return false if @restart_terminator&.call(@subscription.dup)
24
+ if @subscription.restart_count >= @subscription.max_restarts_number
25
+ @failed_subscription_notifier&.call(@subscription.dup, Utils.unwrap_exception(error))
26
+ return false
27
+ end
28
+
29
+ sleep @subscription.time_between_restarts
30
+ true
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'runner_recovery_strategies/restore_connection'
4
+ require_relative 'runner_recovery_strategies/restore_subscription_runner'
5
+ require_relative 'runner_recovery_strategies/restore_subscription_feeder'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgEventstore
4
+ # Defines an interface of a recovery strategy of the BasicRunner.
5
+ # See {PgEventstore::BasicRunner} for an example of usage.
6
+ module RunnerRecoveryStrategy
7
+ # Determines whether this strategy can recover from the error. If multiple strategies can recover from the error,
8
+ # the first one from the :recovery_strategies array is selected.
9
+ # @param error [StandardError]
10
+ # @return [Boolean]
11
+ def recovers?(error)
12
+ end
13
+
14
+ # Actual implementation of recovery strategy. Usually you want to implement here a logic that restores from the
15
+ # error. The returned boolean value will be used to determine whether the runner should be restarted.
16
+ # @param error [StandardError]
17
+ # @return [Boolean]
18
+ def recover(error)
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,7 @@
3
3
  module PgEventstore
4
4
  # This class is responsible for starting/stopping all SubscriptionRunners. The background runner of it is responsible
5
5
  # for events pulling and feeding those SubscriptionRunners.
6
+ # @!visibility private
6
7
  class SubscriptionFeeder
7
8
  extend Forwardable
8
9
 
@@ -15,7 +16,11 @@ module PgEventstore
15
16
  # @param subscriptions_lifecycle [PgEventstore::SubscriptionsLifecycle]
16
17
  def initialize(config_name:, subscriptions_set_lifecycle:, subscriptions_lifecycle:)
17
18
  @config_name = config_name
18
- @basic_runner = BasicRunner.new(0.2, 0)
19
+ @basic_runner = BasicRunner.new(
20
+ run_interval: 0.2,
21
+ async_shutdown_time: 0,
22
+ recovery_strategies: recovery_strategies(config_name, subscriptions_set_lifecycle)
23
+ )
19
24
  @subscriptions_set_lifecycle = subscriptions_set_lifecycle
20
25
  @subscriptions_lifecycle = subscriptions_lifecycle
21
26
  @commands_handler = CommandsHandler.new(@config_name, self, @subscriptions_lifecycle.runners)
@@ -71,10 +76,6 @@ module PgEventstore
71
76
  :after_runner_died, :before,
72
77
  SubscriptionFeederHandlers.setup_handler(:persist_error_info, @subscriptions_set_lifecycle)
73
78
  )
74
- @basic_runner.define_callback(
75
- :after_runner_died, :before,
76
- SubscriptionFeederHandlers.setup_handler(:restart_runner, @subscriptions_set_lifecycle, @basic_runner)
77
- )
78
79
 
79
80
  @basic_runner.define_callback(
80
81
  :process_async, :before,
@@ -107,5 +108,17 @@ module PgEventstore
107
108
  SubscriptionFeederHandlers.setup_handler(:update_subscriptions_set_restarts, @subscriptions_set_lifecycle)
108
109
  )
109
110
  end
111
+
112
+ # @param config_name [Symbol]
113
+ # @param subscriptions_set_lifecycle [PgEventstore::SubscriptionsSetLifecycle]
114
+ # @return [Array<PgEventstore::RunnerRecoveryStrategy>]
115
+ def recovery_strategies(config_name, subscriptions_set_lifecycle)
116
+ [
117
+ RunnerRecoveryStrategies::RestoreConnection.new(config_name),
118
+ RunnerRecoveryStrategies::RestoreSubscriptionFeeder.new(
119
+ subscriptions_set_lifecycle: subscriptions_set_lifecycle
120
+ ),
121
+ ]
122
+ end
110
123
  end
111
124
  end
@@ -28,15 +28,10 @@ module PgEventstore
28
28
  # @param stats [PgEventstore::SubscriptionHandlerPerformance]
29
29
  # @param events_processor [PgEventstore::EventsProcessor]
30
30
  # @param subscription [PgEventstore::Subscription]
31
- # @param restart_terminator [#call, nil]
32
- # @param failed_subscription_notifier [#call, nil]
33
- def initialize(stats:, events_processor:, subscription:, restart_terminator: nil,
34
- failed_subscription_notifier: nil)
31
+ def initialize(stats:, events_processor:, subscription:)
35
32
  @stats = stats
36
33
  @events_processor = events_processor
37
34
  @subscription = subscription
38
- @restart_terminator = restart_terminator
39
- @failed_subscription_notifier = failed_subscription_notifier
40
35
 
41
36
  attach_callbacks
42
37
  end
@@ -87,13 +82,6 @@ module PgEventstore
87
82
  :error, :after,
88
83
  SubscriptionRunnerHandlers.setup_handler(:update_subscription_error, @subscription)
89
84
  )
90
- @events_processor.define_callback(
91
- :error, :after,
92
- SubscriptionRunnerHandlers.setup_handler(
93
- :restart_events_processor,
94
- @subscription, @restart_terminator, @failed_subscription_notifier, @events_processor
95
- )
96
- )
97
85
 
98
86
  @events_processor.define_callback(
99
87
  :feed, :after,
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgEventstore
4
+ # @!visibility private
4
5
  class SubscriptionsLifecycle
5
6
  extend Forwardable
6
7
 
@@ -3,6 +3,8 @@
3
3
  require 'forwardable'
4
4
  require_relative 'runner_state'
5
5
  require_relative 'basic_runner'
6
+ require_relative 'runner_recovery_strategy'
7
+ require_relative 'runner_recovery_strategies'
6
8
  require_relative 'subscription'
7
9
  require_relative 'events_processor'
8
10
  require_relative 'subscription_handler_performance'
@@ -102,11 +104,11 @@ module PgEventstore
102
104
  runner = SubscriptionRunner.new(
103
105
  stats: SubscriptionHandlerPerformance.new,
104
106
  events_processor: EventsProcessor.new(
105
- create_raw_event_handler(middlewares, handler), graceful_shutdown_timeout: graceful_shutdown_timeout
107
+ create_raw_event_handler(middlewares, handler),
108
+ graceful_shutdown_timeout: graceful_shutdown_timeout,
109
+ recovery_strategies: recovery_strategies(subscription, restart_terminator, failed_subscription_notifier)
106
110
  ),
107
111
  subscription: subscription,
108
- restart_terminator: restart_terminator,
109
- failed_subscription_notifier: failed_subscription_notifier
110
112
  )
111
113
 
112
114
  @subscriptions_lifecycle.runners.push(runner)
@@ -170,5 +172,20 @@ module PgEventstore
170
172
 
171
173
  config.middlewares.slice(*middlewares).values
172
174
  end
175
+
176
+ # @param subscription [PgEventstore::Subscription]
177
+ # @param restart_terminator [#call, nil]
178
+ # @param failed_subscription_notifier [#call, nil]
179
+ # @return [Array<PgEventstore::RunnerRecoveryStrategy>]
180
+ def recovery_strategies(subscription, restart_terminator, failed_subscription_notifier)
181
+ [
182
+ RunnerRecoveryStrategies::RestoreConnection.new(config_name),
183
+ RunnerRecoveryStrategies::RestoreSubscriptionRunner.new(
184
+ subscription: subscription,
185
+ restart_terminator: restart_terminator,
186
+ failed_subscription_notifier: failed_subscription_notifier,
187
+ ),
188
+ ]
189
+ end
173
190
  end
174
191
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgEventstore
4
+ # @!visibility private
4
5
  class SubscriptionsSetLifecycle
5
6
  # @return [Integer] number of seconds between heartbeat updates
6
7
  HEARTBEAT_INTERVAL = 10 # seconds
@@ -85,7 +85,8 @@ module PgEventstore
85
85
  def write_to_file(file_path, content)
86
86
  file = File.open(file_path, "w")
87
87
  file.write(content)
88
- file.close
88
+ ensure
89
+ file&.close
89
90
  end
90
91
 
91
92
  # @param file_path [String]
@@ -99,10 +100,10 @@ module PgEventstore
99
100
  # @return [String, nil]
100
101
  def read_pid(file_path)
101
102
  file = File.open(file_path, "r")
102
- file.readline.strip.tap do
103
- file.close
104
- end
103
+ file.readline.strip
105
104
  rescue Errno::ENOENT
105
+ ensure
106
+ file&.close
106
107
  end
107
108
 
108
109
  # @param exception [StandardError]
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PgEventstore
4
4
  # @return [String]
5
- VERSION = "1.11.0"
5
+ VERSION = "1.13.0"
6
6
  end
@@ -5,6 +5,7 @@ require 'base64'
5
5
 
6
6
  module PgEventstore
7
7
  module Web
8
+ # @!visibility private
8
9
  class Application < Sinatra::Base
9
10
  # @return [Symbol]
10
11
  DEFAULT_ADMIN_UI_CONFIG = :admin_web_ui
@@ -27,7 +28,7 @@ module PgEventstore
27
28
  helpers(Paginator::Helpers, Subscriptions::Helpers) do
28
29
  # @return [Array<Hash>, nil]
29
30
  def streams_filter
30
- params in { filter: { streams: Array => streams } }
31
+ streams = QueryBuilders::EventsFiltering.extract_streams_filter(params)
31
32
  streams&.select { _1 in { context: String, stream_name: String, stream_id: String } }&.map do
32
33
  Hash[_1.reject { |_, value| value == '' }].transform_keys(&:to_sym)
33
34
  end&.reject { _1.empty? }
@@ -41,8 +42,9 @@ module PgEventstore
41
42
 
42
43
  # @return [Array<String>, nil]
43
44
  def events_filter
44
- params in { filter: { events: Array => events } }
45
- events&.select { _1.is_a?(String) && _1 != '' }
45
+ event_filters = { filter: { event_types: params.dig(:filter, :events) } }
46
+ events = QueryBuilders::EventsFiltering.extract_event_types_filter(event_filters)
47
+ events&.reject { _1 == '' }
46
48
  end
47
49
 
48
50
  # @return [Symbol]
data/lib/pg_eventstore.rb CHANGED
@@ -9,6 +9,7 @@ require_relative 'pg_eventstore/extensions/callback_handlers_extension'
9
9
  require_relative 'pg_eventstore/extensions/using_connection_extension'
10
10
  require_relative 'pg_eventstore/event_class_resolver'
11
11
  require_relative 'pg_eventstore/config'
12
+ require_relative 'pg_eventstore/partition'
12
13
  require_relative 'pg_eventstore/event'
13
14
  require_relative 'pg_eventstore/stream'
14
15
  require_relative 'pg_eventstore/commands'
@@ -35,10 +36,11 @@ module PgEventstore
35
36
  # @return [Object] a result of the given block
36
37
  def configure(name: DEFAULT_CONFIG)
37
38
  mutex.synchronize do
38
- @config[name] ||= Config.new(name: name)
39
+ @config[name] = @config[name] ? Config.new(name: name, **@config[name].options_hash) : Config.new(name: name)
39
40
  connection_config_was = @config[name].connection_options
40
41
 
41
42
  yield(@config[name]).tap do
43
+ @config[name].freeze
42
44
  next if connection_config_was == @config[name].connection_options
43
45
 
44
46
  # Reset the connection if user decided to reconfigure connection's options
@@ -26,6 +26,8 @@ module PgEventstore
26
26
  # _@param_ `middlewares` — provide a list of middleware names to override a config's middlewares
27
27
  def read: (PgEventstore::Stream stream, ?options: ::Hash[untyped, untyped], ?middlewares: ::Array[::Symbol]?) -> ::Array[PgEventstore::Event]
28
28
 
29
+ def read_grouped: (Stream stream, ?options: Hash[untyped, untyped], ?middlewares: ::Array[::Symbol]?) -> ::Array[PgEventstore::Event]
30
+
29
31
  # _@param_ `stream`
30
32
  #
31
33
  # _@param_ `options` — request options
@@ -0,0 +1,16 @@
1
+ module PgEventstore
2
+ module Commands
3
+ class AllStreamReadGrouped < AbstractCommand
4
+
5
+ def call: (Stream stream, ?options: ::Hash[untyped, untyped]) -> Array[Event]
6
+
7
+ private
8
+
9
+ def build_filter_options_for_partitions: (Partition partition, Hash[untyped, untyped] options) -> Hash[untyped, untyped]
10
+
11
+ def build_filter_options_for_streams: (Partition partition, Array[String] stream_ids, Hash[untyped, untyped] options) -> Array[Hash[untyped, untyped]]
12
+
13
+ def group_stream_ids: (Hash[untyped, untyped] options) -> Hash[untyped, untyped]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module PgEventstore
2
+ module Commands
3
+ class RegularStreamReadGrouped < AbstractCommand
4
+
5
+ def call: (Stream stream, ?options: ::Hash[untyped, untyped]) -> Array[Event]
6
+ end
7
+ end
8
+ end
@@ -12,6 +12,8 @@ module PgEventstore
12
12
  # _@param_ `pool_timeout` — Connection pool timeout in seconds
13
13
  def initialize: (uri: String, ?pool_size: Integer, ?pool_timeout: Integer) -> void
14
14
 
15
+ def shutdown: -> untyped
16
+
15
17
  def with: () { (PG::Connection connection) -> untyped } -> untyped
16
18
 
17
19
  def init_pool: () -> ConnectionPool[untyped]
@@ -0,0 +1,15 @@
1
+ module PgEventstore
2
+ class Partition
3
+ include Extensions::OptionsExtension
4
+
5
+ attr_accessor id: Integer
6
+
7
+ attr_accessor context: String
8
+
9
+ attr_accessor stream_name: String?
10
+
11
+ attr_accessor event_type: String?
12
+
13
+ attr_accessor table_name: String
14
+ end
15
+ end
@@ -10,6 +10,8 @@ module PgEventstore
10
10
  # _@param_ `event`
11
11
  def event_exists?: (PgEventstore::Event event) -> bool
12
12
 
13
+ def grouped_events: (Stream stream, Array[Hash[untyped, untyped]] options_by_event_type, **untyped options)-> Array[Event]
14
+
13
15
  # _@param_ `events`
14
16
  def ids_from_db: (::Array[PgEventstore::Event] events) -> ::Array[String]
15
17
 
@@ -39,6 +39,8 @@ module PgEventstore
39
39
  # _@return_ — partition attributes
40
40
  def context_partition: (PgEventstore::Stream stream) -> ::Hash[untyped, untyped]?
41
41
 
42
+ def partitions: (Array[Hash[Symbol, String | nil]] stream_filters, Array[String] event_filters)-> Array[Partition]
43
+
42
44
  # _@param_ `stream`
43
45
  #
44
46
  # _@return_ — partition attributes
@@ -70,5 +72,9 @@ module PgEventstore
70
72
 
71
73
  # Returns the value of attribute connection.
72
74
  attr_accessor connection: PgEventstore::Connection
75
+
76
+ private
77
+
78
+ def deserialize: (Hash[untyped, untyped] attrs)-> Partition
73
79
  end
74
80
  end
@@ -0,0 +1,15 @@
1
+ module PgEventstore
2
+ module QueryBuilders
3
+ class BasicFiltering
4
+ @sql_builder: SQLBuilder
5
+
6
+ def initialize: -> void
7
+
8
+ def to_exec_params: -> [String, Array[untyped]]
9
+
10
+ def to_sql_builder: -> SQLBuilder
11
+
12
+ def to_table_name: -> String
13
+ end
14
+ end
15
+ end
@@ -1,39 +1,37 @@
1
1
  module PgEventstore
2
2
  module QueryBuilders
3
3
  # @!visibility private
4
- class EventsFiltering
4
+ class EventsFiltering < BasicFiltering
5
5
  DEFAULT_LIMIT: Integer
6
6
  SQL_DIRECTIONS: Hash[String | Symbol, String]
7
7
  SUBSCRIPTIONS_OPTIONS: ::Array[Symbol]
8
8
 
9
- @sql_builder: PgEventstore::SQLBuilder
9
+ TABLE_NAME: String
10
+
11
+ def self.events_filtering: (Stream stream, ::Hash[untyped, untyped] options) -> EventsFiltering
12
+
13
+ def self.extract_event_types_filter: (Hash[untyped, untyped] options) -> Array[String]
14
+
15
+ def self.extract_streams_filter: (Hash[untyped, untyped] options) -> Array[Hash[untyped, untyped]]
10
16
 
11
- def self.events_filtering: (PgEventstore::Stream stream, ::Hash[untyped, untyped] options) -> PgEventstore::QueryBuilders::EventsFiltering
12
-
13
17
  # _@param_ `options`
14
- def self.subscriptions_events_filtering: (::Hash[untyped, untyped] options) -> PgEventstore::QueryBuilders::EventsFiltering
18
+ def self.subscriptions_events_filtering: (::Hash[untyped, untyped] options) -> EventsFiltering
15
19
 
16
20
  # _@param_ `options`
17
- def self.all_stream_filtering: (::Hash[untyped, untyped] options) -> PgEventstore::QueryBuilders::EventsFiltering
21
+ def self.all_stream_filtering: (::Hash[untyped, untyped] options) -> EventsFiltering
18
22
 
19
23
  # _@param_ `stream`
20
24
  #
21
25
  # _@param_ `options`
22
- def self.specific_stream_filtering: (PgEventstore::Stream stream, ::Hash[untyped, untyped] options) -> PgEventstore::QueryBuilders::EventsFiltering
26
+ def self.specific_stream_filtering: (Stream stream, ::Hash[untyped, untyped] options) -> EventsFiltering
23
27
 
24
- def self.system_stream_filtering: (PgEventstore::Stream stream, Hash[untyped, untyped] options) -> PgEventstore::QueryBuilders::EventsFiltering
28
+ def self.system_stream_filtering: (Stream stream, Hash[untyped, untyped] options) -> EventsFiltering
25
29
 
26
30
  def initialize: () -> void
27
31
 
28
- # _@param_ `context`
29
- #
30
- # _@param_ `stream_name`
31
- #
32
- # _@param_ `stream_id`
33
32
  def add_stream_attrs: (?context: String?, ?stream_name: String?, ?stream_id: String?) -> void
34
33
 
35
- # _@param_ `event_types`
36
- def add_event_types: (::Array[String]? event_types) -> void
34
+ def add_event_types: (::Array[String] event_types) -> void
37
35
 
38
36
  # _@param_ `revision`
39
37
  #
@@ -54,9 +52,11 @@ module PgEventstore
54
52
  # _@param_ `limit`
55
53
  def add_limit: (Integer? limit) -> void
56
54
 
57
- def to_sql_builder: () -> PgEventstore::SQLBuilder
55
+ def set_source: (String table_name)-> void
56
+
57
+ def to_sql_builder: () -> SQLBuilder
58
58
 
59
- def to_exec_params: () -> ::Array[untyped]
59
+ def to_exec_params: () -> [String, Array[untyped]]
60
60
 
61
61
  # _@param_ `stream_attrs`
62
62
  def correct_stream_filter?: (::Hash[untyped, untyped] stream_attrs) -> bool
@@ -0,0 +1,21 @@
1
+ module PgEventstore
2
+ module QueryBuilders
3
+ class PartitionsFiltering < BasicFiltering
4
+ TABLE_NAME: String
5
+
6
+ def self.extract_event_types_filter: (Hash[untyped, untyped] options) -> Array[String]
7
+
8
+ def self.extract_streams_filter: (Hash[untyped, untyped] options) -> Array[Hash[untyped, untyped]]
9
+
10
+ def add_event_types: (::Array[String] event_types) -> void
11
+
12
+ def add_stream_attrs: (?context: String?, ?stream_name: String?) -> void
13
+
14
+ def with_event_types: -> void
15
+
16
+ private
17
+
18
+ def correct_stream_filter?: (::Hash[untyped, untyped] stream_attrs) -> bool
19
+ end
20
+ end
21
+ end
@@ -46,7 +46,7 @@ module PgEventstore
46
46
 
47
47
  def remove_group: () -> self
48
48
 
49
- def to_exec_params: () -> ::Array[(String | ::Array[untyped])]
49
+ def to_exec_params: () -> [String, ::Array[untyped]]
50
50
 
51
51
  def positional_values: () -> ::Array[Object]
52
52