sequent 3.5.0 → 4.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11621c1f62780395fc4954a6a5180aa027eb8a26a88d42da6419b20f9e312122
4
- data.tar.gz: 855d52912a637416cfdaf66fad0bdf15d9ea4f4474e8896e7441dc8d56afa98b
3
+ metadata.gz: 3322a4b950e847a5818555b2718df70e2b81a8e398074309a0b58c2a8d332ce5
4
+ data.tar.gz: 6136697a8a9596e999fabf3814509428b06188a0ac577fa3443a80ec190cbdd7
5
5
  SHA512:
6
- metadata.gz: c45c07e3e9ac5a4d52bb82dfb7bd76c7096115eb97f0f87477ee99b95eec513a68e67f422a2fb76d23626596c206a5c881f14afce281129e071b3c383ba36979
7
- data.tar.gz: de31f973652d7bcc75f8dc6964039d139b464c59e2bd0ace6c4dbf000b017d708dd667fcf6cce90c925c7582361f0dd6a9d53f9abc18ed46c8ccae2c1461fcde
6
+ metadata.gz: f8ce675ae0a16274630066192086fb8c46bb0306e9280fd4b8901500af4a7af56844c5d6c40cd0f45a87342c33a4faeb2eee48f0dc0fb05a0a09046a2dea7414
7
+ data.tar.gz: e750e54d72de1c8641a513839c675adeb32fbeaa3435528a8aca755a951a7572d696e9348b7594e104f044978a0e9780f8e080ff1ad5e4ea9b7cc203fac6fee2
data/lib/notices.rb ADDED
@@ -0,0 +1,4 @@
1
+ # This file is for any notices such as deprecation warnings, which should appear
2
+ # in the logs during app boot. Adding such warnings in other places causes
3
+ # lots of noise with duplicated messages, whereas this file is only
4
+ # run once.
data/lib/sequent.rb CHANGED
@@ -3,3 +3,5 @@ require_relative 'sequent/sequent'
3
3
  require_relative 'sequent/core/core'
4
4
  require_relative 'sequent/util/util'
5
5
  require_relative 'sequent/migrations/migrations'
6
+
7
+ require_relative 'notices'
@@ -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.find_by(aggregate_id: event_aggregate_id, sequence_number: event_sequence_number)
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.configuration.event_record_class.column_names.reject { |c| c == 'id' }
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.each &:call
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
- Thread.current[:after_commit_queue] = []
28
+ after_commit_queue.clear
27
29
  end
28
30
  end
29
31
 
@@ -1,4 +1,4 @@
1
- require_relative '../../spec_helper'
1
+ require 'spec_helper'
2
2
  require_relative '../../../app/projectors/post_projector'
3
3
 
4
4
  describe PostProjector do
@@ -1,4 +1,4 @@
1
- require_relative '../../spec_helper'
1
+ require 'spec_helper'
2
2
  require_relative '../../../lib/post'
3
3
 
4
4
  describe PostCommandHandler do
@@ -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.database_config_directory, "#{event_store_schema}.rb")
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)
@@ -92,6 +92,10 @@ module Sequent
92
92
  @event_streams.has_key?(aggregate_id)
93
93
  end
94
94
 
95
+ def events_exists?(aggregate_id)
96
+ @event_streams[aggregate_id].present?
97
+ end
98
+
95
99
  private
96
100
 
97
101
  def to_event_streams(events)
@@ -1,15 +1,29 @@
1
1
  module Sequent
2
2
  module Util
3
- def self.skip_if_already_processing(already_processing_key, &block)
4
- return if Thread.current[already_processing_key]
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[already_processing_key] = true
13
+ Thread.current[processing_key] = true
8
14
 
9
- block.yield
15
+ yield
10
16
  ensure
11
- Thread.current[already_processing_key] = nil
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
@@ -1,3 +1,3 @@
1
1
  module Sequent
2
- VERSION = '3.5.0'
2
+ VERSION = '4.0.0'
3
3
  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: 3.5.0
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: 2020-02-10 00:00:00.000000000 Z
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: '6.0'
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: '6.0'
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: '6.0'
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: '6.0'
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.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.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.17'
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.17'
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.8'
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.8'
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.8'
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.8'
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.12'
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.12'
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.17'
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.17'
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.5'
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.0.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: []