sequent 3.5.0 → 4.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/notices.rb +4 -0
- data/lib/sequent.rb +2 -0
- data/lib/sequent/configuration.rb +3 -0
- data/lib/sequent/core/aggregate_repository.rb +2 -1
- data/lib/sequent/core/command_record.rb +4 -1
- data/lib/sequent/core/command_service.rb +2 -0
- data/lib/sequent/core/event_store.rb +13 -2
- data/lib/sequent/core/transactions/active_record_transaction_provider.rb +5 -3
- data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +1 -1
- data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +1 -1
- data/lib/sequent/migrations/executor.rb +12 -0
- data/lib/sequent/migrations/view_schema.rb +10 -0
- data/lib/sequent/rake/migration_tasks.rb +1 -1
- data/lib/sequent/test/command_handler_helpers.rb +4 -0
- data/lib/sequent/util/skip_if_already_processing.rb +19 -5
- data/lib/version.rb +1 -1
- metadata +50 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3322a4b950e847a5818555b2718df70e2b81a8e398074309a0b58c2a8d332ce5
|
4
|
+
data.tar.gz: 6136697a8a9596e999fabf3814509428b06188a0ac577fa3443a80ec190cbdd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8ce675ae0a16274630066192086fb8c46bb0306e9280fd4b8901500af4a7af56844c5d6c40cd0f45a87342c33a4faeb2eee48f0dc0fb05a0a09046a2dea7414
|
7
|
+
data.tar.gz: e750e54d72de1c8641a513839c675adeb32fbeaa3435528a8aca755a951a7572d696e9348b7594e104f044978a0e9780f8e080ff1ad5e4ea9b7cc203fac6fee2
|
data/lib/notices.rb
ADDED
data/lib/sequent.rb
CHANGED
@@ -13,6 +13,7 @@ module Sequent
|
|
13
13
|
|
14
14
|
DEFAULT_MIGRATION_SQL_FILES_DIRECTORY = 'db/tables'
|
15
15
|
DEFAULT_DATABASE_CONFIG_DIRECTORY = 'db'
|
16
|
+
DEFAULT_DATABASE_SCHEMA_DIRECTORY = 'db'
|
16
17
|
|
17
18
|
DEFAULT_VIEW_SCHEMA_NAME = 'view_schema'
|
18
19
|
DEFAULT_EVENT_STORE_SCHEMA_NAME= 'sequent_schema'
|
@@ -61,6 +62,7 @@ module Sequent
|
|
61
62
|
:online_replay_persistor_class,
|
62
63
|
:number_of_replay_processes,
|
63
64
|
:database_config_directory,
|
65
|
+
:database_schema_directory,
|
64
66
|
:event_store_schema_name
|
65
67
|
|
66
68
|
attr_accessor :strict_check_attributes_on_apply_events
|
@@ -109,6 +111,7 @@ module Sequent
|
|
109
111
|
self.offline_replay_persistor_class = DEFAULT_OFFLINE_REPLAY_PERSISTOR_CLASS
|
110
112
|
self.online_replay_persistor_class = DEFAULT_ONLINE_REPLAY_PERSISTOR_CLASS
|
111
113
|
self.database_config_directory = DEFAULT_DATABASE_CONFIG_DIRECTORY
|
114
|
+
self.database_schema_directory = DEFAULT_DATABASE_SCHEMA_DIRECTORY
|
112
115
|
self.strict_check_attributes_on_apply_events = DEFAULT_STRICT_CHECK_ATTRIBUTES_ON_APPLY_EVENTS
|
113
116
|
|
114
117
|
self.logger = Logger.new(STDOUT).tap {|l| l.level = Logger::INFO }
|
@@ -100,7 +100,8 @@ module Sequent
|
|
100
100
|
##
|
101
101
|
# Returns whether the event store has an aggregate with the given id
|
102
102
|
def contains_aggregate?(aggregate_id)
|
103
|
-
Sequent.configuration.event_store.stream_exists?(aggregate_id)
|
103
|
+
Sequent.configuration.event_store.stream_exists?(aggregate_id) &&
|
104
|
+
Sequent.configuration.event_store.events_exists?(aggregate_id)
|
104
105
|
end
|
105
106
|
|
106
107
|
# Gets all uncommitted_events from the 'registered' aggregates
|
@@ -42,7 +42,10 @@ module Sequent
|
|
42
42
|
validates_presence_of :command_type, :command_json
|
43
43
|
|
44
44
|
def parent
|
45
|
-
EventRecord
|
45
|
+
EventRecord
|
46
|
+
.where(aggregate_id: event_aggregate_id, sequence_number: event_sequence_number)
|
47
|
+
.where('event_type != ?', Sequent::Core::SnapshotEvent.name)
|
48
|
+
.first
|
46
49
|
end
|
47
50
|
|
48
51
|
def children
|
@@ -52,6 +52,7 @@ module Sequent
|
|
52
52
|
while(!command_queue.empty?) do
|
53
53
|
process_command(command_queue.pop)
|
54
54
|
end
|
55
|
+
Sequent::Util.done_processing(:command_service_process_commands)
|
55
56
|
end
|
56
57
|
ensure
|
57
58
|
command_queue.clear
|
@@ -103,6 +104,7 @@ module Sequent
|
|
103
104
|
|
104
105
|
# Raised when BaseCommand.valid? returns false
|
105
106
|
class CommandNotValid < ArgumentError
|
107
|
+
attr_reader :command
|
106
108
|
|
107
109
|
def initialize(command)
|
108
110
|
@command = command
|
@@ -88,6 +88,9 @@ ORDER BY sequence_number ASC, (CASE event_type WHEN #{quote Sequent.configuratio
|
|
88
88
|
Sequent.configuration.stream_record_class.exists?(aggregate_id: aggregate_id)
|
89
89
|
end
|
90
90
|
|
91
|
+
def events_exists?(aggregate_id)
|
92
|
+
Sequent.configuration.event_record_class.exists?(aggregate_id: aggregate_id)
|
93
|
+
end
|
91
94
|
##
|
92
95
|
# Replays all events in the event store to the registered event_handlers.
|
93
96
|
#
|
@@ -166,7 +169,15 @@ SELECT aggregate_id
|
|
166
169
|
private
|
167
170
|
|
168
171
|
def column_names
|
169
|
-
@column_names ||= Sequent
|
172
|
+
@column_names ||= Sequent
|
173
|
+
.configuration
|
174
|
+
.event_record_class
|
175
|
+
.column_names
|
176
|
+
.reject { |c| c == primary_key_event_records }
|
177
|
+
end
|
178
|
+
|
179
|
+
def primary_key_event_records
|
180
|
+
@primary_key_event_records ||= Sequent.configuration.event_record_class.primary_key
|
170
181
|
end
|
171
182
|
|
172
183
|
def deserialize_event(event_hash)
|
@@ -208,7 +219,7 @@ SELECT aggregate_id
|
|
208
219
|
.join(',')
|
209
220
|
columns = column_names.map { |c| connection.quote_column_name(c) }.join(',')
|
210
221
|
sql = %Q{insert into #{connection.quote_table_name(Sequent.configuration.event_record_class.table_name)} (#{columns}) values #{values}}
|
211
|
-
Sequent.configuration.event_record_class.connection.insert(sql)
|
222
|
+
Sequent.configuration.event_record_class.connection.insert(sql, nil, primary_key_event_records)
|
212
223
|
rescue ActiveRecord::RecordNotUnique
|
213
224
|
fail OptimisticLockingError.new
|
214
225
|
end
|
@@ -7,7 +7,9 @@ module Sequent
|
|
7
7
|
Sequent::ApplicationRecord.transaction(requires_new: true) do
|
8
8
|
yield
|
9
9
|
end
|
10
|
-
after_commit_queue.
|
10
|
+
while(!after_commit_queue.empty?) do
|
11
|
+
after_commit_queue.pop.call
|
12
|
+
end
|
11
13
|
ensure
|
12
14
|
clear_after_commit_queue
|
13
15
|
end
|
@@ -19,11 +21,11 @@ module Sequent
|
|
19
21
|
private
|
20
22
|
|
21
23
|
def after_commit_queue
|
22
|
-
Thread.current[:after_commit_queue] ||=
|
24
|
+
Thread.current[:after_commit_queue] ||= Queue.new
|
23
25
|
end
|
24
26
|
|
25
27
|
def clear_after_commit_queue
|
26
|
-
|
28
|
+
after_commit_queue.clear
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -21,6 +21,18 @@ module Sequent
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def create_indexes_after_execute_online(plan)
|
25
|
+
plan.replay_tables.each do |migration|
|
26
|
+
table = migration.record_class
|
27
|
+
original_table_name = table.table_name.gsub("_#{migration.version}", '')
|
28
|
+
indexes_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{original_table_name}.indexes.sql"
|
29
|
+
if File.exist?(indexes_file_name)
|
30
|
+
statements = sql_file_to_statements(indexes_file_name) { |raw_sql| raw_sql.gsub('%SUFFIX%', "_#{migration.version}") }
|
31
|
+
statements.each(&method(:exec_sql))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
24
36
|
def execute_offline(plan, current_version)
|
25
37
|
plan.replay_tables.each do |migration|
|
26
38
|
table = migration.record_class
|
@@ -98,6 +98,12 @@ module Sequent
|
|
98
98
|
Sequent::Core::Migratable.all.flat_map(&:managed_tables).each do |table|
|
99
99
|
statements = sql_file_to_statements("#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.sql") { |raw_sql| raw_sql.remove('%SUFFIX%') }
|
100
100
|
statements.each { |statement| exec_sql(statement) }
|
101
|
+
|
102
|
+
indexes_file_name = "#{Sequent.configuration.migration_sql_files_directory}/#{table.table_name}.indexes.sql"
|
103
|
+
if File.exist?(indexes_file_name)
|
104
|
+
statements = sql_file_to_statements(indexes_file_name) { |raw_sql| raw_sql.remove('%SUFFIX%') }
|
105
|
+
statements.each(&method(:exec_sql))
|
106
|
+
end
|
101
107
|
end
|
102
108
|
end
|
103
109
|
end
|
@@ -159,6 +165,10 @@ module Sequent
|
|
159
165
|
if plan.projectors.any?
|
160
166
|
replay!(Sequent.configuration.online_replay_persistor_class.new)
|
161
167
|
end
|
168
|
+
|
169
|
+
in_view_schema do
|
170
|
+
executor.create_indexes_after_execute_online(plan)
|
171
|
+
end
|
162
172
|
rescue Exception => e
|
163
173
|
rollback_migration
|
164
174
|
raise e
|
@@ -55,7 +55,7 @@ module Sequent
|
|
55
55
|
|
56
56
|
def create_event_store(db_config)
|
57
57
|
event_store_schema = Sequent.configuration.event_store_schema_name
|
58
|
-
sequent_schema = File.join(Sequent.configuration.
|
58
|
+
sequent_schema = File.join(Sequent.configuration.database_schema_directory, "#{event_store_schema}.rb")
|
59
59
|
fail "File #{sequent_schema} does not exist. Check your Sequent configuration." unless File.exists?(sequent_schema)
|
60
60
|
|
61
61
|
Sequent::Support::Database.establish_connection(db_config)
|
@@ -1,15 +1,29 @@
|
|
1
1
|
module Sequent
|
2
2
|
module Util
|
3
|
-
|
4
|
-
|
3
|
+
##
|
4
|
+
# Returns if the current Thread is already processing work
|
5
|
+
# given the +processing_key+ otherwise
|
6
|
+
# it yields the given +&block+.
|
7
|
+
#
|
8
|
+
# Useful in a Queue and Processing strategy
|
9
|
+
def self.skip_if_already_processing(processing_key, &block)
|
10
|
+
return if Thread.current[processing_key]
|
5
11
|
|
6
12
|
begin
|
7
|
-
Thread.current[
|
13
|
+
Thread.current[processing_key] = true
|
8
14
|
|
9
|
-
|
15
|
+
yield
|
10
16
|
ensure
|
11
|
-
Thread.current[
|
17
|
+
Thread.current[processing_key] = nil
|
12
18
|
end
|
13
19
|
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Reset the given +processing_key+ for the current Thread.
|
23
|
+
#
|
24
|
+
# Usefull to make a block protected by +skip_if_already_processing+ reentrant.
|
25
|
+
def self.done_processing(processing_key)
|
26
|
+
Thread.current[processing_key] = nil
|
27
|
+
end
|
14
28
|
end
|
15
29
|
end
|
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: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Vonk
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
- Erik Rozendaal
|
10
10
|
- Mike van Diepen
|
11
11
|
- Stephan van Diepen
|
12
|
-
autorequire:
|
12
|
+
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2021-02-24 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activerecord
|
@@ -21,9 +21,9 @@ dependencies:
|
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: '5.0'
|
24
|
-
- - "
|
24
|
+
- - "<"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 6.0.4
|
27
27
|
type: :runtime
|
28
28
|
prerelease: false
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -31,9 +31,9 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '5.0'
|
34
|
-
- - "
|
34
|
+
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 6.0.4
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: activemodel
|
39
39
|
requirement: !ruby/object:Gem::Requirement
|
@@ -41,9 +41,9 @@ dependencies:
|
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '5.0'
|
44
|
-
- - "
|
44
|
+
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 6.0.4
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -51,23 +51,23 @@ dependencies:
|
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '5.0'
|
54
|
-
- - "
|
54
|
+
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 6.0.4
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: pg
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: '1.
|
63
|
+
version: '1.2'
|
64
64
|
type: :runtime
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: '1.
|
70
|
+
version: '1.2'
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: postgresql_cursor
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,14 +116,14 @@ dependencies:
|
|
116
116
|
requirements:
|
117
117
|
- - "~>"
|
118
118
|
- !ruby/object:Gem::Version
|
119
|
-
version: '1.
|
119
|
+
version: '1.20'
|
120
120
|
type: :runtime
|
121
121
|
prerelease: false
|
122
122
|
version_requirements: !ruby/object:Gem::Requirement
|
123
123
|
requirements:
|
124
124
|
- - "~>"
|
125
125
|
- !ruby/object:Gem::Version
|
126
|
-
version: '1.
|
126
|
+
version: '1.20'
|
127
127
|
- !ruby/object:Gem::Dependency
|
128
128
|
name: bcrypt
|
129
129
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,16 +142,22 @@ dependencies:
|
|
142
142
|
name: parser
|
143
143
|
requirement: !ruby/object:Gem::Requirement
|
144
144
|
requirements:
|
145
|
-
- - "
|
145
|
+
- - ">="
|
146
146
|
- !ruby/object:Gem::Version
|
147
147
|
version: 2.6.5
|
148
|
+
- - "<="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '3'
|
148
151
|
type: :runtime
|
149
152
|
prerelease: false
|
150
153
|
version_requirements: !ruby/object:Gem::Requirement
|
151
154
|
requirements:
|
152
|
-
- - "
|
155
|
+
- - ">="
|
153
156
|
- !ruby/object:Gem::Version
|
154
157
|
version: 2.6.5
|
158
|
+
- - "<="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '3'
|
155
161
|
- !ruby/object:Gem::Dependency
|
156
162
|
name: i18n
|
157
163
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,20 +172,34 @@ dependencies:
|
|
166
172
|
- - ">="
|
167
173
|
- !ruby/object:Gem::Version
|
168
174
|
version: '0'
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: tzinfo
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "<="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: 1.2.7
|
182
|
+
type: :runtime
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - "<="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: 1.2.7
|
169
189
|
- !ruby/object:Gem::Dependency
|
170
190
|
name: rspec
|
171
191
|
requirement: !ruby/object:Gem::Requirement
|
172
192
|
requirements:
|
173
193
|
- - "~>"
|
174
194
|
- !ruby/object:Gem::Version
|
175
|
-
version: '3.
|
195
|
+
version: '3.10'
|
176
196
|
type: :development
|
177
197
|
prerelease: false
|
178
198
|
version_requirements: !ruby/object:Gem::Requirement
|
179
199
|
requirements:
|
180
200
|
- - "~>"
|
181
201
|
- !ruby/object:Gem::Version
|
182
|
-
version: '3.
|
202
|
+
version: '3.10'
|
183
203
|
- !ruby/object:Gem::Dependency
|
184
204
|
name: timecop
|
185
205
|
requirement: !ruby/object:Gem::Requirement
|
@@ -200,14 +220,14 @@ dependencies:
|
|
200
220
|
requirements:
|
201
221
|
- - "~>"
|
202
222
|
- !ruby/object:Gem::Version
|
203
|
-
version: '3.
|
223
|
+
version: '3.10'
|
204
224
|
type: :development
|
205
225
|
prerelease: false
|
206
226
|
version_requirements: !ruby/object:Gem::Requirement
|
207
227
|
requirements:
|
208
228
|
- - "~>"
|
209
229
|
- !ruby/object:Gem::Version
|
210
|
-
version: '3.
|
230
|
+
version: '3.10'
|
211
231
|
- !ruby/object:Gem::Dependency
|
212
232
|
name: rspec-collection_matchers
|
213
233
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,28 +262,28 @@ dependencies:
|
|
242
262
|
requirements:
|
243
263
|
- - "~>"
|
244
264
|
- !ruby/object:Gem::Version
|
245
|
-
version: '0.
|
265
|
+
version: '0.13'
|
246
266
|
type: :development
|
247
267
|
prerelease: false
|
248
268
|
version_requirements: !ruby/object:Gem::Requirement
|
249
269
|
requirements:
|
250
270
|
- - "~>"
|
251
271
|
- !ruby/object:Gem::Version
|
252
|
-
version: '0.
|
272
|
+
version: '0.13'
|
253
273
|
- !ruby/object:Gem::Dependency
|
254
274
|
name: simplecov
|
255
275
|
requirement: !ruby/object:Gem::Requirement
|
256
276
|
requirements:
|
257
277
|
- - "~>"
|
258
278
|
- !ruby/object:Gem::Version
|
259
|
-
version: '0.
|
279
|
+
version: '0.21'
|
260
280
|
type: :development
|
261
281
|
prerelease: false
|
262
282
|
version_requirements: !ruby/object:Gem::Requirement
|
263
283
|
requirements:
|
264
284
|
- - "~>"
|
265
285
|
- !ruby/object:Gem::Version
|
266
|
-
version: '0.
|
286
|
+
version: '0.21'
|
267
287
|
description: Sequent is a CQRS and event sourcing framework for Ruby.
|
268
288
|
email:
|
269
289
|
- lars.vonk@gmail.com
|
@@ -278,6 +298,7 @@ extra_rdoc_files: []
|
|
278
298
|
files:
|
279
299
|
- bin/sequent
|
280
300
|
- db/sequent_schema.rb
|
301
|
+
- lib/notices.rb
|
281
302
|
- lib/sequent.rb
|
282
303
|
- lib/sequent/application_record.rb
|
283
304
|
- lib/sequent/configuration.rb
|
@@ -390,7 +411,7 @@ homepage: https://github.com/zilverline/sequent
|
|
390
411
|
licenses:
|
391
412
|
- MIT
|
392
413
|
metadata: {}
|
393
|
-
post_install_message:
|
414
|
+
post_install_message:
|
394
415
|
rdoc_options: []
|
395
416
|
require_paths:
|
396
417
|
- lib
|
@@ -398,15 +419,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
398
419
|
requirements:
|
399
420
|
- - ">="
|
400
421
|
- !ruby/object:Gem::Version
|
401
|
-
version: '2.
|
422
|
+
version: '2.7'
|
402
423
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
403
424
|
requirements:
|
404
425
|
- - ">="
|
405
426
|
- !ruby/object:Gem::Version
|
406
427
|
version: '0'
|
407
428
|
requirements: []
|
408
|
-
rubygems_version: 3.
|
409
|
-
signing_key:
|
429
|
+
rubygems_version: 3.2.3
|
430
|
+
signing_key:
|
410
431
|
specification_version: 4
|
411
432
|
summary: Event sourcing framework for Ruby
|
412
433
|
test_files: []
|