sequent 4.0.0 → 4.3.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sequent +33 -26
  3. data/lib/notices.rb +2 -0
  4. data/lib/sequent/application_record.rb +2 -0
  5. data/lib/sequent/configuration.rb +24 -31
  6. data/lib/sequent/core/aggregate_repository.rb +48 -13
  7. data/lib/sequent/core/aggregate_root.rb +36 -7
  8. data/lib/sequent/core/aggregate_roots.rb +24 -0
  9. data/lib/sequent/core/aggregate_snapshotter.rb +8 -5
  10. data/lib/sequent/core/base_command_handler.rb +4 -2
  11. data/lib/sequent/core/command.rb +17 -9
  12. data/lib/sequent/core/command_record.rb +8 -3
  13. data/lib/sequent/core/command_service.rb +18 -18
  14. data/lib/sequent/core/core.rb +2 -0
  15. data/lib/sequent/core/current_event.rb +2 -0
  16. data/lib/sequent/core/event.rb +16 -11
  17. data/lib/sequent/core/event_publisher.rb +16 -15
  18. data/lib/sequent/core/event_record.rb +7 -7
  19. data/lib/sequent/core/event_store.rb +89 -51
  20. data/lib/sequent/core/ext/ext.rb +9 -1
  21. data/lib/sequent/core/helpers/array_with_type.rb +4 -1
  22. data/lib/sequent/core/helpers/association_validator.rb +9 -7
  23. data/lib/sequent/core/helpers/attribute_support.rb +45 -28
  24. data/lib/sequent/core/helpers/autoset_attributes.rb +4 -4
  25. data/lib/sequent/core/helpers/boolean_validator.rb +6 -1
  26. data/lib/sequent/core/helpers/copyable.rb +2 -2
  27. data/lib/sequent/core/helpers/date_time_validator.rb +4 -1
  28. data/lib/sequent/core/helpers/date_validator.rb +6 -1
  29. data/lib/sequent/core/helpers/default_validators.rb +12 -10
  30. data/lib/sequent/core/helpers/equal_support.rb +8 -6
  31. data/lib/sequent/core/helpers/helpers.rb +2 -0
  32. data/lib/sequent/core/helpers/mergable.rb +6 -5
  33. data/lib/sequent/core/helpers/message_handler.rb +3 -1
  34. data/lib/sequent/core/helpers/param_support.rb +19 -15
  35. data/lib/sequent/core/helpers/secret.rb +14 -12
  36. data/lib/sequent/core/helpers/string_support.rb +5 -4
  37. data/lib/sequent/core/helpers/string_to_value_parsers.rb +7 -2
  38. data/lib/sequent/core/helpers/string_validator.rb +6 -1
  39. data/lib/sequent/core/helpers/type_conversion_support.rb +5 -3
  40. data/lib/sequent/core/helpers/uuid_helper.rb +5 -2
  41. data/lib/sequent/core/helpers/value_validators.rb +23 -9
  42. data/lib/sequent/core/persistors/active_record_persistor.rb +19 -9
  43. data/lib/sequent/core/persistors/persistor.rb +16 -14
  44. data/lib/sequent/core/persistors/persistors.rb +2 -0
  45. data/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +70 -47
  46. data/lib/sequent/core/projector.rb +53 -22
  47. data/lib/sequent/core/random_uuid_generator.rb +2 -0
  48. data/lib/sequent/core/sequent_oj.rb +2 -0
  49. data/lib/sequent/core/stream_record.rb +9 -3
  50. data/lib/sequent/core/transactions/active_record_transaction_provider.rb +30 -9
  51. data/lib/sequent/core/transactions/no_transactions.rb +2 -1
  52. data/lib/sequent/core/transactions/read_only_active_record_transaction_provider.rb +46 -0
  53. data/lib/sequent/core/transactions/transactions.rb +3 -0
  54. data/lib/sequent/core/value_object.rb +8 -10
  55. data/lib/sequent/core/workflow.rb +35 -5
  56. data/lib/sequent/generator/aggregate.rb +16 -10
  57. data/lib/sequent/generator/command.rb +26 -19
  58. data/lib/sequent/generator/event.rb +19 -17
  59. data/lib/sequent/generator/generator.rb +2 -0
  60. data/lib/sequent/generator/project.rb +9 -0
  61. data/lib/sequent/generator/template_project/Gemfile +1 -1
  62. data/lib/sequent/generator/template_project/ruby-version +1 -0
  63. data/lib/sequent/generator.rb +2 -0
  64. data/lib/sequent/migrations/executor.rb +22 -13
  65. data/lib/sequent/migrations/functions.rb +5 -6
  66. data/lib/sequent/migrations/migrate_events.rb +12 -9
  67. data/lib/sequent/migrations/migrations.rb +2 -1
  68. data/lib/sequent/migrations/planner.rb +33 -23
  69. data/lib/sequent/migrations/projectors.rb +4 -3
  70. data/lib/sequent/migrations/sql.rb +2 -0
  71. data/lib/sequent/migrations/view_schema.rb +84 -45
  72. data/lib/sequent/rake/migration_tasks.rb +58 -22
  73. data/lib/sequent/rake/tasks.rb +5 -2
  74. data/lib/sequent/sequent.rb +2 -0
  75. data/lib/sequent/support/database.rb +30 -15
  76. data/lib/sequent/support/view_projection.rb +6 -3
  77. data/lib/sequent/support/view_schema.rb +2 -0
  78. data/lib/sequent/support.rb +2 -0
  79. data/lib/sequent/test/command_handler_helpers.rb +35 -17
  80. data/lib/sequent/test/event_handler_helpers.rb +10 -4
  81. data/lib/sequent/test/event_stream_helpers.rb +7 -3
  82. data/lib/sequent/test/time_comparison.rb +12 -5
  83. data/lib/sequent/test.rb +2 -0
  84. data/lib/sequent/util/dry_run.rb +28 -20
  85. data/lib/sequent/util/printer.rb +6 -5
  86. data/lib/sequent/util/skip_if_already_processing.rb +3 -1
  87. data/lib/sequent/util/timer.rb +2 -0
  88. data/lib/sequent/util/util.rb +2 -0
  89. data/lib/sequent.rb +2 -0
  90. data/lib/version.rb +3 -1
  91. metadata +84 -67
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequent
2
4
  module Migrations
3
5
  class Migration
4
-
5
6
  module ClassMethods
6
7
  def create(record_class, version)
7
8
  migration = new(record_class)
@@ -11,6 +12,7 @@ module Sequent
11
12
  end
12
13
 
13
14
  def self.inherited(child_class)
15
+ super
14
16
  class << child_class
15
17
  include ClassMethods
16
18
  end
@@ -35,11 +37,11 @@ module Sequent
35
37
  def ==(other)
36
38
  return false unless other.class == self.class
37
39
 
38
- self.table_name == other.table_name && version == other.version
40
+ table_name == other.table_name && version == other.version
39
41
  end
40
42
 
41
43
  def hash
42
- self.table_name.hash + (version&.hash || 0)
44
+ table_name.hash + (version&.hash || 0)
43
45
  end
44
46
  end
45
47
 
@@ -48,7 +50,6 @@ module Sequent
48
50
  class ReplayTable < Migration; end
49
51
 
50
52
  module Functions
51
-
52
53
  module ClassMethods
53
54
  def alter_table(name)
54
55
  AlterTable.new(name)
@@ -62,13 +63,11 @@ module Sequent
62
63
  def all_projectors
63
64
  Sequent::Core::Migratable.all
64
65
  end
65
-
66
66
  end
67
67
 
68
68
  def self.included(base)
69
69
  base.extend(ClassMethods)
70
70
  end
71
-
72
71
  end
73
72
 
74
73
  include Functions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # When you need to upgrade the event store based on information of the previous schema version
3
5
  # this is the place you need to implement a migration.
@@ -20,11 +22,12 @@
20
22
  module Sequent
21
23
  module Migrations
22
24
  class MigrateEvents
23
-
24
25
  ##
25
26
  # @param env The string representing the current environment. E.g. "development", "production"
26
27
  def initialize(env)
27
- warn '[DEPRECATED] Use of MigrateEvents is deprecated and will be removed from future version. Please use Sequent::Migrations::ViewSchema instead. See the changelog on how to update.'
28
+ warn <<~EOS
29
+ [DEPRECATED] Use of MigrateEvents is deprecated and will be removed from future version. Please use Sequent::Migrations::ViewSchema instead. See the changelog on how to update.
30
+ EOS
28
31
  @env = env
29
32
  end
30
33
 
@@ -32,9 +35,10 @@ module Sequent
32
35
  #
33
36
  # @param current_version The current version of the application. E.g. 10
34
37
  # @param new_version The version to migrate to. E.g. 11
35
- # @param &after_migration_block an optional block (with the current upgrade version as param) to run after the migrations run. E.g. close resources
38
+ # @param &after_migration_block an optional block (with the current upgrade version as param)
39
+ # to run after the migrations run. E.g. close resources
36
40
  #
37
- def execute_migrations(current_version, new_version, &after_migration_block)
41
+ def execute_migrations(current_version, new_version)
38
42
  migrations(current_version, new_version).each do |migration_class|
39
43
  migration = migration_class.new(@env)
40
44
  begin
@@ -47,12 +51,11 @@ module Sequent
47
51
 
48
52
  def migrations(current_version, new_version)
49
53
  return [] if current_version == 0
54
+
50
55
  ((current_version + 1)..new_version).map do |upgrade_to_version|
51
- begin
52
- Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
53
- rescue NameError
54
- nil
55
- end
56
+ Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
57
+ rescue NameError
58
+ nil
56
59
  end.compact
57
60
  end
58
61
 
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequent
2
4
  module Migrations
3
-
4
5
  end
5
6
  end
6
7
 
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequent
2
4
  module Migrations
3
5
  class Planner
4
6
  Plan = Struct.new(:projectors, :migrations) do
5
7
  def replay_tables
6
- migrations.select { |m| m.class == ReplayTable }
8
+ migrations.select { |m| m.instance_of?(ReplayTable) }
7
9
  end
8
10
 
9
11
  def alter_tables
10
- migrations.select { |m| m.class == AlterTable }
12
+ migrations.select { |m| m.instance_of?(AlterTable) }
11
13
  end
12
14
 
13
15
  def empty?
@@ -28,7 +30,7 @@ module Sequent
28
30
  migrations.yield_self(&method(:select_projectors)),
29
31
  migrations
30
32
  .yield_self(&method(:create_migrations))
31
- .yield_self(&method(:remove_redundant_migrations))
33
+ .yield_self(&method(:remove_redundant_migrations)),
32
34
  )
33
35
  end
34
36
 
@@ -43,11 +45,11 @@ module Sequent
43
45
 
44
46
  def remove_redundant_migrations(migrations)
45
47
  redundant_migrations = migrations
46
- .yield_self(&method(:group_identical_migrations))
47
- .yield_self(&method(:select_redundant_migrations))
48
- .yield_self(&method(:remove_redundancy))
49
- .values
50
- .flatten
48
+ .yield_self(&method(:group_identical_migrations))
49
+ .yield_self(&method(:select_redundant_migrations))
50
+ .yield_self(&method(:remove_redundancy))
51
+ .values
52
+ .flatten
51
53
 
52
54
  (migrations - redundant_migrations)
53
55
  .yield_self(&method(:remove_alter_tables_before_replay_table))
@@ -64,21 +66,22 @@ module Sequent
64
66
 
65
67
  def remove_alter_tables_before_replay_table(migrations)
66
68
  migrations - migrations
67
- .each_with_index
68
- .select { |migration, _index| migration.class == AlterTable }
69
- .select { |migration, index| migrations
70
- .slice((index + 1)..-1)
71
- .find { |m| m.class == ReplayTable && m.record_class == migration.record_class }
72
- }.map(&:first)
69
+ .each_with_index
70
+ .select { |migration, _index| migration.instance_of?(AlterTable) }
71
+ .select do |migration, index|
72
+ migrations
73
+ .slice((index + 1)..-1)
74
+ .find { |m| m.instance_of?(ReplayTable) && m.record_class == migration.record_class }
75
+ end.map(&:first)
73
76
  end
74
77
 
75
78
  def remove_redundancy(grouped_migrations)
76
- grouped_migrations.reduce({}) { |memo, (key, ms)|
79
+ grouped_migrations.reduce({}) do |memo, (key, ms)|
77
80
  memo[key] = ms
78
- .yield_self(&method(:order_by_version_desc))
79
- .slice(1..-1)
81
+ .yield_self(&method(:order_by_version_desc))
82
+ .slice(1..-1)
80
83
  memo
81
- }
84
+ end
82
85
  end
83
86
 
84
87
  def order_by_version_desc(migrations)
@@ -95,13 +98,20 @@ module Sequent
95
98
  end
96
99
 
97
100
  def map_to_migrations(migrations)
98
- migrations.reduce({}) do |memo, (version, _migrations)|
99
- fail "Declared migrations for version #{version} must be an Array. For example: {'3' => [FooProjector]}" unless _migrations.is_a?(Array)
101
+ migrations.reduce({}) do |memo, (version, ms)|
102
+ unless ms.is_a?(Array)
103
+ fail "Declared migrations for version #{version} must be an Array. For example: {'3' => [FooProjector]}"
104
+ end
100
105
 
101
- memo[version] = _migrations.flat_map do |migration|
106
+ memo[version] = ms.flat_map do |migration|
102
107
  if migration.is_a?(AlterTable)
103
- alter_table_sql_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{migration.table_name}_#{version}.sql"
104
- fail "Missing file #{alter_table_sql_file_name} to apply for version #{version}" unless File.exist?(alter_table_sql_file_name)
108
+ alter_table_sql_file_name = <<~EOS.chomp
109
+ #{Sequent.configuration.migration_sql_files_directory}/#{migration.table_name}_#{version}.sql
110
+ EOS
111
+ unless File.exist?(alter_table_sql_file_name)
112
+ fail "Missing file #{alter_table_sql_file_name} to apply for version #{version}"
113
+ end
114
+
105
115
  migration.copy(version)
106
116
  elsif migration < Sequent::Projector
107
117
  migration.managed_tables.map { |table| ReplayTable.create(table, version) }
@@ -1,19 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'planner'
2
4
  module Sequent
3
5
  module Migrations
4
6
  class Projectors
5
7
  def self.versions
6
- fail "Define your own Sequent::Migrations::List class that extends this class and implements this method"
8
+ fail 'Define your own Sequent::Migrations::List class that extends this class and implements this method'
7
9
  end
8
10
 
9
11
  def self.version
10
- fail "Define your own Sequent::Migrations::List class that extends this class and implements this method"
12
+ fail 'Define your own Sequent::Migrations::List class that extends this class and implements this method'
11
13
  end
12
14
 
13
15
  def self.migrations_between(old, new)
14
16
  Planner.new(versions).plan(old, new)
15
17
  end
16
18
  end
17
-
18
19
  end
19
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../application_record'
2
4
 
3
5
  module Sequent
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'parallel'
2
4
  require 'postgresql_cursor'
3
5
 
@@ -24,11 +26,13 @@ module Sequent
24
26
  # - AlterTable (For instance if you introduce a new column)
25
27
  #
26
28
  # To maintain your migrations you need to:
27
- # 1. Create a class that extends `Sequent::Migrations::Projectors` and specify in `Sequent.configuration.migrations_class_name`
29
+ # 1. Create a class that extends `Sequent::Migrations::Projectors`
30
+ # and specify in `Sequent.configuration.migrations_class_name`
28
31
  # 2. Define per version which migrations you want to execute
29
32
  # See the definition of `Sequent::Migrations::Projectors.versions` and `Sequent::Migrations::Projectors.version`
30
33
  # 3. Specify in Sequent where your sql files reside (Sequent.configuration.migration_sql_files_directory)
31
- # 4. Ensure that you add %SUFFIX% to each name that needs to be unique in postgres (like TABLE names, INDEX names, PRIMARY KEYS)
34
+ # 4. Ensure that you add %SUFFIX% to each name that needs to be unique in postgres
35
+ # (like TABLE names, INDEX names, PRIMARY KEYS)
32
36
  # E.g. `create table foo%SUFFIX% (id serial NOT NULL, CONSTRAINT foo_pkey%SUFFIX% PRIMARY KEY (id))`
33
37
  # 5. If you want to run an `alter_table` migration ensure that
34
38
  # a sql file named `table_name_VERSION.sql` exists.
@@ -96,7 +100,10 @@ module Sequent
96
100
  create_view_schema_if_not_exists
97
101
  in_view_schema do
98
102
  Sequent::Core::Migratable.all.flat_map(&:managed_tables).each do |table|
99
- statements = sql_file_to_statements("#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql") { |raw_sql| raw_sql.remove('%SUFFIX%') }
103
+ sql_file = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql"
104
+ statements = sql_file_to_statements(sql_file) do |raw_sql|
105
+ raw_sql.remove('%SUFFIX%')
106
+ end
100
107
  statements.each { |statement| exec_sql(statement) }
101
108
 
102
109
  indexes_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.indexes.sql"
@@ -121,10 +128,14 @@ module Sequent
121
128
  #
122
129
  # This method is mainly useful during an initial setup of the view schema
123
130
  def create_view_schema_if_not_exists
124
- exec_sql(%Q{CREATE SCHEMA IF NOT EXISTS #{view_schema}})
131
+ exec_sql(%(CREATE SCHEMA IF NOT EXISTS #{view_schema}))
125
132
  in_view_schema do
126
- exec_sql(%Q{CREATE TABLE IF NOT EXISTS #{Versions.table_name} (version integer NOT NULL, CONSTRAINT version_pk PRIMARY KEY(version))})
127
- exec_sql(%Q{CREATE TABLE IF NOT EXISTS #{ReplayedIds.table_name} (event_id bigint NOT NULL, CONSTRAINT event_id_pk PRIMARY KEY(event_id))})
133
+ exec_sql(<<~SQL.chomp)
134
+ CREATE TABLE IF NOT EXISTS #{Versions.table_name} (version integer NOT NULL, CONSTRAINT version_pk PRIMARY KEY(version))
135
+ SQL
136
+ exec_sql(<<~SQL.chomp)
137
+ CREATE TABLE IF NOT EXISTS #{ReplayedIds.table_name} (event_id bigint NOT NULL, CONSTRAINT event_id_pk PRIMARY KEY(event_id))
138
+ SQL
128
139
  end
129
140
  end
130
141
 
@@ -162,14 +173,14 @@ module Sequent
162
173
  executor.execute_online(plan)
163
174
  end
164
175
 
165
- if plan.projectors.any?
166
- replay!(Sequent.configuration.online_replay_persistor_class.new)
167
- end
176
+ replay!(Sequent.configuration.online_replay_persistor_class.new) if plan.projectors.any?
168
177
 
169
178
  in_view_schema do
170
179
  executor.create_indexes_after_execute_online(plan)
171
180
  end
181
+ # rubocop:disable Lint/RescueException
172
182
  rescue Exception => e
183
+ # rubocop:enable Lint/RescueException
173
184
  rollback_migration
174
185
  raise e
175
186
  end
@@ -201,7 +212,13 @@ module Sequent
201
212
  executor.set_table_names_to_new_version(plan)
202
213
 
203
214
  # 1 replay events not yet replayed
204
- replay!(Sequent.configuration.offline_replay_persistor_class.new, exclude_ids: true, group_exponent: 1) if plan.projectors.any?
215
+ if plan.projectors.any?
216
+ replay!(
217
+ Sequent.configuration.offline_replay_persistor_class.new,
218
+ exclude_ids: true,
219
+ group_exponent: 1,
220
+ )
221
+ end
205
222
 
206
223
  in_view_schema do
207
224
  Sequent::ApplicationRecord.transaction do
@@ -215,50 +232,57 @@ module Sequent
215
232
  truncate_replay_ids_table!
216
233
  end
217
234
  logger.info "Migrated to version #{Sequent.new_version}"
235
+ # rubocop:disable Lint/RescueException
218
236
  rescue Exception => e
237
+ # rubocop:enable Lint/RescueException
219
238
  rollback_migration
220
239
  raise e
221
240
  end
222
241
 
223
242
  private
224
243
 
225
-
226
244
  def ensure_version_correct!
227
245
  create_view_schema_if_not_exists
228
246
  new_version = Sequent.new_version
229
247
 
230
- fail ArgumentError.new("new_version [#{new_version}] must be greater or equal to current_version [#{current_version}]") if new_version < current_version
231
-
248
+ if new_version < current_version
249
+ fail ArgumentError,
250
+ "new_version [#{new_version}] must be greater or equal to current_version [#{current_version}]"
251
+ end
232
252
  end
233
253
 
234
254
  def replay!(replay_persistor, projectors: plan.projectors, exclude_ids: false, group_exponent: 3)
235
255
  logger.info "group_exponent: #{group_exponent.inspect}"
236
256
 
237
257
  with_sequent_config(replay_persistor, projectors) do
238
- logger.info "Start replaying events"
258
+ logger.info 'Start replaying events'
239
259
 
240
- time("#{16 ** group_exponent} groups replayed") do
260
+ time("#{16**group_exponent} groups replayed") do
241
261
  event_types = projectors.flat_map { |projector| projector.message_mapping.keys }.uniq.map(&:name)
242
262
  disconnect!
243
263
 
244
- number_of_groups = 16 ** group_exponent
264
+ number_of_groups = 16**group_exponent
245
265
  groups = groups_of_aggregate_id_prefixes(number_of_groups)
246
266
 
247
267
  @connected = false
248
268
  # using `map_with_index` because https://github.com/grosser/parallel/issues/175
249
- result = Parallel.map_with_index(groups, in_processes: Sequent.configuration.number_of_replay_processes) do |aggregate_prefixes, index|
250
- begin
251
- @connected ||= establish_connection
252
- time("Group (#{aggregate_prefixes.first}-#{aggregate_prefixes.last}) #{index + 1}/#{number_of_groups} replayed") do
253
- replay_events(aggregate_prefixes, event_types, exclude_ids, replay_persistor, &insert_ids)
254
- end
255
- nil
256
- rescue => e
257
- logger.error "Replaying failed for ids: ^#{aggregate_prefixes.first} - #{aggregate_prefixes.last}"
258
- logger.error "+++++++++++++++ ERROR +++++++++++++++"
259
- recursively_print(e)
260
- raise Parallel::Kill # immediately kill all sub-processes
269
+ result = Parallel.map_with_index(
270
+ groups,
271
+ in_processes: Sequent.configuration.number_of_replay_processes,
272
+ ) do |aggregate_prefixes, index|
273
+ @connected ||= establish_connection
274
+ msg = <<~EOS.chomp
275
+ Group (#{aggregate_prefixes.first}-#{aggregate_prefixes.last}) #{index + 1}/#{number_of_groups} replayed
276
+ EOS
277
+ time(msg) do
278
+ replay_events(aggregate_prefixes, event_types, exclude_ids, replay_persistor, &insert_ids)
261
279
  end
280
+ nil
281
+ rescue StandardError => e
282
+ logger.error "Replaying failed for ids: ^#{aggregate_prefixes.first} - #{aggregate_prefixes.last}"
283
+ logger.error '+++++++++++++++ ERROR +++++++++++++++'
284
+ recursively_print(e)
285
+ raise Parallel::Kill # immediately kill all sub-processes
262
286
  end
263
287
  establish_connection
264
288
  fail if result.nil?
@@ -270,7 +294,7 @@ module Sequent
270
294
  Sequent.configuration.event_store.replay_events_from_cursor(
271
295
  block_size: 1000,
272
296
  get_events: -> { event_stream(aggregate_prefixes, event_types, exclude_already_replayed) },
273
- on_progress: on_progress
297
+ on_progress: on_progress,
274
298
  )
275
299
 
276
300
  replay_persistor.commit
@@ -293,29 +317,31 @@ module Sequent
293
317
  end
294
318
 
295
319
  def groups_of_aggregate_id_prefixes(number_of_groups)
296
- all_prefixes = (0...16 ** LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE).to_a.map { |i| i.to_s(16) } # first x digits of hex
297
- all_prefixes = all_prefixes.map { |s| s.length == 3 ? s : "#{"0" * (3 - s.length)}#{s}" }
320
+ all_prefixes = (0...16**LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE).to_a.map do |i|
321
+ i.to_s(16)
322
+ end
323
+ all_prefixes = all_prefixes.map { |s| s.length == 3 ? s : "#{'0' * (3 - s.length)}#{s}" }
298
324
 
299
325
  logger.info "Number of groups #{number_of_groups}"
300
326
 
301
327
  logger.debug "Prefixes: #{all_prefixes.length}"
302
- fail "Can not have more groups #{number_of_groups} than number of prefixes #{all_prefixes.length}" if number_of_groups > all_prefixes.length
328
+ if number_of_groups > all_prefixes.length
329
+ fail "Can not have more groups #{number_of_groups} than number of prefixes #{all_prefixes.length}"
330
+ end
303
331
 
304
332
  all_prefixes.each_slice(all_prefixes.length / number_of_groups).to_a
305
333
  end
306
334
 
307
- def in_view_schema
308
- Sequent::Support::Database.with_schema_search_path(view_schema, db_config) do
309
- yield
310
- end
335
+ def in_view_schema(&block)
336
+ Sequent::Support::Database.with_schema_search_path(view_schema, db_config, &block)
311
337
  end
312
338
 
313
339
  def drop_old_tables(new_version)
314
340
  versions_to_check = (current_version - 10)..new_version
315
341
  old_tables = versions_to_check.flat_map do |old_version|
316
- exec_sql(
317
- "select table_name from information_schema.tables where table_schema = '#{Sequent.configuration.view_schema_name}' and table_name LIKE '%_#{old_version}'"
318
- ).flat_map { |row| row.values }
342
+ exec_sql(<<~SQL).flat_map(&:values)
343
+ select table_name from information_schema.tables where table_schema = '#{Sequent.configuration.view_schema_name}' and table_name LIKE '%_#{old_version}'
344
+ SQL
319
345
  end
320
346
  old_tables.each do |old_table|
321
347
  exec_sql("DROP TABLE #{Sequent.configuration.view_schema_name}.#{old_table} CASCADE")
@@ -324,7 +350,13 @@ module Sequent
324
350
 
325
351
  def insert_ids
326
352
  ->(progress, done, ids) do
327
- exec_sql("insert into #{ReplayedIds.table_name} (event_id) values #{ids.map { |id| "(#{id})" }.join(',')}") unless ids.empty?
353
+ unless ids.empty?
354
+ exec_sql(
355
+ "insert into #{ReplayedIds.table_name} (event_id) values #{ids.map do |id|
356
+ "(#{id})"
357
+ end.join(',')}",
358
+ )
359
+ end
328
360
  Sequent::Core::EventStore::PRINT_PROGRESS[progress, done, ids] if progress > 0
329
361
  end
330
362
  end
@@ -334,7 +366,9 @@ module Sequent
334
366
 
335
367
  config = Sequent.configuration.dup
336
368
 
337
- replay_projectors = projectors.map { |projector_class| projector_class.new(projector_class.replay_persistor || replay_persistor) }
369
+ replay_projectors = projectors.map do |projector_class|
370
+ projector_class.new(projector_class.replay_persistor || replay_persistor)
371
+ end
338
372
  config.transaction_provider = Sequent::Core::Transactions::NoTransactions.new
339
373
  config.event_handlers = replay_projectors
340
374
 
@@ -346,12 +380,17 @@ module Sequent
346
380
  end
347
381
 
348
382
  def event_stream(aggregate_prefixes, event_types, exclude_already_replayed)
349
- fail ArgumentError.new("aggregate_prefixes is mandatory") unless aggregate_prefixes.present?
383
+ fail ArgumentError, 'aggregate_prefixes is mandatory' unless aggregate_prefixes.present?
350
384
 
351
385
  event_stream = Sequent.configuration.event_record_class.where(event_type: event_types)
352
- event_stream = event_stream.where("substring(aggregate_id::varchar from 1 for #{LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE}) in (?)", aggregate_prefixes)
353
- event_stream = event_stream.where("NOT EXISTS (SELECT 1 FROM #{ReplayedIds.table_name} WHERE event_id = event_records.id)") if exclude_already_replayed
354
- event_stream = event_stream.where("event_records.created_at > ?", 1.day.ago) if exclude_already_replayed
386
+ event_stream = event_stream.where(<<~SQL, aggregate_prefixes)
387
+ substring(aggregate_id::varchar from 1 for #{LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE}) in (?)
388
+ SQL
389
+ if exclude_already_replayed
390
+ event_stream = event_stream
391
+ .where("NOT EXISTS (SELECT 1 FROM #{ReplayedIds.table_name} WHERE event_id = event_records.id)")
392
+ end
393
+ event_stream = event_stream.where('event_records.created_at > ?', 1.day.ago) if exclude_already_replayed
355
394
  event_stream.order('sequence_number ASC').select('id, event_type, event_json, sequence_number')
356
395
  end
357
396