sequent 4.1.0 → 4.2.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: 5e0c606e57bb36fdcaeeb102904dd450a0ff9fc2a84fdd5aff7f365a914c45d3
4
- data.tar.gz: ea03e8a0c7ab524ff8c73fded97a726edf3dff240b95db62496496d5a6a6d580
3
+ metadata.gz: b7e291ad7f19e869e7606e8dc49282a545db07d4a656f5ee44d71ed5c2e33170
4
+ data.tar.gz: fb73e4b00b0f0e9ef94cab2152922c280b51d3568f5f9ecb7a9cdaa00afed97e
5
5
  SHA512:
6
- metadata.gz: 10f78e12826549dcd0ea3677940b5b2cdbde26fb9ecdf2f5a1bca67d5dd8405447409417b6cd277bd554c3590a2a7a3814a0918ae79ceec2b6da9510d8d1fa3f
7
- data.tar.gz: abde6abb5638e8ad3f4f2081eb1e9eada6588d4d74994a5a62a4ef761b9737277981a5c270e75297a5e508cc611031a2e779df43b3a70b3d5a9bb0b77c81ec34
6
+ metadata.gz: df076f1efbe41c17c75c99c5331d7f1e23ff8c52607c9a0e709a9dd46504a2b6e78d471ed247dff4e5913809de28bc328a820ce00779d0a97fb64f669a10670e
7
+ data.tar.gz: 552dca913ac052facd09d2602c08a38fa33c66e3d4c092d38a6fcd018dabca2683ef93d5f3ddef8b105fa043c6d99bf765be38ad2f69171a08e5af63df3783ad
data/bin/sequent CHANGED
@@ -20,10 +20,11 @@ def new_project(args)
20
20
  Success!
21
21
 
22
22
  Your brand spanking new sequent app is waiting for you in:
23
- #{File.expand_path(name, __dir__)}
23
+ #{File.expand_path(name, Dir.pwd)}
24
24
 
25
25
  To finish setting up your app:
26
26
  cd #{name}
27
+ bundle install
27
28
  bundle exec rake sequent:db:create
28
29
  bundle exec rake sequent:db:create_view_schema
29
30
  bundle exec rake sequent:migrate:online
@@ -92,6 +92,11 @@ module Sequent
92
92
  @persistor = persistor
93
93
  end
94
94
 
95
+ def self.inherited(subclass)
96
+ super
97
+ Projectors << subclass
98
+ end
99
+
95
100
  def self.replay_persistor
96
101
  nil
97
102
  end
@@ -125,5 +130,28 @@ module Sequent
125
130
  end
126
131
  end
127
132
  end
133
+
134
+ #
135
+ # Utility class containing all subclasses of Projector
136
+ #
137
+ class Projectors
138
+ class << self
139
+ def projectors
140
+ @projectors ||= []
141
+ end
142
+
143
+ def all
144
+ projectors
145
+ end
146
+
147
+ def <<(projector)
148
+ projectors << projector
149
+ end
150
+
151
+ def find(projector_name)
152
+ projectors.find { |c| c.name == projector_name }
153
+ end
154
+ end
155
+ end
128
156
  end
129
157
  end
@@ -3,6 +3,31 @@
3
3
  module Sequent
4
4
  module Core
5
5
  module Transactions
6
+ ##
7
+ # Always require a new transaction.
8
+ #
9
+ # Read:
10
+ # http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
11
+ #
12
+ # Without this change, there is a potential bug:
13
+ #
14
+ # ```ruby
15
+ # ActiveRecord::Base.transaction do
16
+ # Sequent.configuration.command_service.execute_commands command
17
+ # end
18
+ #
19
+ # on Command do
20
+ # do.some.things
21
+ # fail ActiveRecord::Rollback
22
+ # end
23
+ # ```
24
+ #
25
+ # In this example, you might be surprised to find that `do.some.things`
26
+ # does not get rolled back! This is because AR doesn't automatically make
27
+ # a "savepoint" for us when we call `.transaction` in a nested manner. In
28
+ # order to enable this behaviour, we have to call `.transaction` like
29
+ # this: `.transaction(requires_new: true)`.
30
+ #
6
31
  class ActiveRecordTransactionProvider
7
32
  def transactional(&block)
8
33
  Sequent::ApplicationRecord.transaction(requires_new: true, &block)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequent
4
+ module Core
5
+ module Transactions
6
+ class ReadOnlyActiveRecordTransactionProvider
7
+ def initialize(transaction_provider)
8
+ @transaction_provider = transaction_provider
9
+ end
10
+
11
+ def transactional(&block)
12
+ register_call
13
+ @transaction_provider.transactional do
14
+ Sequent::ApplicationRecord.connection.execute('SET TRANSACTION READ ONLY')
15
+ block.call
16
+ rescue ActiveRecord::StatementInvalid
17
+ @skip_set_transaction = true
18
+ raise
19
+ ensure
20
+ deregister_call
21
+ reset_stack_size if stack_size == 0
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def stack_size
28
+ Thread.current[:read_only_active_record_transaction_provider_calls]
29
+ end
30
+
31
+ def register_call
32
+ Thread.current[:read_only_active_record_transaction_provider_calls] ||= 0
33
+ Thread.current[:read_only_active_record_transaction_provider_calls] += 1
34
+ end
35
+
36
+ def deregister_call
37
+ Thread.current[:read_only_active_record_transaction_provider_calls] -= 1
38
+ end
39
+
40
+ def reset_stack_size
41
+ Thread.current[:read_only_active_record_transaction_provider_calls] = nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,3 +2,4 @@
2
2
 
3
3
  require_relative 'active_record_transaction_provider'
4
4
  require_relative 'no_transactions'
5
+ require_relative 'read_only_active_record_transaction_provider'
@@ -8,6 +8,11 @@ module Sequent
8
8
  class Workflow
9
9
  include Helpers::MessageHandler
10
10
 
11
+ def self.inherited(subclass)
12
+ super
13
+ Workflows << subclass
14
+ end
15
+
11
16
  def self.on(*message_classes, &block)
12
17
  decorated_block = ->(event) do
13
18
  begin
@@ -42,5 +47,28 @@ module Sequent
42
47
  end
43
48
  end
44
49
  end
50
+
51
+ #
52
+ # Utility class containing all subclasses of Workflow
53
+ #
54
+ class Workflows
55
+ class << self
56
+ def workflows
57
+ @workflows ||= []
58
+ end
59
+
60
+ def all
61
+ workflows
62
+ end
63
+
64
+ def <<(workflow)
65
+ workflows << workflow
66
+ end
67
+
68
+ def find(workflow_name)
69
+ workflows.find { |c| c.name == workflow_name }
70
+ end
71
+ end
72
+ end
45
73
  end
46
74
  end
@@ -14,6 +14,7 @@ module Sequent
14
14
  def execute
15
15
  make_directory
16
16
  copy_files
17
+ rename_ruby_version
17
18
  rename_app_file
18
19
  replace_app_name
19
20
  end
@@ -28,6 +29,12 @@ module Sequent
28
29
  FileUtils.copy_entry(File.expand_path('template_project', __dir__), path)
29
30
  end
30
31
 
32
+ # Hidden files are by default excluded from gem build.
33
+ # Therefor we need to rename the ruby-version to .ruby-version.
34
+ def rename_ruby_version
35
+ FileUtils.mv("#{path}/ruby-version", "#{path}/.ruby-version")
36
+ end
37
+
31
38
  def rename_app_file
32
39
  FileUtils.mv("#{path}/my_app.rb", "#{path}/#{name_underscored}.rb")
33
40
  end
@@ -36,18 +36,18 @@ module Sequent
36
36
 
37
37
  delegate :load_events_for_aggregates,
38
38
  :load_events,
39
- :publish_events,
40
39
  :stream_exists?,
40
+ :events_exists?,
41
41
  to: :event_store
42
42
 
43
- def initialize(result)
44
- @event_store = Sequent::Test::CommandHandlerHelpers::FakeEventStore.new
43
+ def initialize(result, event_store)
44
+ @event_store = event_store
45
45
  @command_with_events = {}
46
46
  @result = result
47
47
  end
48
48
 
49
49
  def commit_events(command, streams_with_events)
50
- event_store.commit_events(command, streams_with_events)
50
+ Sequent.configuration.event_publisher.publish_events(streams_with_events.flat_map { |_, events| events })
51
51
 
52
52
  new_events = streams_with_events.flat_map { |_, events| events }
53
53
  @result.published_command_with_events(command, new_events)
@@ -66,18 +66,18 @@ module Sequent
66
66
  end
67
67
 
68
68
  def process_event(event)
69
- Sequent.configuration.event_handlers.each do |handler|
70
- next unless handler.class.handles_message?(event)
69
+ [*Sequent::Core::Workflows.all, *Sequent::Core::Projectors.all].each do |handler_class|
70
+ next unless handler_class.handles_message?(event)
71
71
 
72
- if handler.is_a?(Sequent::Workflow)
73
- @result.invoked_workflow(EventInvokedHandler.new(event, handler.class))
74
- elsif handler.is_a?(Sequent::Projector)
75
- @result.invoked_projector(EventInvokedHandler.new(event, handler.class))
72
+ if handler_class < Sequent::Workflow
73
+ @result.invoked_workflow(EventInvokedHandler.new(event, handler_class))
74
+ elsif handler_class < Sequent::Projector
75
+ @result.invoked_projector(EventInvokedHandler.new(event, handler_class))
76
76
  else
77
- fail "Unrecognized event_handler #{handler.class} called for event #{event.class}"
77
+ fail "Unrecognized event_handler #{handler_class} called for event #{event.class}"
78
78
  end
79
79
  rescue StandardError
80
- raise PublishEventError.new(handler.class, event)
80
+ raise PublishEventError.new(handler_class, event)
81
81
  end
82
82
  end
83
83
  end
@@ -177,10 +177,14 @@ module Sequent
177
177
  def self.these_commands(commands)
178
178
  current_event_store = Sequent.configuration.event_store
179
179
  current_event_publisher = Sequent.configuration.event_publisher
180
+ current_transaction_provider = Sequent.configuration.transaction_provider
181
+
180
182
  result = Result.new
181
183
 
182
- Sequent.configuration.event_store = EventStoreProxy.new(result)
184
+ Sequent.configuration.event_store = EventStoreProxy.new(result, current_event_store)
183
185
  Sequent.configuration.event_publisher = RecordingEventPublisher.new(result)
186
+ Sequent.configuration.transaction_provider =
187
+ Sequent::Core::Transactions::ReadOnlyActiveRecordTransactionProvider.new(current_transaction_provider)
184
188
 
185
189
  Sequent.command_service.execute_commands(*commands)
186
190
 
@@ -188,6 +192,7 @@ module Sequent
188
192
  ensure
189
193
  Sequent.configuration.event_store = current_event_store
190
194
  Sequent.configuration.event_publisher = current_event_publisher
195
+ Sequent.configuration.transaction_provider = current_transaction_provider
191
196
  end
192
197
  end
193
198
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sequent
4
- VERSION = '4.1.0'
4
+ VERSION = '4.2.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: 4.1.0
4
+ version: 4.2.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: 2021-12-21 00:00:00.000000000 Z
15
+ date: 2022-01-30 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: 6.1.4
26
+ version: 6.1.4.4
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: 6.1.4
36
+ version: 6.1.4.4
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: 6.1.4
46
+ version: 6.1.4.4
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: 6.1.4
56
+ version: 6.1.4.4
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: bcrypt
59
59
  requirement: !ruby/object:Gem::Requirement
@@ -362,6 +362,7 @@ files:
362
362
  - lib/sequent/core/stream_record.rb
363
363
  - lib/sequent/core/transactions/active_record_transaction_provider.rb
364
364
  - lib/sequent/core/transactions/no_transactions.rb
365
+ - lib/sequent/core/transactions/read_only_active_record_transaction_provider.rb
365
366
  - lib/sequent/core/transactions/transactions.rb
366
367
  - lib/sequent/core/value_object.rb
367
368
  - lib/sequent/core/workflow.rb
@@ -393,6 +394,7 @@ files:
393
394
  - lib/sequent/generator/template_project/lib/post/post.rb
394
395
  - lib/sequent/generator/template_project/lib/post/post_command_handler.rb
395
396
  - lib/sequent/generator/template_project/my_app.rb
397
+ - lib/sequent/generator/template_project/ruby-version
396
398
  - lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb
397
399
  - lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb
398
400
  - lib/sequent/generator/template_project/spec/spec_helper.rb