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 +4 -4
- data/lib/sequent/configuration.rb +57 -1
- data/lib/sequent/core/aggregate_repository.rb +2 -2
- data/lib/sequent/core/aggregate_snapshotter.rb +4 -0
- data/lib/sequent/core/base_command_handler.rb +5 -0
- data/lib/sequent/core/core.rb +1 -1
- data/lib/sequent/core/event.rb +2 -2
- data/lib/sequent/core/event_store.rb +16 -16
- data/lib/sequent/core/helpers/attribute_support.rb +7 -7
- data/lib/sequent/core/helpers/message_dispatcher.rb +4 -1
- data/lib/sequent/core/projector.rb +4 -0
- data/lib/sequent/core/transactions/active_record_transaction_provider.rb +2 -1
- data/lib/sequent/core/workflow.rb +4 -0
- data/lib/sequent/migrations/migrations.rb +0 -1
- data/lib/sequent/migrations/planner.rb +4 -4
- data/lib/sequent/migrations/view_schema.rb +2 -2
- data/lib/sequent/sequent.rb +4 -11
- data/lib/sequent/support/database.rb +3 -1
- data/lib/version.rb +1 -1
- metadata +6 -7
- data/lib/sequent/migrations/migrate_events.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2271f62c7221e3eb21eb7707ad2f7df52b9adeae3154c0856b860133af872457
|
4
|
+
data.tar.gz: dc3b99bc7c06957f98f5c45be5cff4082ae0d9cca493a9ea3431fc14eea67e08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
83
|
-
|
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
|
|
data/lib/sequent/core/core.rb
CHANGED
@@ -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'
|
data/lib/sequent/core/event.rb
CHANGED
@@ -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
|
-
|
33
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
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
|
-
|
83
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
210
|
-
|
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
|
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
|
@@ -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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
391
|
-
|
390
|
+
"(#{id})"
|
391
|
+
end.join(',')}",
|
392
392
|
)
|
393
393
|
end
|
394
394
|
Sequent::Core::EventStore::PRINT_PROGRESS[progress, done, ids] if progress > 0
|
data/lib/sequent/sequent.rb
CHANGED
@@ -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.
|
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
|
-
|
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
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:
|
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-
|
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.
|
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.
|
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.
|
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.
|
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
|