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 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: []