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.
- checksums.yaml +4 -4
- data/.rubocop.yml +126 -0
- data/CHANGELOG.md +4 -0
- data/exe/pg-eventstore +6 -6
- data/lib/pg_eventstore/abstract_command.rb +1 -1
- data/lib/pg_eventstore/callbacks.rb +7 -2
- data/lib/pg_eventstore/cli/commands/callback_handlers/start_cmd_handlers.rb +1 -0
- data/lib/pg_eventstore/cli/commands/start_subscriptions_command.rb +5 -4
- data/lib/pg_eventstore/cli/parser_options/metadata.rb +4 -4
- data/lib/pg_eventstore/cli/parsers/default_parser.rb +8 -8
- data/lib/pg_eventstore/cli/parsers/subscription_parser.rb +2 -2
- data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +4 -1
- data/lib/pg_eventstore/cli.rb +4 -4
- data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +2 -2
- data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +1 -0
- data/lib/pg_eventstore/commands/link_to.rb +4 -5
- data/lib/pg_eventstore/commands/multiple.rb +1 -3
- data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +1 -1
- data/lib/pg_eventstore/config.rb +1 -1
- data/lib/pg_eventstore/connection.rb +4 -1
- data/lib/pg_eventstore/errors.rb +3 -1
- data/lib/pg_eventstore/extensions/callbacks_extension.rb +2 -0
- data/lib/pg_eventstore/extensions/options_extension.rb +10 -10
- data/lib/pg_eventstore/extensions/using_connection_extension.rb +1 -1
- data/lib/pg_eventstore/pg_connection.rb +7 -5
- data/lib/pg_eventstore/queries/event_queries.rb +11 -10
- data/lib/pg_eventstore/queries/partition_queries.rb +4 -4
- data/lib/pg_eventstore/queries/transaction_queries.rb +5 -9
- data/lib/pg_eventstore/query_builders/events_filtering.rb +13 -13
- data/lib/pg_eventstore/query_builders/partitions_filtering.rb +6 -8
- data/lib/pg_eventstore/rspec/has_option_matcher.rb +12 -13
- data/lib/pg_eventstore/rspec/test_helpers.rb +4 -3
- data/lib/pg_eventstore/sql_builder.rb +9 -13
- data/lib/pg_eventstore/stream.rb +8 -8
- data/lib/pg_eventstore/subscriptions/basic_runner.rb +4 -3
- data/lib/pg_eventstore/subscriptions/commands_handler.rb +1 -1
- data/lib/pg_eventstore/subscriptions/events_processor.rb +1 -1
- data/lib/pg_eventstore/subscriptions/extensions/base_command_extension.rb +10 -8
- data/lib/pg_eventstore/subscriptions/queries/subscription_command_queries.rb +23 -21
- data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +11 -8
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_command_queries.rb +8 -13
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +7 -6
- data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_connection.rb +3 -1
- data/lib/pg_eventstore/subscriptions/runner_recovery_strategies/restore_subscription_runner.rb +1 -0
- data/lib/pg_eventstore/subscriptions/runner_state.rb +3 -1
- data/lib/pg_eventstore/subscriptions/subscription.rb +11 -10
- data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +5 -7
- data/lib/pg_eventstore/subscriptions/subscriptions_set.rb +8 -8
- data/lib/pg_eventstore/subscriptions/subscriptions_set_lifecycle.rb +2 -0
- data/lib/pg_eventstore/tasks/setup.rake +7 -6
- data/lib/pg_eventstore/utils.rb +8 -4
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +22 -15
- data/lib/pg_eventstore/web/paginator/event_types_collection.rb +9 -11
- data/lib/pg_eventstore/web/paginator/events_collection.rb +6 -7
- data/lib/pg_eventstore/web/paginator/helpers.rb +19 -19
- data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +9 -9
- data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +9 -10
- data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +9 -11
- data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/subscriptions_to_set_association.rb +2 -0
- data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
- data/lib/pg_eventstore.rb +3 -11
- data/pg_eventstore.gemspec +19 -19
- data/sig/pg_eventstore/client.rbs +4 -8
- data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +2 -0
- data/sig/pg_eventstore/web/application.rbs +2 -0
- metadata +8 -7
@@ -7,7 +7,7 @@ module PgEventstore
|
|
7
7
|
include Extensions::CallbacksExtension
|
8
8
|
|
9
9
|
# @return [Hash<Symbol => String>]
|
10
|
-
STATES = %i
|
10
|
+
STATES = %i[initial running halting stopped dead].to_h { [_1, _1.to_s.freeze] }.freeze
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
initial!
|
@@ -36,11 +36,13 @@ module PgEventstore
|
|
36
36
|
|
37
37
|
# @param state [String]
|
38
38
|
# @return [String]
|
39
|
+
# rubocop:disable Naming/AccessorMethodName
|
39
40
|
def set_state(state)
|
40
41
|
old_state = @state
|
41
42
|
@state = state
|
42
43
|
callbacks.run_callbacks(:change_state, @state) unless old_state == @state
|
43
44
|
@state
|
44
45
|
end
|
46
|
+
# rubocop:enable Naming/AccessorMethodName
|
45
47
|
end
|
46
48
|
end
|
@@ -26,10 +26,11 @@ module PgEventstore
|
|
26
26
|
# the list of available options
|
27
27
|
attribute(:options)
|
28
28
|
# @!attribute current_position
|
29
|
-
# @return [Integer, nil] current Subscription's position. It is updated automatically each time an event is
|
29
|
+
# @return [Integer, nil] current Subscription's position. It is updated automatically each time an event is
|
30
|
+
# processed
|
30
31
|
attribute(:current_position)
|
31
32
|
# @!attribute state
|
32
|
-
# @return [String, nil] current Subscription's state. It is updated automatically during Subscription's life cycle
|
33
|
+
# @return [String, nil] current Subscription's state. It is updated automatically during Subscription's life cycle
|
33
34
|
# See {RunnerState::STATES} for possible values.
|
34
35
|
attribute(:state)
|
35
36
|
# @!attribute average_event_processing_time
|
@@ -141,20 +142,20 @@ module PgEventstore
|
|
141
142
|
id.hash
|
142
143
|
end
|
143
144
|
|
144
|
-
# @param
|
145
|
+
# @param other [Object]
|
145
146
|
# @return [Boolean]
|
146
|
-
def eql?(
|
147
|
-
return false unless
|
147
|
+
def eql?(other)
|
148
|
+
return false unless other.is_a?(Subscription)
|
148
149
|
|
149
|
-
hash ==
|
150
|
+
hash == other.hash
|
150
151
|
end
|
151
152
|
|
152
|
-
# @param
|
153
|
+
# @param other [Object]
|
153
154
|
# @return [Boolean]
|
154
|
-
def ==(
|
155
|
-
return false unless
|
155
|
+
def ==(other)
|
156
|
+
return false unless other.is_a?(Subscription)
|
156
157
|
|
157
|
-
id ==
|
158
|
+
id == other.id
|
158
159
|
end
|
159
160
|
|
160
161
|
private
|
@@ -34,7 +34,7 @@ module PgEventstore
|
|
34
34
|
# The average time required to process an event.
|
35
35
|
# @return [Float]
|
36
36
|
def average_event_processing_time
|
37
|
-
synchronize { @timings.
|
37
|
+
synchronize { @timings.empty? ? 0.0 : @timings.sum / @timings.size }
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -58,7 +58,7 @@ module PgEventstore
|
|
58
58
|
|
59
59
|
# @return [Integer]
|
60
60
|
def estimate_events_number
|
61
|
-
return INITIAL_EVENTS_PER_CHUNK if @stats.average_event_processing_time
|
61
|
+
return INITIAL_EVENTS_PER_CHUNK if @stats.average_event_processing_time == 0
|
62
62
|
|
63
63
|
events_per_chunk = (@subscription.chunk_query_interval / @stats.average_event_processing_time).round
|
64
64
|
events_to_fetch = [events_per_chunk, MAX_EVENTS_PER_CHUNK].min - @events_processor.events_left_in_chunk
|
@@ -54,7 +54,7 @@ module PgEventstore
|
|
54
54
|
{
|
55
55
|
name: set_name,
|
56
56
|
max_restarts_number: max_retries || config.subscriptions_set_max_retries,
|
57
|
-
time_between_restarts: retries_interval || config.subscriptions_set_retries_interval
|
57
|
+
time_between_restarts: retries_interval || config.subscriptions_set_retries_interval,
|
58
58
|
}
|
59
59
|
)
|
60
60
|
@subscriptions_lifecycle = SubscriptionsLifecycle.new(
|
@@ -108,7 +108,7 @@ module PgEventstore
|
|
108
108
|
graceful_shutdown_timeout: graceful_shutdown_timeout,
|
109
109
|
recovery_strategies: recovery_strategies(subscription, restart_terminator, failed_subscription_notifier)
|
110
110
|
),
|
111
|
-
subscription: subscription
|
111
|
+
subscription: subscription
|
112
112
|
)
|
113
113
|
|
114
114
|
@subscriptions_lifecycle.runners.push(runner)
|
@@ -149,12 +149,10 @@ module PgEventstore
|
|
149
149
|
private
|
150
150
|
|
151
151
|
# @return [Object] the result of the passed block
|
152
|
-
def run_cli_callbacks
|
152
|
+
def run_cli_callbacks(&blk)
|
153
153
|
return yield unless defined?(::PgEventstore::CLI)
|
154
154
|
|
155
|
-
PgEventstore::CLI.callbacks.run_callbacks(:start_manager, self)
|
156
|
-
yield
|
157
|
-
end
|
155
|
+
PgEventstore::CLI.callbacks.run_callbacks(:start_manager, self, &blk)
|
158
156
|
end
|
159
157
|
|
160
158
|
# @param middlewares [Array<Symbol>, nil]
|
@@ -183,7 +181,7 @@ module PgEventstore
|
|
183
181
|
RunnerRecoveryStrategies::RestoreSubscriptionRunner.new(
|
184
182
|
subscription: subscription,
|
185
183
|
restart_terminator: restart_terminator,
|
186
|
-
failed_subscription_notifier: failed_subscription_notifier
|
184
|
+
failed_subscription_notifier: failed_subscription_notifier
|
187
185
|
),
|
188
186
|
]
|
189
187
|
end
|
@@ -92,20 +92,20 @@ module PgEventstore
|
|
92
92
|
id.hash
|
93
93
|
end
|
94
94
|
|
95
|
-
# @param
|
95
|
+
# @param other [Object]
|
96
96
|
# @return [Boolean]
|
97
|
-
def eql?(
|
98
|
-
return false unless
|
97
|
+
def eql?(other)
|
98
|
+
return false unless other.is_a?(SubscriptionsSet)
|
99
99
|
|
100
|
-
hash ==
|
100
|
+
hash == other.hash
|
101
101
|
end
|
102
102
|
|
103
|
-
# @param
|
103
|
+
# @param other [Object]
|
104
104
|
# @return [Boolean]
|
105
|
-
def ==(
|
106
|
-
return false unless
|
105
|
+
def ==(other)
|
106
|
+
return false unless other.is_a?(SubscriptionsSet)
|
107
107
|
|
108
|
-
id ==
|
108
|
+
id == other.id
|
109
109
|
end
|
110
110
|
|
111
111
|
private
|
@@ -27,9 +27,11 @@ module PgEventstore
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [PgEventstore::SubscriptionsSet]
|
30
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
30
31
|
def persisted_subscriptions_set
|
31
32
|
@subscriptions_set ||= SubscriptionsSet.using_connection(@config_name).create(@subscriptions_set_attrs)
|
32
33
|
end
|
34
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
33
35
|
|
34
36
|
# @return [void]
|
35
37
|
def reset_subscriptions_set
|
@@ -14,13 +14,13 @@ helpers = Class.new do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def db_name
|
17
|
-
@db_name ||= URI.parse(ENV.fetch('PG_EVENTSTORE_URI')).path&.delete(
|
17
|
+
@db_name ||= URI.parse(ENV.fetch('PG_EVENTSTORE_URI')).path&.delete('/')
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
namespace :pg_eventstore do
|
23
|
-
desc
|
23
|
+
desc 'Creates events table, indexes, etc.'
|
24
24
|
task :create do
|
25
25
|
PgEventstore.configure do |config|
|
26
26
|
config.pg_uri = helpers.postgres_uri
|
@@ -28,7 +28,8 @@ namespace :pg_eventstore do
|
|
28
28
|
|
29
29
|
PgEventstore.connection.with do |conn|
|
30
30
|
exists =
|
31
|
-
conn.exec_params(
|
31
|
+
conn.exec_params('SELECT 1 as exists FROM pg_database where datname = $1', [helpers.db_name]).
|
32
|
+
first&.dig('exists')
|
32
33
|
if exists
|
33
34
|
puts "#{helpers.db_name} already exists. Skipping."
|
34
35
|
else
|
@@ -42,7 +43,7 @@ namespace :pg_eventstore do
|
|
42
43
|
config.pg_uri = ENV['PG_EVENTSTORE_URI']
|
43
44
|
end
|
44
45
|
|
45
|
-
migration_files_root = "#{Gem::Specification.find_by_name(
|
46
|
+
migration_files_root = "#{Gem::Specification.find_by_name('pg_eventstore').gem_dir}/db/migrations"
|
46
47
|
|
47
48
|
PgEventstore.connection.with do |conn|
|
48
49
|
conn.exec('CREATE TABLE IF NOT EXISTS migrations (number int NOT NULL)')
|
@@ -50,7 +51,7 @@ namespace :pg_eventstore do
|
|
50
51
|
conn.exec('SELECT number FROM migrations ORDER BY number DESC LIMIT 1').to_a.dig(0, 'number') || -1
|
51
52
|
|
52
53
|
Dir.chdir migration_files_root do
|
53
|
-
Dir[
|
54
|
+
Dir['*.{sql,rb}'].sort_by { |f_name| f_name.split('_').first.to_i }.each do |f_name|
|
54
55
|
number = File.basename(f_name).split('_')[0].to_i
|
55
56
|
next if latest_migration >= number
|
56
57
|
|
@@ -65,7 +66,7 @@ namespace :pg_eventstore do
|
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
68
|
-
desc
|
69
|
+
desc 'Drops events table and related pg_eventstore objects.'
|
69
70
|
task :drop do
|
70
71
|
PgEventstore.configure do |config|
|
71
72
|
config.pg_uri = helpers.postgres_uri
|
data/lib/pg_eventstore/utils.rb
CHANGED
@@ -50,7 +50,7 @@ module PgEventstore
|
|
50
50
|
{
|
51
51
|
class: original_error.class,
|
52
52
|
message: original_error.message,
|
53
|
-
backtrace: original_error.backtrace
|
53
|
+
backtrace: original_error.backtrace,
|
54
54
|
}.tap do |attrs|
|
55
55
|
attrs.merge!(error.extra) if error.is_a?(WrappedException)
|
56
56
|
end
|
@@ -61,7 +61,7 @@ module PgEventstore
|
|
61
61
|
def underscore_str(str)
|
62
62
|
str = str.dup
|
63
63
|
str[0] = str[0].downcase
|
64
|
-
str.gsub!(/[A-Z]/) { |letter|
|
64
|
+
str.gsub!(/[A-Z]/) { |letter| "_#{letter.downcase}" }
|
65
65
|
str
|
66
66
|
end
|
67
67
|
|
@@ -83,7 +83,7 @@ module PgEventstore
|
|
83
83
|
# @param content [String]
|
84
84
|
# @return [void]
|
85
85
|
def write_to_file(file_path, content)
|
86
|
-
file = File.open(file_path,
|
86
|
+
file = File.open(file_path, 'w')
|
87
87
|
file.write(content)
|
88
88
|
ensure
|
89
89
|
file&.close
|
@@ -91,20 +91,24 @@ module PgEventstore
|
|
91
91
|
|
92
92
|
# @param file_path [String]
|
93
93
|
# @return [void]
|
94
|
+
# rubocop:disable Lint/SuppressedException
|
94
95
|
def remove_file(file_path)
|
95
96
|
File.delete(file_path)
|
96
97
|
rescue Errno::ENOENT
|
97
98
|
end
|
99
|
+
# rubocop:enable Lint/SuppressedException
|
98
100
|
|
99
101
|
# @param file_path [String]
|
100
102
|
# @return [String, nil]
|
103
|
+
# rubocop:disable Lint/SuppressedException
|
101
104
|
def read_pid(file_path)
|
102
|
-
file = File.open(file_path,
|
105
|
+
file = File.open(file_path, 'r')
|
103
106
|
file.readline.strip
|
104
107
|
rescue Errno::ENOENT
|
105
108
|
ensure
|
106
109
|
file&.close
|
107
110
|
end
|
111
|
+
# rubocop:enable Lint/SuppressedException
|
108
112
|
|
109
113
|
# @param exception [StandardError]
|
110
114
|
# @param extra [Hash] additional exception info
|
@@ -13,26 +13,33 @@ module PgEventstore
|
|
13
13
|
COOKIES_CONFIG_KEY = 'current_config'
|
14
14
|
# @return [String]
|
15
15
|
COOKIES_FLASH_MESSAGE_KEY = 'flash_message'
|
16
|
+
# @return [Array<Symbol>]
|
17
|
+
LOGGING_ENVS = %i[development test].freeze
|
18
|
+
private_constant :LOGGING_ENVS
|
16
19
|
|
17
20
|
# Defines a replacement for empty string value in a stream attributes filter or in an event type filter. This
|
18
21
|
# replacement is needed to differentiate a user selection vs default placeholder value.
|
19
22
|
# @return [String]
|
20
|
-
EMPTY_STRING_SIGN = "\x00"
|
23
|
+
EMPTY_STRING_SIGN = "\x00"
|
21
24
|
|
22
|
-
set :static_cache_control, [:private, max_age:
|
25
|
+
set :static_cache_control, [:private, { max_age: 86_400 }]
|
23
26
|
set :environment, -> { (ENV['RACK_ENV'] || ENV['RAILS_ENV'] || ENV['APP_ENV'])&.to_sym || :development }
|
24
|
-
set :logging, -> { environment
|
27
|
+
set :logging, -> { LOGGING_ENVS.include?(environment) }
|
25
28
|
set :erb, layout: :'layouts/application'
|
26
29
|
set :host_authorization, { allow_if: ->(_env) { true } }
|
27
30
|
|
28
31
|
helpers(Paginator::Helpers, Subscriptions::Helpers) do
|
29
32
|
# @return [Array<Hash>, nil]
|
33
|
+
# rubocop:disable Style/HashConversion
|
30
34
|
def streams_filter
|
31
35
|
streams = QueryBuilders::EventsFiltering.extract_streams_filter(params)
|
32
|
-
streams
|
33
|
-
|
34
|
-
|
36
|
+
streams = streams.select { _1 in { context: String, stream_name: String, stream_id: String } }
|
37
|
+
streams = streams.map do |stream_attrs|
|
38
|
+
Hash[stream_attrs.reject { |_, value| value == '' }].transform_keys(&:to_sym)
|
39
|
+
end
|
40
|
+
streams.reject(&:empty?)
|
35
41
|
end
|
42
|
+
# rubocop:enable Style/HashConversion
|
36
43
|
|
37
44
|
# @return [String, nil]
|
38
45
|
def system_stream
|
@@ -44,7 +51,7 @@ module PgEventstore
|
|
44
51
|
def events_filter
|
45
52
|
event_filters = { filter: { event_types: params.dig(:filter, :events) } }
|
46
53
|
events = QueryBuilders::EventsFiltering.extract_event_types_filter(event_filters)
|
47
|
-
events
|
54
|
+
events.reject { _1 == '' }
|
48
55
|
end
|
49
56
|
|
50
57
|
# @return [Symbol]
|
@@ -81,7 +88,7 @@ module PgEventstore
|
|
81
88
|
end
|
82
89
|
halt 200, {
|
83
90
|
results: results,
|
84
|
-
pagination: { more: !collection.next_page_starting_id.nil?, starting_id: collection.next_page_starting_id }
|
91
|
+
pagination: { more: !collection.next_page_starting_id.nil?, starting_id: collection.next_page_starting_id },
|
85
92
|
}.to_json
|
86
93
|
end
|
87
94
|
|
@@ -144,7 +151,7 @@ module PgEventstore
|
|
144
151
|
order: Paginator::EventsCollection::SQL_DIRECTIONS[params[:order]],
|
145
152
|
options: {
|
146
153
|
filter: { event_types: events_filter, streams: streams_filter },
|
147
|
-
resolve_link_tos: resolve_link_tos
|
154
|
+
resolve_link_tos: resolve_link_tos?,
|
148
155
|
},
|
149
156
|
system_stream: system_stream
|
150
157
|
)
|
@@ -154,7 +161,7 @@ module PgEventstore
|
|
154
161
|
halt 200, {
|
155
162
|
events: erb(:'home/partials/events', { layout: false }, { events: @collection.collection }),
|
156
163
|
total_count: total_count(@collection.total_count),
|
157
|
-
pagination: erb(:'home/partials/pagination_links', { layout: false }, { collection: @collection })
|
164
|
+
pagination: erb(:'home/partials/pagination_links', { layout: false }, { collection: @collection }),
|
158
165
|
}.to_json
|
159
166
|
else
|
160
167
|
erb :'home/dashboard'
|
@@ -223,7 +230,7 @@ module PgEventstore
|
|
223
230
|
options: {
|
224
231
|
query: params[:term],
|
225
232
|
context: unescape_empty_string(params[:context]),
|
226
|
-
stream_name: unescape_empty_string(params[:stream_name])
|
233
|
+
stream_name: unescape_empty_string(params[:stream_name]),
|
227
234
|
}
|
228
235
|
)
|
229
236
|
paginated_json_response(collection)
|
@@ -297,7 +304,7 @@ module PgEventstore
|
|
297
304
|
PgEventstore.maintenance(current_config).delete_event(event, force: force)
|
298
305
|
self.flash_message = {
|
299
306
|
message: "An event at global position #{event.global_position} has been deleted successfully.",
|
300
|
-
kind: 'success'
|
307
|
+
kind: 'success',
|
301
308
|
}
|
302
309
|
rescue TooManyRecordsToLockError => e
|
303
310
|
text = <<~TEXT
|
@@ -319,10 +326,10 @@ module PgEventstore
|
|
319
326
|
stream_id: params[:stream_id]&.to_s,
|
320
327
|
}
|
321
328
|
|
322
|
-
err_message =
|
329
|
+
err_message = lambda { |attrs|
|
323
330
|
self.flash_message = {
|
324
331
|
message: "Could not delete #{attrs}. It is not valid stream for deletion.",
|
325
|
-
kind: 'error'
|
332
|
+
kind: 'error',
|
326
333
|
}
|
327
334
|
}
|
328
335
|
|
@@ -334,7 +341,7 @@ module PgEventstore
|
|
334
341
|
PgEventstore.maintenance(current_config).delete_stream(stream)
|
335
342
|
self.flash_message = {
|
336
343
|
message: "Stream #{stream.to_hash} has been successfully deleted.",
|
337
|
-
kind: 'success'
|
344
|
+
kind: 'success',
|
338
345
|
}
|
339
346
|
end
|
340
347
|
else
|
@@ -9,14 +9,13 @@ module PgEventstore
|
|
9
9
|
|
10
10
|
# @return [Array<Hash<String => String>>]
|
11
11
|
def collection
|
12
|
-
@
|
12
|
+
@collection ||=
|
13
13
|
begin
|
14
|
-
sql_builder =
|
15
|
-
|
16
|
-
where('context is not null and stream_name is not null').
|
17
|
-
group('event_type').order("event_type #{order}").limit(per_page)
|
14
|
+
sql_builder = SQLBuilder.new.select('event_type').from('partitions')
|
15
|
+
sql_builder.where('context is not null and stream_name is not null')
|
18
16
|
sql_builder.where("event_type #{direction_operator} ?", starting_id) if starting_id
|
19
17
|
sql_builder.where('event_type ilike ?', "%#{options[:query]}%")
|
18
|
+
sql_builder.group('event_type').order("event_type #{order}").limit(per_page)
|
20
19
|
connection.with do |conn|
|
21
20
|
conn.exec_params(*sql_builder.to_exec_params)
|
22
21
|
end.to_a
|
@@ -28,12 +27,11 @@ module PgEventstore
|
|
28
27
|
return unless collection.size == per_page
|
29
28
|
|
30
29
|
starting_id = collection.first['event_type']
|
31
|
-
sql_builder =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
group('event_type').order("event_type #{order}").limit(1).offset(per_page)
|
30
|
+
sql_builder = SQLBuilder.new.select('event_type').from('partitions')
|
31
|
+
sql_builder.where('context is not null and stream_name is not null')
|
32
|
+
sql_builder.where("event_type #{direction_operator} ?", starting_id)
|
33
|
+
sql_builder.where('event_type ilike ?', "%#{options[:query]}%")
|
34
|
+
sql_builder.group('event_type').order("event_type #{order}").limit(1).offset(per_page)
|
37
35
|
|
38
36
|
connection.with do |conn|
|
39
37
|
conn.exec_params(*sql_builder.to_exec_params)
|
@@ -7,7 +7,7 @@ module PgEventstore
|
|
7
7
|
# @return [Hash<String => Symbol>] SQL directions, string-to-symbol mapping
|
8
8
|
SQL_DIRECTIONS = {
|
9
9
|
'asc' => :asc,
|
10
|
-
'desc' => :desc
|
10
|
+
'desc' => :desc,
|
11
11
|
}.tap do |directions|
|
12
12
|
directions.default = :desc
|
13
13
|
end.freeze
|
@@ -32,7 +32,7 @@ module PgEventstore
|
|
32
32
|
|
33
33
|
# @return [Array<PgEventstore::Event>]
|
34
34
|
def collection
|
35
|
-
@
|
35
|
+
@collection ||= PgEventstore.client(config_name).read(
|
36
36
|
@stream,
|
37
37
|
options: options.merge(from_position: starting_id, max_count: per_page, direction: order)
|
38
38
|
)
|
@@ -59,18 +59,17 @@ module PgEventstore
|
|
59
59
|
).to_sql_builder.unselect.select('global_position').offset(1)
|
60
60
|
sql, params = sql_builder.to_exec_params
|
61
61
|
sql = "SELECT * FROM (#{sql}) events ORDER BY global_position #{order} LIMIT 1"
|
62
|
-
connection.with
|
62
|
+
connection.with do |conn|
|
63
63
|
conn.exec_params(sql, params)
|
64
64
|
end.to_a.dig(0, 'global_position')
|
65
65
|
end
|
66
66
|
|
67
67
|
# @return [Integer]
|
68
68
|
def total_count
|
69
|
-
@
|
69
|
+
@total_count ||=
|
70
70
|
begin
|
71
|
-
sql_builder =
|
72
|
-
|
73
|
-
to_sql_builder.remove_limit.remove_group.remove_order
|
71
|
+
sql_builder = QueryBuilders::EventsFiltering.events_filtering(@stream, options).to_sql_builder
|
72
|
+
sql_builder.remove_limit.remove_group.remove_order
|
74
73
|
count = estimate_count(sql_builder)
|
75
74
|
return count if count > MAX_NUMBER_TO_COUNT
|
76
75
|
|
@@ -10,10 +10,10 @@ module PgEventstore
|
|
10
10
|
id = collection.prev_page_starting_id
|
11
11
|
disabled = id ? '' : 'disabled'
|
12
12
|
<<~HTML
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
<li class="page-item #{disabled}">
|
14
|
+
<a class="page-link" href="#{build_starting_id_link(id)}" tabindex="-1">Previous</a>
|
15
|
+
</li>
|
16
|
+
HTML
|
17
17
|
end
|
18
18
|
|
19
19
|
# @param collection [PgEventstore::Web::Paginator::BaseCollection]
|
@@ -22,20 +22,20 @@ module PgEventstore
|
|
22
22
|
id = collection.next_page_starting_id
|
23
23
|
disabled = id ? '' : 'disabled'
|
24
24
|
<<~HTML
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
<li class="page-item #{disabled}">
|
26
|
+
<a class="page-link" href="#{build_starting_id_link(id)}" tabindex="-1">Next</a>
|
27
|
+
</li>
|
28
|
+
HTML
|
29
29
|
end
|
30
30
|
|
31
31
|
# @return [String]
|
32
32
|
def first_page_link
|
33
33
|
path = build_path(params.slice(*(params.keys - ['starting_id'])))
|
34
34
|
<<~HTML
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
<li class="page-item">
|
36
|
+
<a class="page-link" href="#{path}" tabindex="-1">First</a>
|
37
|
+
</li>
|
38
|
+
HTML
|
39
39
|
end
|
40
40
|
|
41
41
|
# @param per_page [String] string representation of items per page. E.g. "10", "20", etc.
|
@@ -59,9 +59,9 @@ module PgEventstore
|
|
59
59
|
def total_count(number)
|
60
60
|
prefix =
|
61
61
|
if number > Paginator::EventsCollection::MAX_NUMBER_TO_COUNT
|
62
|
-
|
62
|
+
'Estimate count: '
|
63
63
|
else
|
64
|
-
|
64
|
+
'Total count: '
|
65
65
|
end
|
66
66
|
number = number_with_delimiter(number)
|
67
67
|
prefix + number
|
@@ -75,7 +75,7 @@ module PgEventstore
|
|
75
75
|
number = number.to_s
|
76
76
|
symbols_to_skip = number.size % 3
|
77
77
|
parts = []
|
78
|
-
parts.push(number[0...symbols_to_skip]) unless symbols_to_skip
|
78
|
+
parts.push(number[0...symbols_to_skip]) unless symbols_to_skip == 0
|
79
79
|
parts.push(*number[symbols_to_skip..].scan(/\d{3}/))
|
80
80
|
parts.join(delimiter)
|
81
81
|
end
|
@@ -90,10 +90,10 @@ module PgEventstore
|
|
90
90
|
{
|
91
91
|
context: escape_empty_string(event.stream.context),
|
92
92
|
stream_name: escape_empty_string(event.stream.stream_name),
|
93
|
-
stream_id: escape_empty_string(event.stream.stream_id)
|
94
|
-
}
|
95
|
-
]
|
96
|
-
}
|
93
|
+
stream_id: escape_empty_string(event.stream.stream_id),
|
94
|
+
},
|
95
|
+
],
|
96
|
+
},
|
97
97
|
}
|
98
98
|
)
|
99
99
|
end
|
@@ -9,14 +9,13 @@ module PgEventstore
|
|
9
9
|
|
10
10
|
# @return [Array<Hash<String => String>>]
|
11
11
|
def collection
|
12
|
-
@
|
12
|
+
@collection ||=
|
13
13
|
begin
|
14
|
-
sql_builder =
|
15
|
-
|
16
|
-
where('stream_name is null and event_type is null').
|
17
|
-
limit(per_page).order("context #{order}")
|
14
|
+
sql_builder = SQLBuilder.new.select('context').from('partitions')
|
15
|
+
sql_builder.where('stream_name is null and event_type is null')
|
18
16
|
sql_builder.where("context #{direction_operator} ?", starting_id) if starting_id
|
19
17
|
sql_builder.where('context ilike ?', "%#{options[:query]}%")
|
18
|
+
sql_builder.limit(per_page).order("context #{order}")
|
20
19
|
connection.with do |conn|
|
21
20
|
conn.exec_params(*sql_builder.to_exec_params)
|
22
21
|
end.to_a
|
@@ -28,10 +27,11 @@ module PgEventstore
|
|
28
27
|
return unless collection.size == per_page
|
29
28
|
|
30
29
|
starting_id = collection.first['context']
|
31
|
-
sql_builder =
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
sql_builder = SQLBuilder.new.select('context').from('partitions')
|
31
|
+
sql_builder.where('stream_name is null and event_type is null')
|
32
|
+
sql_builder.where("context #{direction_operator} ?", starting_id)
|
33
|
+
sql_builder.where('context ilike ?', "%#{options[:query]}%")
|
34
|
+
sql_builder.limit(1).offset(per_page).order("context #{order}")
|
35
35
|
|
36
36
|
connection.with do |conn|
|
37
37
|
conn.exec_params(*sql_builder.to_exec_params)
|
@@ -9,12 +9,11 @@ module PgEventstore
|
|
9
9
|
|
10
10
|
# @return [Array<Hash<String => String>>]
|
11
11
|
def collection
|
12
|
-
@
|
12
|
+
@collection ||=
|
13
13
|
begin
|
14
|
-
sql_builder =
|
15
|
-
|
16
|
-
|
17
|
-
where('stream_id like ?', "#{options[:query]}%")
|
14
|
+
sql_builder = SQLBuilder.new.select('stream_id').from('events')
|
15
|
+
sql_builder.where('context = ? and stream_name = ?', options[:context], options[:stream_name])
|
16
|
+
sql_builder.where('stream_id like ?', "#{options[:query]}%")
|
18
17
|
sql_builder.where("stream_id #{direction_operator} ?", starting_id) if starting_id
|
19
18
|
sql_builder.group('stream_id').limit(per_page).order("stream_id #{order}")
|
20
19
|
connection.with do |conn|
|
@@ -28,11 +27,11 @@ module PgEventstore
|
|
28
27
|
return unless collection.size == per_page
|
29
28
|
|
30
29
|
starting_id = collection.first['stream_id']
|
31
|
-
sql_builder =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
sql_builder = SQLBuilder.new.select('stream_id').from('events')
|
31
|
+
sql_builder.where("stream_id #{direction_operator} ?", starting_id)
|
32
|
+
sql_builder.where('stream_id like ?', "#{options[:query]}%")
|
33
|
+
sql_builder.where('context = ? and stream_name = ?', options[:context], options[:stream_name])
|
34
|
+
sql_builder.group('stream_id').limit(1).offset(per_page).order("stream_id #{order}")
|
36
35
|
|
37
36
|
connection.with do |conn|
|
38
37
|
conn.exec_params(*sql_builder.to_exec_params)
|