dry-transaction 0.9.0 → 0.10.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 +4 -4
- data/Gemfile.lock +6 -6
- data/README.md +11 -7
- data/lib/dry/transaction.rb +35 -43
- data/lib/dry/transaction/builder.rb +26 -0
- data/lib/dry/transaction/dsl.rb +30 -38
- data/lib/dry/transaction/instance_methods.rb +95 -0
- data/lib/dry/transaction/operation.rb +16 -0
- data/lib/dry/transaction/operation_resolver.rb +19 -0
- data/lib/dry/transaction/result_matcher.rb +2 -2
- data/lib/dry/transaction/step.rb +19 -8
- data/lib/dry/transaction/step_adapters.rb +1 -1
- data/lib/dry/transaction/step_adapters/map.rb +1 -1
- data/lib/dry/transaction/step_adapters/raw.rb +1 -1
- data/lib/dry/transaction/step_adapters/tee.rb +1 -1
- data/lib/dry/transaction/step_adapters/try.rb +1 -1
- data/lib/dry/transaction/step_failure.rb +1 -3
- data/lib/dry/transaction/version.rb +2 -2
- data/spec/examples.txt +60 -75
- data/spec/integration/custom_step_adapters_spec.rb +12 -12
- data/spec/integration/operation_spec.rb +30 -0
- data/spec/integration/passing_step_arguments_spec.rb +14 -13
- data/spec/integration/publishing_step_events_spec.rb +14 -12
- data/spec/integration/transaction_spec.rb +140 -22
- data/spec/spec_helper.rb +6 -2
- data/spec/unit/step_spec.rb +29 -0
- metadata +10 -10
- data/lib/dry/transaction/api.rb +0 -301
- data/lib/dry/transaction/step_definition.rb +0 -23
- data/spec/integration/custom_matcher_spec.rb +0 -59
- data/spec/unit/step_definition_spec.rb +0 -32
- data/spec/unit/transaction_spec.rb +0 -209
data/lib/dry/transaction/step.rb
CHANGED
@@ -3,9 +3,11 @@ require "wisper"
|
|
3
3
|
require "dry/transaction/step_failure"
|
4
4
|
|
5
5
|
module Dry
|
6
|
-
|
6
|
+
module Transaction
|
7
7
|
# @api private
|
8
8
|
class Step
|
9
|
+
UNDEFINED = Object.new.freeze
|
10
|
+
|
9
11
|
include Wisper::Publisher
|
10
12
|
include Dry::Monads::Either::Mixin
|
11
13
|
|
@@ -14,26 +16,35 @@ module Dry
|
|
14
16
|
attr_reader :operation_name
|
15
17
|
attr_reader :operation
|
16
18
|
attr_reader :options
|
17
|
-
attr_reader :block
|
18
19
|
attr_reader :call_args
|
19
20
|
|
20
|
-
def initialize(step_adapter, step_name, operation_name, operation, options, call_args = []
|
21
|
+
def initialize(step_adapter, step_name, operation_name, operation, options, call_args = [])
|
21
22
|
@step_adapter = step_adapter
|
22
23
|
@step_name = step_name
|
23
24
|
@operation_name = operation_name
|
24
25
|
@operation = operation
|
25
26
|
@options = options
|
26
|
-
@block = block
|
27
27
|
@call_args = call_args
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
self
|
30
|
+
def with(operation: UNDEFINED, call_args: UNDEFINED)
|
31
|
+
return self if operation == UNDEFINED && call_args == UNDEFINED
|
32
|
+
new_operation = operation == UNDEFINED ? self.operation : operation
|
33
|
+
new_call_args = call_args == UNDEFINED ? self.call_args : call_args
|
34
|
+
|
35
|
+
self.class.new(
|
36
|
+
step_adapter,
|
37
|
+
step_name,
|
38
|
+
operation_name,
|
39
|
+
new_operation,
|
40
|
+
options,
|
41
|
+
new_call_args,
|
42
|
+
)
|
32
43
|
end
|
33
44
|
|
34
45
|
def call(input)
|
35
|
-
args = [input] + call_args
|
36
|
-
result = step_adapter.call(self, *args
|
46
|
+
args = [input] + Array(call_args)
|
47
|
+
result = step_adapter.call(self, *args)
|
37
48
|
|
38
49
|
result.fmap { |value|
|
39
50
|
broadcast :"#{step_name}_success", value
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module Dry
|
2
|
-
|
2
|
+
module Transaction
|
3
3
|
# A wrapper for storing together the step that failed
|
4
4
|
# and value describing the failure.
|
5
5
|
class StepFailure
|
6
6
|
attr_reader :step
|
7
7
|
attr_reader :value
|
8
8
|
|
9
|
-
# @param step [Step]
|
10
|
-
# @param value [Object]
|
11
9
|
def initialize(step, value)
|
12
10
|
@step = step
|
13
11
|
@value = value
|
data/spec/examples.txt
CHANGED
@@ -1,77 +1,62 @@
|
|
1
1
|
example_id | status | run_time |
|
2
2
|
-------------------------------------------------------- | ------ | --------------- |
|
3
|
-
./spec/integration/
|
4
|
-
./spec/integration/
|
5
|
-
./spec/integration/
|
6
|
-
./spec/integration/passing_step_arguments_spec.rb[1:
|
7
|
-
./spec/integration/passing_step_arguments_spec.rb[1:
|
8
|
-
./spec/integration/
|
9
|
-
./spec/integration/publishing_step_events_spec.rb[1:1:
|
10
|
-
./spec/integration/publishing_step_events_spec.rb[1:2
|
11
|
-
./spec/integration/publishing_step_events_spec.rb[1:2:
|
12
|
-
./spec/integration/
|
13
|
-
./spec/integration/transaction_spec.rb[1:1:
|
14
|
-
./spec/integration/transaction_spec.rb[1:1:
|
15
|
-
./spec/integration/transaction_spec.rb[1:1:
|
16
|
-
./spec/integration/transaction_spec.rb[1:1:
|
17
|
-
./spec/integration/transaction_spec.rb[1:
|
18
|
-
./spec/integration/transaction_spec.rb[1:2:
|
19
|
-
./spec/integration/transaction_spec.rb[1:
|
20
|
-
./spec/integration/transaction_spec.rb[1:
|
21
|
-
./spec/integration/transaction_spec.rb[1:
|
22
|
-
./spec/integration/transaction_spec.rb[1:
|
23
|
-
./spec/integration/transaction_spec.rb[1:
|
24
|
-
./spec/integration/transaction_spec.rb[1:
|
25
|
-
./spec/integration/transaction_spec.rb[1:
|
26
|
-
./spec/integration/transaction_spec.rb[1:
|
27
|
-
./spec/integration/transaction_spec.rb[1:
|
28
|
-
./spec/integration/transaction_spec.rb[1:
|
29
|
-
./spec/
|
30
|
-
./spec/
|
31
|
-
./spec/
|
32
|
-
./spec/
|
33
|
-
./spec/
|
34
|
-
./spec/
|
35
|
-
./spec/unit/step_adapters/
|
36
|
-
./spec/unit/step_adapters/
|
37
|
-
./spec/unit/step_adapters/
|
38
|
-
./spec/unit/step_adapters/
|
39
|
-
./spec/unit/step_adapters/
|
40
|
-
./spec/unit/step_adapters/
|
41
|
-
./spec/unit/step_adapters/
|
42
|
-
./spec/unit/step_adapters/
|
43
|
-
./spec/unit/step_adapters/
|
44
|
-
./spec/unit/step_adapters/try_spec.rb[1:1:
|
45
|
-
./spec/unit/step_adapters/try_spec.rb[1:1:2:
|
46
|
-
./spec/unit/step_adapters/try_spec.rb[1:1:2:
|
47
|
-
./spec/unit/
|
48
|
-
./spec/unit/
|
49
|
-
./spec/unit/
|
50
|
-
./spec/unit/
|
51
|
-
./spec/unit/
|
52
|
-
./spec/unit/
|
53
|
-
./spec/unit/step_spec.rb[1:1:
|
54
|
-
./spec/unit/step_spec.rb[1:1:
|
55
|
-
./spec/unit/step_spec.rb[1:1:2:
|
56
|
-
./spec/unit/step_spec.rb[1:2:
|
57
|
-
./spec/unit/step_spec.rb[1:
|
58
|
-
./spec/unit/
|
59
|
-
./spec/unit/
|
60
|
-
./spec/unit/
|
61
|
-
./spec/unit/
|
62
|
-
./spec/unit/
|
63
|
-
./spec/unit/transaction_spec.rb[1:2:2] | passed | 0.00018 seconds |
|
64
|
-
./spec/unit/transaction_spec.rb[1:2:3] | passed | 0.00015 seconds |
|
65
|
-
./spec/unit/transaction_spec.rb[1:2:4] | passed | 0.00016 seconds |
|
66
|
-
./spec/unit/transaction_spec.rb[1:3:1] | passed | 0.00015 seconds |
|
67
|
-
./spec/unit/transaction_spec.rb[1:3:2] | passed | 0.0002 seconds |
|
68
|
-
./spec/unit/transaction_spec.rb[1:4:1] | passed | 0.00028 seconds |
|
69
|
-
./spec/unit/transaction_spec.rb[1:4:2] | passed | 0.00019 seconds |
|
70
|
-
./spec/unit/transaction_spec.rb[1:4:3] | passed | 0.00013 seconds |
|
71
|
-
./spec/unit/transaction_spec.rb[1:4:4] | passed | 0.00014 seconds |
|
72
|
-
./spec/unit/transaction_spec.rb[1:4:5:1] | passed | 0.00023 seconds |
|
73
|
-
./spec/unit/transaction_spec.rb[1:4:5:2] | passed | 0.00018 seconds |
|
74
|
-
./spec/unit/transaction_spec.rb[1:4:6:1] | passed | 0.0002 seconds |
|
75
|
-
./spec/unit/transaction_spec.rb[1:4:6:2] | passed | 0.00022 seconds |
|
76
|
-
./spec/unit/transaction_spec.rb[1:4:7:1] | passed | 0.00019 seconds |
|
77
|
-
./spec/unit/transaction_spec.rb[1:4:7:2] | passed | 0.0002 seconds |
|
3
|
+
./spec/integration/custom_step_adapters_spec.rb[1:1] | passed | 0.00312 seconds |
|
4
|
+
./spec/integration/operation_spec.rb[1:1] | passed | 0.00014 seconds |
|
5
|
+
./spec/integration/operation_spec.rb[1:2] | passed | 0.00016 seconds |
|
6
|
+
./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00048 seconds |
|
7
|
+
./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00038 seconds |
|
8
|
+
./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00067 seconds |
|
9
|
+
./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00057 seconds |
|
10
|
+
./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00054 seconds |
|
11
|
+
./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.00225 seconds |
|
12
|
+
./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00048 seconds |
|
13
|
+
./spec/integration/transaction_spec.rb[1:1:1] | passed | 0.00102 seconds |
|
14
|
+
./spec/integration/transaction_spec.rb[1:1:2] | passed | 0.00083 seconds |
|
15
|
+
./spec/integration/transaction_spec.rb[1:1:3] | passed | 0.00054 seconds |
|
16
|
+
./spec/integration/transaction_spec.rb[1:1:4] | passed | 0.00207 seconds |
|
17
|
+
./spec/integration/transaction_spec.rb[1:1:5] | passed | 0.00081 seconds |
|
18
|
+
./spec/integration/transaction_spec.rb[1:2:1] | passed | 0.00032 seconds |
|
19
|
+
./spec/integration/transaction_spec.rb[1:3:1] | passed | 0.00041 seconds |
|
20
|
+
./spec/integration/transaction_spec.rb[1:4:1] | passed | 0.00032 seconds |
|
21
|
+
./spec/integration/transaction_spec.rb[1:5:1] | passed | 0.00032 seconds |
|
22
|
+
./spec/integration/transaction_spec.rb[1:6:1] | passed | 0.00098 seconds |
|
23
|
+
./spec/integration/transaction_spec.rb[1:7:1] | passed | 0.00034 seconds |
|
24
|
+
./spec/integration/transaction_spec.rb[1:7:2] | passed | 0.00035 seconds |
|
25
|
+
./spec/integration/transaction_spec.rb[1:7:3] | passed | 0.00231 seconds |
|
26
|
+
./spec/integration/transaction_spec.rb[1:7:4] | passed | 0.00035 seconds |
|
27
|
+
./spec/integration/transaction_spec.rb[1:7:5] | passed | 0.00037 seconds |
|
28
|
+
./spec/integration/transaction_spec.rb[1:7:6] | passed | 0.00038 seconds |
|
29
|
+
./spec/integration/transaction_spec.rb[1:8:1] | passed | 0.00032 seconds |
|
30
|
+
./spec/integration/transaction_spec.rb[1:8:2] | passed | 0.0003 seconds |
|
31
|
+
./spec/integration/transaction_spec.rb[1:8:3] | passed | 0.00032 seconds |
|
32
|
+
./spec/integration/transaction_spec.rb[1:8:4] | passed | 0.00033 seconds |
|
33
|
+
./spec/integration/transaction_spec.rb[1:8:5] | passed | 0.00038 seconds |
|
34
|
+
./spec/integration/transaction_spec.rb[1:9:1] | passed | 0.00031 seconds |
|
35
|
+
./spec/unit/step_adapters/map_spec.rb[1:1:1] | passed | 0.00137 seconds |
|
36
|
+
./spec/unit/step_adapters/map_spec.rb[1:1:2] | passed | 0.00124 seconds |
|
37
|
+
./spec/unit/step_adapters/raw_spec.rb[1:1:1:1] | passed | 0.00217 seconds |
|
38
|
+
./spec/unit/step_adapters/raw_spec.rb[1:1:2:1] | passed | 0.00011 seconds |
|
39
|
+
./spec/unit/step_adapters/raw_spec.rb[1:1:2:2] | passed | 0.00011 seconds |
|
40
|
+
./spec/unit/step_adapters/raw_spec.rb[1:1:3:1] | passed | 0.00013 seconds |
|
41
|
+
./spec/unit/step_adapters/raw_spec.rb[1:1:3:2] | passed | 0.00011 seconds |
|
42
|
+
./spec/unit/step_adapters/tee_spec.rb[1:1:1] | passed | 0.0001 seconds |
|
43
|
+
./spec/unit/step_adapters/tee_spec.rb[1:1:2] | passed | 0.00015 seconds |
|
44
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:1:1] | passed | 0.00015 seconds |
|
45
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:1:1] | passed | 0.00013 seconds |
|
46
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:1:2] | passed | 0.00019 seconds |
|
47
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:1] | passed | 0.00012 seconds |
|
48
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:2] | passed | 0.00015 seconds |
|
49
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:2:1] | passed | 0.00047 seconds |
|
50
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:2:2] | passed | 0.00011 seconds |
|
51
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:1] | passed | 0.00012 seconds |
|
52
|
+
./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:2] | passed | 0.00051 seconds |
|
53
|
+
./spec/unit/step_spec.rb[1:1:1:1] | passed | 0.00057 seconds |
|
54
|
+
./spec/unit/step_spec.rb[1:1:1:2] | passed | 0.00086 seconds |
|
55
|
+
./spec/unit/step_spec.rb[1:1:2:1] | passed | 0.00305 seconds |
|
56
|
+
./spec/unit/step_spec.rb[1:1:2:2] | passed | 0.00432 seconds |
|
57
|
+
./spec/unit/step_spec.rb[1:1:2:3] | passed | 0.01511 seconds |
|
58
|
+
./spec/unit/step_spec.rb[1:2:1:1] | passed | 0.00011 seconds |
|
59
|
+
./spec/unit/step_spec.rb[1:2:2:1] | passed | 0.00012 seconds |
|
60
|
+
./spec/unit/step_spec.rb[1:2:3:1] | passed | 0.00013 seconds |
|
61
|
+
./spec/unit/step_spec.rb[1:3:1:1] | passed | 0.00014 seconds |
|
62
|
+
./spec/unit/step_spec.rb[1:3:2:1] | passed | 0.00013 seconds |
|
@@ -1,18 +1,12 @@
|
|
1
1
|
RSpec.describe "Custom step adapters" do
|
2
2
|
let(:transaction) {
|
3
|
-
|
4
|
-
|
5
|
-
tee :persist
|
6
|
-
enqueue :deliver
|
7
|
-
end
|
8
|
-
}
|
3
|
+
Class.new do
|
4
|
+
include Dry::Transaction(container: Test::Container, step_adapters: Test::CustomStepAdapters)
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
deliver: -> input { "Delivered email to #{input[:email]}" },
|
15
|
-
}
|
6
|
+
map :process, with: :process
|
7
|
+
tee :persist, with: :persist
|
8
|
+
enqueue :deliver, with: :deliver
|
9
|
+
end.new
|
16
10
|
}
|
17
11
|
|
18
12
|
before do
|
@@ -20,6 +14,12 @@ RSpec.describe "Custom step adapters" do
|
|
20
14
|
Test::QUEUE = []
|
21
15
|
|
22
16
|
module Test
|
17
|
+
Container = {
|
18
|
+
process: -> input { {name: input["name"], email: input["email"]} },
|
19
|
+
persist: -> input { Test::DB << input and true },
|
20
|
+
deliver: -> input { "Delivered email to #{input[:email]}" },
|
21
|
+
}
|
22
|
+
|
23
23
|
class CustomStepAdapters < Dry::Transaction::StepAdapters
|
24
24
|
extend Dry::Monads::Either::Mixin
|
25
25
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "dry/transaction/operation"
|
2
|
+
|
3
|
+
RSpec.describe Dry::Transaction::Operation do
|
4
|
+
subject(:operation) {
|
5
|
+
Class.new do
|
6
|
+
include Dry::Transaction::Operation
|
7
|
+
|
8
|
+
def call(input)
|
9
|
+
Right(input)
|
10
|
+
end
|
11
|
+
end.new
|
12
|
+
}
|
13
|
+
|
14
|
+
it "mixes in the Either monad constructors" do
|
15
|
+
expect(operation.("hello")).to be_right
|
16
|
+
end
|
17
|
+
|
18
|
+
it "supports pattern matching when called with a block" do
|
19
|
+
result = operation.("hello") do |m|
|
20
|
+
m.success do |v|
|
21
|
+
"Success: #{v}"
|
22
|
+
end
|
23
|
+
m.failure do |v|
|
24
|
+
"Failure: #{v}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
expect(result).to eq "Success: hello"
|
29
|
+
end
|
30
|
+
end
|
@@ -1,20 +1,14 @@
|
|
1
1
|
RSpec.describe "Passing additional arguments to step operations" do
|
2
|
-
let(:call_transaction) { transaction.call(input
|
2
|
+
let(:call_transaction) { transaction.with_step_args(step_options).call(input) }
|
3
3
|
|
4
4
|
let(:transaction) {
|
5
|
-
|
6
|
-
|
7
|
-
try :validate, catch: Test::NotValidError
|
8
|
-
tee :persist
|
9
|
-
end
|
10
|
-
}
|
5
|
+
Class.new do
|
6
|
+
include Dry::Transaction(container: Test::Container)
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
persist: -> input { Test::DB << input and true }
|
17
|
-
}
|
8
|
+
map :process, with: :process
|
9
|
+
try :validate, with: :validate, catch: Test::NotValidError
|
10
|
+
tee :persist, with: :persist
|
11
|
+
end.new
|
18
12
|
}
|
19
13
|
|
20
14
|
let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
|
@@ -22,6 +16,13 @@ RSpec.describe "Passing additional arguments to step operations" do
|
|
22
16
|
before do
|
23
17
|
Test::NotValidError = Class.new(StandardError)
|
24
18
|
Test::DB = []
|
19
|
+
module Test
|
20
|
+
Container = {
|
21
|
+
process: -> input { {name: input["name"], email: input["email"]} },
|
22
|
+
validate: -> input, allowed { !input[:email].include?(allowed) ? raise(Test::NotValidError, "email not allowed") : input },
|
23
|
+
persist: -> input { Test::DB << input and true }
|
24
|
+
}
|
25
|
+
end
|
25
26
|
end
|
26
27
|
|
27
28
|
context "required arguments provided" do
|
@@ -1,24 +1,26 @@
|
|
1
1
|
RSpec.describe "publishing step events" do
|
2
2
|
let(:transaction) {
|
3
|
-
|
4
|
-
|
5
|
-
step :verify
|
6
|
-
tee :persist
|
7
|
-
end
|
8
|
-
}
|
3
|
+
Class.new do
|
4
|
+
include Dry::Transaction(container: Test::Container)
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
persist: -> input { Test::DB << input and true }
|
15
|
-
}
|
6
|
+
map :process, with: :process
|
7
|
+
step :verify, with: :verify
|
8
|
+
tee :persist, with: :persist
|
9
|
+
end.new
|
16
10
|
}
|
17
11
|
|
18
12
|
let(:subscriber) { spy(:subscriber) }
|
19
13
|
|
20
14
|
before do
|
21
15
|
Test::DB = []
|
16
|
+
|
17
|
+
module Test
|
18
|
+
Container = {
|
19
|
+
process: -> input { {name: input["name"]} },
|
20
|
+
verify: -> input { input[:name].to_s != "" ? Dry::Monads.Right(input) : Dry::Monads.Left("no name") },
|
21
|
+
persist: -> input { Test::DB << input and true }
|
22
|
+
}
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
26
|
context "subscribing to all step events" do
|
@@ -1,31 +1,25 @@
|
|
1
1
|
RSpec.describe "Transactions" do
|
2
2
|
let(:transaction) {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
input
|
11
|
-
end
|
12
|
-
}, catch: Test::NotValidError
|
13
|
-
tee :persist
|
14
|
-
end
|
3
|
+
Class.new do
|
4
|
+
include Dry::Transaction(container: Test::Container)
|
5
|
+
map :process
|
6
|
+
step :verify
|
7
|
+
try :validate, catch: Test::NotValidError
|
8
|
+
tee :persist
|
9
|
+
end.new(**dependencies)
|
15
10
|
}
|
16
11
|
|
17
|
-
let(:
|
18
|
-
{
|
19
|
-
process: -> input { {name: input["name"], email: input["email"]} },
|
20
|
-
verify: -> input { Right(input) },
|
21
|
-
persist: -> input { Test::DB << input and true },
|
22
|
-
invalid_error: Test::NotValidError
|
23
|
-
}
|
24
|
-
}
|
12
|
+
let(:dependencies) { {} }
|
25
13
|
|
26
14
|
before do
|
27
15
|
Test::NotValidError = Class.new(StandardError)
|
28
16
|
Test::DB = []
|
17
|
+
Test::Container = {
|
18
|
+
process: -> input { {name: input["name"], email: input["email"]} },
|
19
|
+
verify: -> input { Right(input) },
|
20
|
+
validate: -> input { input[:email].nil? ? raise(Test::NotValidError, "email required") : input },
|
21
|
+
persist: -> input { Test::DB << input and true },
|
22
|
+
}
|
29
23
|
end
|
30
24
|
|
31
25
|
context "successful" do
|
@@ -67,6 +61,130 @@ RSpec.describe "Transactions" do
|
|
67
61
|
end
|
68
62
|
end
|
69
63
|
|
64
|
+
context "different step names" do
|
65
|
+
before do
|
66
|
+
module Test
|
67
|
+
ContainerNames = {
|
68
|
+
process_step: -> input { {name: input["name"], email: input["email"]} },
|
69
|
+
verify_step: -> input { Dry::Monads.Right(input) },
|
70
|
+
persist_step: -> input { Test::DB << input and true },
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
let(:transaction) {
|
76
|
+
Class.new do
|
77
|
+
include Dry::Transaction(container: Test::ContainerNames)
|
78
|
+
|
79
|
+
map :process, with: :process_step
|
80
|
+
step :verify, with: :verify_step
|
81
|
+
tee :persist, with: :persist_step
|
82
|
+
end.new(**dependencies)
|
83
|
+
}
|
84
|
+
|
85
|
+
it "supports steps using differently named container operations" do
|
86
|
+
transaction.call("name" => "Jane", "email" => "jane@doe.com")
|
87
|
+
expect(Test::DB).to include(name: "Jane", email: "jane@doe.com")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "operation injection" do
|
92
|
+
let(:transaction) {
|
93
|
+
Class.new do
|
94
|
+
include Dry::Transaction(container: Test::Container)
|
95
|
+
map :process
|
96
|
+
step :verify_step, with: :verify
|
97
|
+
tee :persist
|
98
|
+
end.new(**dependencies)
|
99
|
+
}
|
100
|
+
|
101
|
+
let(:dependencies) {
|
102
|
+
{verify_step: -> input { Dry::Monads.Right(input.merge(foo: :bar)) }}
|
103
|
+
}
|
104
|
+
|
105
|
+
it "calls injected operations" do
|
106
|
+
transaction.call("name" => "Jane", "email" => "jane@doe.com")
|
107
|
+
|
108
|
+
expect(Test::DB).to include(name: "Jane", email: "jane@doe.com", foo: :bar)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "wrapping operations with local methods" do
|
113
|
+
let(:transaction) do
|
114
|
+
Class.new do
|
115
|
+
include Dry::Transaction(container: Test::Container)
|
116
|
+
|
117
|
+
map :process, with: :process
|
118
|
+
step :verify, with: :verify
|
119
|
+
tee :persist, with: :persist
|
120
|
+
|
121
|
+
def verify(input)
|
122
|
+
new_input = input.merge(greeting: "hello!")
|
123
|
+
super(new_input)
|
124
|
+
end
|
125
|
+
end.new(**dependencies)
|
126
|
+
end
|
127
|
+
|
128
|
+
let(:dependencies) { {} }
|
129
|
+
|
130
|
+
it "allows local methods to run operations via super" do
|
131
|
+
transaction.call("name" => "Jane", "email" => "jane@doe.com")
|
132
|
+
|
133
|
+
expect(Test::DB).to include(name: "Jane", email: "jane@doe.com", greeting: "hello!")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "local step definition" do
|
138
|
+
let(:transaction) do
|
139
|
+
Class.new do
|
140
|
+
include Dry::Transaction(container: Test::Container)
|
141
|
+
|
142
|
+
map :process, with: :process
|
143
|
+
step :verify
|
144
|
+
tee :persist, with: :persist
|
145
|
+
|
146
|
+
def verify(input)
|
147
|
+
Right(input.keys)
|
148
|
+
end
|
149
|
+
end.new
|
150
|
+
end
|
151
|
+
|
152
|
+
it "execute step only defined as local method" do
|
153
|
+
transaction.call("name" => "Jane", "email" => "jane@doe.com")
|
154
|
+
|
155
|
+
expect(Test::DB).to include([:name, :email])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "all steps are local methods" do
|
160
|
+
let(:transaction) do
|
161
|
+
Class.new do
|
162
|
+
include Dry::Transaction
|
163
|
+
|
164
|
+
map :process
|
165
|
+
step :verify
|
166
|
+
tee :persist
|
167
|
+
|
168
|
+
def process(input)
|
169
|
+
input.to_a
|
170
|
+
end
|
171
|
+
|
172
|
+
def verify(input)
|
173
|
+
Dry::Monads.Right(input)
|
174
|
+
end
|
175
|
+
|
176
|
+
def persist(input)
|
177
|
+
Test::DB << input and true
|
178
|
+
end
|
179
|
+
end.new
|
180
|
+
end
|
181
|
+
|
182
|
+
it "executes succesfully" do
|
183
|
+
transaction.call("name" => "Jane", "email" => "jane@doe.com")
|
184
|
+
expect(Test::DB).to include([["name", "Jane"], ["email", "jane@doe.com"]])
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
70
188
|
context "failed in a try step" do
|
71
189
|
let(:input) { {"name" => "Jane"} }
|
72
190
|
|
@@ -134,7 +252,7 @@ RSpec.describe "Transactions" do
|
|
134
252
|
let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
|
135
253
|
|
136
254
|
before do
|
137
|
-
|
255
|
+
Test::Container[:verify] = -> input { Left("raw failure") }
|
138
256
|
end
|
139
257
|
|
140
258
|
it "does not run subsequent operations" do
|
@@ -167,7 +285,7 @@ RSpec.describe "Transactions" do
|
|
167
285
|
let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
|
168
286
|
|
169
287
|
before do
|
170
|
-
|
288
|
+
Test::Container[:verify] = -> input { "failure" }
|
171
289
|
end
|
172
290
|
|
173
291
|
it "raises an exception" do
|