sequent 6.0.1 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e420a9289f17d8552364afd49977cdb8cdbc0b37f39445a0a7ce310f9c1a180f
4
- data.tar.gz: 116144ee36558de52bc381b8e99e13d44aad3bedda6d531b380d93b3d7b96445
3
+ metadata.gz: 2271f62c7221e3eb21eb7707ad2f7df52b9adeae3154c0856b860133af872457
4
+ data.tar.gz: dc3b99bc7c06957f98f5c45be5cff4082ae0d9cca493a9ea3431fc14eea67e08
5
5
  SHA512:
6
- metadata.gz: 434eb99e05dda79479a8c8a6529a0d2b3bfa2fc3e02c7143ad314f27a2140d33c6a01f1d3d1a147892b1dafefcd899bed8bde9cbe3b0c76520f3561b5dfa2b05
7
- data.tar.gz: 6fd8a9df8cac32aaad084fd2b472caab478c13840da563b8d3a8e8c9e1d86c32bfc3d43a7e8d7031386a36a127c9be6648d3baaa241dcfb45d92f3d7721a9d4d
6
+ metadata.gz: 150cff9d3a13c1b230dfb71f6897f740c1c4c5ac3448dbb0fd334858229ae1bf3ff67e1bdad897145e5bc0a2a5cd70a31a430e93939857ba753f2f9895a84fa1
7
+ data.tar.gz: ae8ae17080b36ed4b60f361aefb3d9b816b12b037f9eb4022c00969c2b9ce2c78cdfe6f4c67358d02c376ec37479d5951ad10e92944ba4b3e6b056b3fd8c2b5e
@@ -36,6 +36,7 @@ module Sequent
36
36
 
37
37
  attr_accessor :aggregate_repository,
38
38
  :event_store,
39
+ :event_store_cache_event_types,
39
40
  :command_service,
40
41
  :event_record_class,
41
42
  :stream_record_class,
@@ -63,7 +64,8 @@ module Sequent
63
64
  :enable_multiple_database_support,
64
65
  :primary_database_role,
65
66
  :primary_database_key,
66
- :time_precision
67
+ :time_precision,
68
+ :enable_autoregistration
67
69
 
68
70
  attr_reader :migrations_class_name,
69
71
  :versions_table_name,
@@ -73,10 +75,13 @@ module Sequent
73
75
  @instance ||= new
74
76
  end
75
77
 
78
+ # Create a new instance of Configuration
76
79
  def self.reset
77
80
  @instance = new
78
81
  end
79
82
 
83
+ # Restore the given Configuration
84
+ # @param configuration [Sequent::Configuration]
80
85
  def self.restore(configuration)
81
86
  @instance = configuration
82
87
  end
@@ -88,6 +93,7 @@ module Sequent
88
93
  self.command_middleware = Sequent::Core::Middleware::Chain.new
89
94
 
90
95
  self.aggregate_repository = Sequent::Core::AggregateRepository.new
96
+ self.event_store_cache_event_types = true
91
97
  self.event_store = Sequent::Core::EventStore.new
92
98
  self.command_service = Sequent::Core::CommandService.new
93
99
  self.event_record_class = Sequent::Core::EventRecord
@@ -121,6 +127,8 @@ module Sequent
121
127
  self.primary_database_key = :primary
122
128
 
123
129
  self.time_precision = DEFAULT_TIME_PRECISION
130
+
131
+ self.enable_autoregistration = false
124
132
  end
125
133
 
126
134
  def can_use_multiple_databases?
@@ -149,5 +157,53 @@ module Sequent
149
157
 
150
158
  @migrations_class_name = class_name
151
159
  end
160
+
161
+ def autoregister!
162
+ return unless enable_autoregistration
163
+
164
+ # Only autoregister the AggregateSnapshotter if the autoregistration is enabled
165
+ Sequent::Core::AggregateSnapshotter.skip_autoregister = false
166
+
167
+ Rails.autoloaders.main.eager_load(force: true) if defined?(Rails)
168
+
169
+ self.class.instance.command_handlers ||= []
170
+ for_each_autoregisterable_descenant_of(Sequent::CommandHandler) do |command_handler_class|
171
+ Sequent.logger.debug("[Configuration] Autoregistering CommandHandler #{command_handler_class}")
172
+ self.class.instance.command_handlers << command_handler_class.new
173
+ end
174
+
175
+ self.class.instance.event_handlers ||= []
176
+ for_each_autoregisterable_descenant_of(Sequent::Projector) do |projector_class|
177
+ Sequent.logger.debug("[Configuration] Autoregistering Projector #{projector_class}")
178
+ self.class.instance.event_handlers << projector_class.new
179
+ end
180
+
181
+ for_each_autoregisterable_descenant_of(Sequent::Workflow) do |workflow_class|
182
+ Sequent.logger.debug("[Configuration] Autoregistering Workflow #{workflow_class}")
183
+ self.class.instance.event_handlers << workflow_class.new
184
+ end
185
+
186
+ self.class.instance.command_handlers.map(&:class).tally.each do |(clazz, count)|
187
+ if count > 1
188
+ fail "CommandHandler #{clazz} is registered #{count} times. A CommandHandler can only be registered once"
189
+ end
190
+ end
191
+
192
+ self.class.instance.event_handlers.map(&:class).tally.each do |(clazz, count)|
193
+ if count > 1
194
+ fail "EventHandler #{clazz} is registered #{count} times. An EventHandler can only be registered once"
195
+ end
196
+ end
197
+ end
198
+
199
+ private
200
+
201
+ def for_each_autoregisterable_descenant_of(clazz, &block)
202
+ clazz
203
+ .descendants
204
+ .reject(&:abstract_class)
205
+ .reject(&:skip_autoregister)
206
+ .each(&block)
207
+ end
152
208
  end
153
209
  end
@@ -79,8 +79,8 @@ module Sequent
79
79
  .configuration
80
80
  .event_store
81
81
  .stream_events_for_aggregate(aggregate_id, load_until: load_until) do |event_stream|
82
- aggregate.stream_from_history(event_stream)
83
- end
82
+ aggregate.stream_from_history(event_stream)
83
+ end
84
84
 
85
85
  if clazz
86
86
  fail TypeError, "#{aggregate.class} is not a #{clazz}" unless aggregate.class <= clazz
@@ -15,6 +15,10 @@ module Sequent
15
15
  end
16
16
 
17
17
  class AggregateSnapshotter < BaseCommandHandler
18
+ # By default skip autoregistering this CommandHandler.
19
+ # The AggregateSnapshotter is only autoregistered if autoregistration is enabled.
20
+ self.skip_autoregister = true
21
+
18
22
  on SnapshotCommand do |command|
19
23
  aggregate_ids = Sequent.configuration.event_store.aggregates_that_need_snapshots(
20
24
  @last_aggregate_id,
@@ -21,6 +21,11 @@ module Sequent
21
21
  class BaseCommandHandler
22
22
  include Sequent::Core::Helpers::UuidHelper
23
23
  include Sequent::Core::Helpers::MessageHandler
24
+ extend ActiveSupport::DescendantsTracker
25
+
26
+ class << self
27
+ attr_accessor :abstract_class, :skip_autoregister
28
+ end
24
29
 
25
30
  protected
26
31
 
@@ -16,7 +16,7 @@ require_relative 'projector'
16
16
  require_relative 'event_store'
17
17
  require_relative 'event_record'
18
18
  require_relative 'command_record'
19
- require_relative 'aggregate_snapshotter'
20
19
  require_relative 'workflow'
21
20
  require_relative 'random_uuid_generator'
22
21
  require_relative 'event_publisher'
22
+ require_relative 'aggregate_snapshotter'
@@ -29,8 +29,8 @@ module Sequent
29
29
  .reject { |k| payload_variables.include?(k) }
30
30
  .select { |k| self.class.types.keys.include?(to_attribute_name(k)) }
31
31
  .each do |k|
32
- result[k.to_s[1..-1].to_sym] = instance_variable_get(k)
33
- end
32
+ result[k.to_s[1..-1].to_sym] = instance_variable_get(k)
33
+ end
34
34
  result
35
35
  end
36
36
 
@@ -35,14 +35,6 @@ module Sequent
35
35
  end
36
36
  end
37
37
 
38
- def initialize(cache_event_types: true)
39
- @event_types = if cache_event_types
40
- ThreadSafe::Cache.new
41
- else
42
- NoEventTypesCache.new
43
- end
44
- end
45
-
46
38
  ##
47
39
  # Stores the events in the EventStore and publishes the events
48
40
  # to the registered event_handlers.
@@ -114,13 +106,13 @@ module Sequent
114
106
  events
115
107
  .group_by(&:aggregate_id)
116
108
  .map do |aggregate_id, es|
117
- [
118
- streams.find do |stream_record|
119
- stream_record.aggregate_id == aggregate_id
120
- end.event_stream,
121
- es,
122
- ]
123
- end
109
+ [
110
+ streams.find do |stream_record|
111
+ stream_record.aggregate_id == aggregate_id
112
+ end.event_stream,
113
+ es,
114
+ ]
115
+ end
124
116
  end
125
117
 
126
118
  def aggregate_query(aggregate_id)
@@ -217,6 +209,14 @@ module Sequent
217
209
 
218
210
  private
219
211
 
212
+ def event_types
213
+ @event_types = if Sequent.configuration.event_store_cache_event_types
214
+ ThreadSafe::Cache.new
215
+ else
216
+ NoEventTypesCache.new
217
+ end
218
+ end
219
+
220
220
  def column_names
221
221
  @column_names ||= Sequent
222
222
  .configuration
@@ -238,7 +238,7 @@ module Sequent
238
238
  end
239
239
 
240
240
  def resolve_event_type(event_type)
241
- @event_types.fetch_or_store(event_type) { |k| Class.const_get(k) }
241
+ event_types.fetch_or_store(event_type) { |k| Class.const_get(k) }
242
242
  end
243
243
 
244
244
  def publish_events(events)
@@ -79,8 +79,8 @@ module Sequent
79
79
  super if defined?(super)
80
80
  ensure_known_attributes(attrs)
81
81
  #{@types.map do |attribute, _|
82
- "@#{attribute} = attrs[:#{attribute}]"
83
- end.join("\n ")}
82
+ "@#{attribute} = attrs[:#{attribute}]"
83
+ end.join("\n ")}
84
84
  self
85
85
  end
86
86
  EOS
@@ -89,8 +89,8 @@ EOS
89
89
  def update_all_attributes_from_json(attrs)
90
90
  super if defined?(super)
91
91
  #{@types.map do |attribute, type|
92
- "@#{attribute} = #{type}.deserialize_from_json(attrs['#{attribute}'])"
93
- end.join("\n ")}
92
+ "@#{attribute} = #{type}.deserialize_from_json(attrs['#{attribute}'])"
93
+ end.join("\n ")}
94
94
  end
95
95
  EOS
96
96
  end
@@ -206,10 +206,10 @@ EOS
206
206
  value
207
207
  .select { |val| val.respond_to?(:validation_errors) }
208
208
  .each_with_index do |val, index|
209
- val.validation_errors.each do |k, v|
210
- result["#{field[0]}_#{index}_#{k}".to_sym] = v
209
+ val.validation_errors.each do |k, v|
210
+ result["#{field[0]}_#{index}_#{k}".to_sym] = v
211
+ end
211
212
  end
212
- end
213
213
  end
214
214
  end
215
215
  prefix ? HashWithIndifferentAccess[result.map { |k, v| ["#{prefix}_#{k}", v] }] : result
@@ -12,7 +12,10 @@ module Sequent
12
12
  def dispatch_message(message)
13
13
  @message_router
14
14
  .match_message(message)
15
- .each { |handler| @context.instance_exec(message, &handler) }
15
+ .each do |handler|
16
+ Sequent.logger.debug("[MessageDispatcher] Handler #{@context.class} handling #{message.class}")
17
+ @context.instance_exec(message, &handler)
18
+ end
16
19
  end
17
20
  end
18
21
  end
@@ -88,6 +88,10 @@ module Sequent
88
88
  include Migratable
89
89
  extend ActiveSupport::DescendantsTracker
90
90
 
91
+ class << self
92
+ attr_accessor :abstract_class, :skip_autoregister
93
+ end
94
+
91
95
  def initialize(persistor = Sequent::Core::Persistors::ActiveRecordPersistor.new)
92
96
  ensure_valid!
93
97
  @persistor = persistor
@@ -30,8 +30,9 @@ module Sequent
30
30
  #
31
31
  class ActiveRecordTransactionProvider
32
32
  def transactional(&block)
33
- Sequent::ApplicationRecord.transaction(requires_new: true, &block)
33
+ result = Sequent::ApplicationRecord.transaction(requires_new: true, &block)
34
34
  after_commit_queue.pop.call until after_commit_queue.empty?
35
+ result
35
36
  ensure
36
37
  clear_after_commit_queue
37
38
  end
@@ -9,6 +9,10 @@ module Sequent
9
9
  include Helpers::MessageHandler
10
10
  extend ActiveSupport::DescendantsTracker
11
11
 
12
+ class << self
13
+ attr_accessor :abstract_class, :skip_autoregister
14
+ end
15
+
12
16
  def self.on(*args, **opts, &block)
13
17
  decorated_block = ->(event) do
14
18
  begin
@@ -5,7 +5,6 @@ module Sequent
5
5
  end
6
6
  end
7
7
 
8
- require_relative 'migrate_events'
9
8
  require_relative 'projectors'
10
9
  require_relative 'view_schema'
11
10
  require_relative 'functions'
@@ -69,10 +69,10 @@ module Sequent
69
69
  .each_with_index
70
70
  .select { |migration, _index| migration.instance_of?(AlterTable) }
71
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)
72
+ migrations
73
+ .slice((index + 1)..-1)
74
+ .find { |m| m.instance_of?(ReplayTable) && m.record_class == migration.record_class }
75
+ end.map(&:first)
76
76
  end
77
77
 
78
78
  def remove_redundancy(grouped_migrations)
@@ -387,8 +387,8 @@ module Sequent
387
387
  unless ids.empty?
388
388
  exec_sql(
389
389
  "insert into #{ReplayedIds.table_name} (event_id) values #{ids.map do |id|
390
- "(#{id})"
391
- end.join(',')}",
390
+ "(#{id})"
391
+ end.join(',')}",
392
392
  )
393
393
  end
394
394
  Sequent::Core::EventStore::PRINT_PROGRESS[progress, done, ids] if progress > 0
@@ -22,21 +22,14 @@ module Sequent
22
22
  # A minimal setup could look like this:
23
23
  #
24
24
  # Sequent.configure do |config|
25
- # config.event_handlers = [
26
- # MyProjector.new,
27
- # AnotherProjector.new,
28
- # MyWorkflow.new,
29
- # ]
30
- #
31
- # config.command_handlers = [
32
- # MyCommandHandler.new,
33
- # ]
34
- #
25
+ # config.enable_autoregistration = true
35
26
  # end
36
27
  #
37
- #
28
+ # Calling configure a second time will create a new configuration
38
29
  def self.configure
30
+ Configuration.reset
39
31
  yield Configuration.instance
32
+ Configuration.instance.autoregister!
40
33
  end
41
34
 
42
35
  def self.configuration
@@ -53,7 +53,9 @@ module Sequent
53
53
  db_config = db_config.deep_merge(
54
54
  Sequent.configuration.primary_database_key => db_config_overrides,
55
55
  ).stringify_keys
56
- ActiveRecord.legacy_connection_handling = false
56
+ if Gem.loaded_specs['activerecord'].version < Gem::Version.create('7.1.0')
57
+ ActiveRecord.legacy_connection_handling = false
58
+ end
57
59
  ActiveRecord::Base.configurations = db_config.stringify_keys
58
60
  ActiveRecord::Base.connects_to database: {
59
61
  Sequent.configuration.primary_database_role => Sequent.configuration.primary_database_key,
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sequent
4
- VERSION = '6.0.1'
4
+ VERSION = '7.0.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequent
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.1
4
+ version: 7.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Vonk
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2023-09-28 00:00:00.000000000 Z
15
+ date: 2023-11-02 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activemodel
@@ -23,7 +23,7 @@ dependencies:
23
23
  version: '5.0'
24
24
  - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '7.1'
26
+ version: '7.2'
27
27
  type: :runtime
28
28
  prerelease: false
29
29
  version_requirements: !ruby/object:Gem::Requirement
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: '5.0'
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '7.1'
36
+ version: '7.2'
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: activerecord
39
39
  requirement: !ruby/object:Gem::Requirement
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '5.0'
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '7.1'
46
+ version: '7.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
@@ -53,7 +53,7 @@ dependencies:
53
53
  version: '5.0'
54
54
  - - "<"
55
55
  - !ruby/object:Gem::Version
56
- version: '7.1'
56
+ version: '7.2'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: bcrypt
59
59
  requirement: !ruby/object:Gem::Requirement
@@ -430,7 +430,6 @@ files:
430
430
  - lib/sequent/generator/template_project/spec/spec_helper.rb
431
431
  - lib/sequent/migrations/executor.rb
432
432
  - lib/sequent/migrations/functions.rb
433
- - lib/sequent/migrations/migrate_events.rb
434
433
  - lib/sequent/migrations/migrations.rb
435
434
  - lib/sequent/migrations/planner.rb
436
435
  - lib/sequent/migrations/projectors.rb
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ##
4
- # When you need to upgrade the event store based on information of the previous schema version
5
- # this is the place you need to implement a migration.
6
- # Examples are: corrupt events (due to insufficient testing for instance...)
7
- # or adding extra events to the event stream if a new concept is introduced.
8
- #
9
- # To implement a migration you should create a class according to the following contract:
10
- # module Database
11
- # class MigrateToVersionXXX
12
- # def initialize(env)
13
- # @env = env
14
- # end
15
- #
16
- # def migrate
17
- # # your migration code here...
18
- # end
19
- # end
20
- # end
21
- #
22
- module Sequent
23
- module Migrations
24
- class MigrateEvents
25
- ##
26
- # @param env The string representing the current environment. E.g. "development", "production"
27
- def initialize(env)
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
31
- @env = env
32
- end
33
-
34
- ##
35
- #
36
- # @param current_version The current version of the application. E.g. 10
37
- # @param new_version The version to migrate to. E.g. 11
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
40
- #
41
- def execute_migrations(current_version, new_version)
42
- migrations(current_version, new_version).each do |migration_class|
43
- migration = migration_class.new(@env)
44
- begin
45
- migration.migrate
46
- ensure
47
- yield(migration.version) if block_given?
48
- end
49
- end
50
- end
51
-
52
- def migrations(current_version, new_version)
53
- return [] if current_version == 0
54
-
55
- ((current_version + 1)..new_version).map do |upgrade_to_version|
56
- Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
57
- rescue NameError
58
- nil
59
- end.compact
60
- end
61
-
62
- def has_migrations?(current_version, new_version)
63
- migrations(current_version, new_version).any?
64
- end
65
- end
66
- end
67
- end