opera 0.2.7 → 0.2.10

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: b5bbb67e42e162ac6cbea3ac242a707d270110035cf618f84ea8cc5e33a60de8
4
- data.tar.gz: 512a3bf21c0a6e686e41e9eb25ed21634612f4e004bd7ece8c3e3177664bcbcd
3
+ metadata.gz: 84e206c0f8da7dd69e6a4132a7228b87cbe3b79e7eeb3e936659554d7ac8a69a
4
+ data.tar.gz: b962b7656ff7ddcfd0d964bd622027f4b431b2ddf9cb0d8ad59ec97a045eb6bc
5
5
  SHA512:
6
- metadata.gz: 8d55665d552e5be5d23f150d17f121700b958fc8dfdd92ef1c4cc82d9d4329b03e8a4c08c8204bff87897e65d0c2858c06df8677748b9a437795476e47b6dd62
7
- data.tar.gz: 939e7abdc56c89ff03131ff98d9721dde54224891711923073bc5377a7389f46c660b7a8f909e13204ec74f565be6217a21c12e00e522dc18ecf1cbff42a6dc6
6
+ metadata.gz: 1159a0ffc970a9365ca78fde1589f49eb34ee73ebbcbc5bde0b895ce13cbd48c6ea361d4468002d39a9d00b6ffad377bf0ccbe3f4340be19882d07e780772a2d
7
+ data.tar.gz: 85136103bf11201f4f0f877ef556c913b0d7031fc8e4ef10d42bcdcf30f3e0a7504eeea285b047397006a0ec54e8a383c80b7d51bc0c667a3348c42b48ef7876
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Opera Changelog
2
2
 
3
+ ### 0.2.10 - June 1, 2022
4
+
5
+ - `finish!` does not break transaction
6
+
7
+ ### 0.2.9 - May 16, 2022
8
+
9
+ - Improve executions for failing operations
10
+
11
+ ### 0.2.8 - December 7, 2021
12
+
13
+ - Fix issue with default value
14
+ - Update Readme
15
+
3
16
  ### 0.2.7 - October 29, 2021
4
17
 
5
18
  - Adds `finish_if` step to DSL
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- opera (0.2.7)
4
+ opera (0.2.10)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -81,4 +81,4 @@ DEPENDENCIES
81
81
  rspec (~> 3.0)
82
82
 
83
83
  BUNDLED WITH
84
- 2.2.15
84
+ 2.2.32
data/README.md CHANGED
@@ -702,7 +702,7 @@ class Profile::Create < Opera::Operation::Base
702
702
  end
703
703
  ```
704
704
 
705
- #### Example with information (real and total) from benchmark
705
+ #### Example output for success block
706
706
 
707
707
  ```ruby
708
708
  Profile::Create.call(params: {
@@ -60,7 +60,11 @@ module Opera
60
60
  check_method_availability!(attribute)
61
61
 
62
62
  define_method(attribute) do
63
- value = send(method).key?(attribute) ? send(method)[attribute] : self.instance_exec(&options[:default])
63
+ value = if send(method).key?(attribute)
64
+ send(method)[attribute]
65
+ elsif options[:default]
66
+ instance_exec(&options[:default])
67
+ end
64
68
 
65
69
  if send(method).frozen?
66
70
  send(method)[attribute] || value
@@ -12,12 +12,13 @@ module Opera
12
12
 
13
13
  if operation_result.success?
14
14
  add_instruction_output(instruction, operation_result.output)
15
- execution = result.executions.pop
16
- result.executions << { execution => operation_result.executions }
17
15
  else
18
16
  result.add_errors(operation_result.errors)
19
17
  result.add_exceptions(operation_result.exceptions)
20
18
  end
19
+
20
+ execution = result.executions.pop
21
+ result.executions << { execution => operation_result.executions }
21
22
  end
22
23
 
23
24
  private
@@ -12,11 +12,11 @@ module Opera
12
12
  transaction_class.send(*arguments) do
13
13
  super
14
14
 
15
- return if !operation.finished? && result.success?
15
+ return if result.success?
16
16
 
17
- raise(RollbackTransactionError)
17
+ raise(transaction_error)
18
18
  end
19
- rescue RollbackTransactionError
19
+ rescue transaction_error
20
20
  nil
21
21
  end
22
22
 
@@ -31,6 +31,10 @@ module Opera
31
31
  def transaction_options
32
32
  config.transaction_options
33
33
  end
34
+
35
+ def transaction_error
36
+ RollbackTransactionError
37
+ end
34
38
  end
35
39
  end
36
40
  end
data/lib/opera/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Opera
2
- VERSION = '0.2.7'
2
+ VERSION = '0.2.10'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opera
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - ProFinda Development Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-03 00:00:00.000000000 Z
11
+ date: 2022-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-validation
@@ -78,7 +78,6 @@ files:
78
78
  - lib/opera.rb
79
79
  - lib/opera/errors.rb
80
80
  - lib/opera/operation.rb
81
- - lib/opera/operation/README.md
82
81
  - lib/opera/operation/base.rb
83
82
  - lib/opera/operation/builder.rb
84
83
  - lib/opera/operation/config.rb
@@ -1,786 +0,0 @@
1
- # Opera::Operation
2
-
3
- Simple DSL for services/interactions classes.
4
-
5
- # Installation
6
-
7
- ```
8
- gem install pro_finda-operation
9
- ```
10
-
11
- or in Gemfile:
12
-
13
- ```
14
- gem 'pro_finda-operation', path: 'vendor/pro_finda-operation'
15
- ```
16
-
17
- # Configuration
18
-
19
- ```ruby
20
- Opera::Operation::Config.configure do |config|
21
- config.transaction_class = ActiveRecord::Base
22
- config.transaction_method = :transaction
23
- config.reporter = if defined?(Rollbar) then Rollbar else Rails.logger
24
- end
25
-
26
- class A < Opera::Operation::Base
27
-
28
- configure do |config|
29
- config.transaction_class = Profile
30
- config.reporter = Rails.logger
31
- end
32
-
33
- success :populate
34
-
35
- operation :inner_operation
36
-
37
- validate :profile_schema
38
-
39
- transaction do
40
- step :create
41
- step :update
42
- step :destroy
43
- end
44
-
45
- validate do
46
- step :validate_object
47
- step :validate_relationships
48
- end
49
-
50
- benchmark do
51
- success :hal_sync
52
- end
53
-
54
- success do
55
- step :send_mail
56
- step :report_to_audit_log
57
- end
58
-
59
- step :output
60
- end
61
- ```
62
-
63
- # Specs
64
-
65
- When using Opera::Operation inside an engine add the following
66
- configuration to your spec_helper.rb or rails_helper.rb:
67
-
68
- ```
69
- Opera::Operation::Config.configure do |config|
70
- config.transaction_class = ActiveRecord::Base
71
- end
72
- ```
73
-
74
- Without this extra configuration you will receive:
75
- ```
76
- NoMethodError:
77
- undefined method `transaction' for nil:NilClass
78
- ```
79
-
80
- # Debugging
81
-
82
- When you want to easily debug exceptions you can add this
83
- to your dummy.rb:
84
-
85
- ```
86
- Rails.application.configure do
87
- config.x.reporter = Logger.new(STDERR)
88
- end
89
- ```
90
-
91
- This should display exceptions captured inside operations.
92
-
93
- You can also do it in Opera::Operation configuration block:
94
-
95
- ```
96
- Opera::Operation::Config.configure do |config|
97
- config.transaction_class = ActiveRecord::Base
98
- config.reporter = Logger.new(STDERR)
99
- end
100
- ```
101
-
102
- # Content
103
- [Basic operation](#user-content-basic-operation)
104
-
105
- [Example with sanitizing parameters](#user-content-example-with-sanitizing-parameters)
106
-
107
- [Example operation with old validations](#user-content-example-operation-with-old-validations)
108
-
109
- [Example with step that raises exception](#user-content-example-with-step-that-raises-exception)
110
-
111
- [Failing transaction](#user-content-failing-transaction)
112
-
113
- [Passing transaction](#user-content-passing-transaction)
114
-
115
- [Benchmark](#user-content-benchmark)
116
-
117
- [Success](#user-content-success)
118
-
119
- [Inner Operation](#user-content-inner-operation)
120
-
121
- [Inner Operations](#user-content-inner-operations)
122
-
123
- # Usage examples
124
-
125
- Some cases and example how to use new operations
126
-
127
- ## Basic operation
128
-
129
- ```ruby
130
- class Profile::Create < Opera::Operation::Base
131
- validate :profile_schema
132
-
133
- step :create
134
- step :send_email
135
- step :output
136
-
137
- def profile_schema
138
- Dry::Validation.Schema do
139
- required(:first_name).filled
140
- end.call(params)
141
- end
142
-
143
- def create
144
- context[:profile] = dependencies[:current_account].profiles.create(params)
145
- end
146
-
147
- def send_email
148
- dependencies[:mailer]&.send_mail(profile: context[:profile])
149
- end
150
-
151
- def output
152
- result.output = { model: context[:profile] }
153
- end
154
- end
155
- ```
156
-
157
- #### Call with valid parameters
158
-
159
- ```ruby
160
- Profile::Create.call(params: {
161
- first_name: :foo,
162
- last_name: :bar
163
- }, dependencies: {
164
- mailer: ProfindaMailer,
165
- current_account: Account.find(1)
166
- })
167
-
168
- #<Opera::Operation::Result:0x0000561636dced60 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :create, :send_email, :output], @output={:model=>#<Profile id: 30, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2018-12-14 16:04:08", updated_at: "2018-12-14 16:04:08", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
169
- ```
170
-
171
- #### Call with INVALID parameters - missing first_name
172
-
173
- ```ruby
174
- Profile::Create.call(params: {
175
- last_name: :bar
176
- }, dependencies: {
177
- mailer: ProfindaMailer,
178
- current_account: Account.find(1)
179
- })
180
-
181
- #<Opera::Operation::Result:0x0000562d3f635390 @errors={:first_name=>["is missing"]}, @exceptions={}, @information={}, @executions=[:profile_schema]>
182
- ```
183
-
184
- #### Call with MISSING dependencies
185
-
186
- ```ruby
187
- Profile::Create.call(params: {
188
- first_name: :foo,
189
- last_name: :bar
190
- }, dependencies: {
191
- current_account: Account.find(1)
192
- })
193
-
194
- #<Opera::Operation::Result:0x007f87ba2c8f00 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :create, :send_email, :output], @output={:model=>#<Profile id: 33, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2019-01-03 12:04:25", updated_at: "2019-01-03 12:04:25", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
195
- ```
196
-
197
- ## Example with sanitizing parameters
198
-
199
- ```ruby
200
- class Profile::Create < Opera::Operation::Base
201
- validate :profile_schema
202
-
203
- step :create
204
- step :send_email
205
- step :output
206
-
207
- def profile_schema
208
- Dry::Validation.Schema do
209
- configure { config.input_processor = :sanitizer }
210
-
211
- required(:first_name).filled
212
- end.call(params)
213
- end
214
-
215
- def create
216
- context[:profile] = dependencies[:current_account].profiles.create(context[:profile_schema_output])
217
- end
218
-
219
- def send_email
220
- return true unless dependencies[:mailer]
221
- dependencies[:mailer].send_mail(profile: context[:profile])
222
- end
223
-
224
- def output
225
- result.output = { model: context[:profile] }
226
- end
227
- end
228
- ```
229
-
230
- ```ruby
231
- Profile::Create.call(params: {
232
- first_name: :foo,
233
- last_name: :bar
234
- }, dependencies: {
235
- mailer: ProfindaMailer,
236
- current_account: Account.find(1)
237
- })
238
-
239
- # NOTE: Last name is missing in output model
240
- #<Opera::Operation::Result:0x000055e36a1fab78 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :create, :send_email, :output], @output={:model=>#<Profile id: 44, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: nil, created_at: "2018-12-17 11:07:08", updated_at: "2018-12-17 11:07:08", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
241
- ```
242
-
243
- ## Example operation with old validations
244
-
245
- ```ruby
246
- class Profile::Create < Opera::Operation::Base
247
- validate :profile_schema
248
-
249
- step :build_record
250
- step :old_validation
251
- step :create
252
- step :send_email
253
- step :output
254
-
255
- def profile_schema
256
- Dry::Validation.Schema do
257
- required(:first_name).filled
258
- end.call(params)
259
- end
260
-
261
- def build_record
262
- context[:profile] = dependencies[:current_account].profiles.build(params)
263
- context[:profile].force_name_validation = true
264
- end
265
-
266
- def old_validation
267
- return true if context[:profile].valid?
268
-
269
- result.add_information(missing_validations: "Please check dry validations")
270
- result.add_errors(context[:profile].errors.messages)
271
-
272
- false
273
- end
274
-
275
- def create
276
- context[:profile].save
277
- end
278
-
279
- def send_email
280
- dependencies[:mailer].send_mail(profile: context[:profile])
281
- end
282
-
283
- def output
284
- result.output = { model: context[:profile] }
285
- end
286
- end
287
- ```
288
-
289
- #### Call with valid parameters
290
-
291
- ```ruby
292
- Profile::Create.call(params: {
293
- first_name: :foo,
294
- last_name: :bar
295
- }, dependencies: {
296
- mailer: ProfindaMailer,
297
- current_account: Account.find(1)
298
- })
299
-
300
- #<Opera::Operation::Result:0x0000560ebc9e7a98 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :build_record, :old_validation, :create, :send_email, :output], @output={:model=>#<Profile id: 41, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2018-12-14 19:15:12", updated_at: "2018-12-14 19:15:12", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
301
- ```
302
-
303
- #### Call with INVALID parameters
304
-
305
- ```ruby
306
- Profile::Create.call(params: {
307
- first_name: :foo
308
- }, dependencies: {
309
- mailer: ProfindaMailer,
310
- current_account: Account.find(1)
311
- })
312
-
313
- #<Opera::Operation::Result:0x0000560ef76ba588 @errors={:last_name=>["can't be blank"]}, @exceptions={}, @information={:missing_validations=>"Please check dry validations"}, @executions=[:build_record, :old_validation]>
314
- ```
315
-
316
- ## Example with step that raises exception
317
-
318
- ```ruby
319
- class Profile::Create < Opera::Operation::Base
320
- validate :profile_schema
321
-
322
- step :build_record
323
- step :exception
324
- step :create
325
- step :send_email
326
- step :output
327
-
328
- def profile_schema
329
- Dry::Validation.Schema do
330
- required(:first_name).filled
331
- end.call(params)
332
- end
333
-
334
- def build_record
335
- context[:profile] = dependencies[:current_account].profiles.build(params)
336
- context[:profile].force_name_validation = true
337
- end
338
-
339
- def exception
340
- raise StandardError, 'Example'
341
- end
342
-
343
- def create
344
- context[:profile] = context[:profile].save
345
- end
346
-
347
- def send_email
348
- return true unless dependencies[:mailer]
349
-
350
- dependencies[:mailer].send_mail(profile: context[:profile])
351
- end
352
-
353
- def output
354
- result.output(model: context[:profile])
355
- end
356
- end
357
- ```
358
- ##### Call with step throwing exception
359
- ```ruby
360
- result = Profile::Create.call(params: {
361
- first_name: :foo,
362
- last_name: :bar
363
- }, dependencies: {
364
- current_account: Account.find(1)
365
- })
366
-
367
- #<Opera::Operation::Result:0x0000562ad0f897c8 @errors={}, @exceptions={"Profile::Create#exception"=>["Example"]}, @information={}, @executions=[:profile_schema, :build_record, :exception]>
368
- ```
369
-
370
- ## Example with step that finishes execution
371
-
372
- ```ruby
373
- class Profile::Create < Opera::Operation::Base
374
- validate :profile_schema
375
-
376
- step :build_record
377
- step :create
378
- step :send_email
379
- step :output
380
-
381
- def profile_schema
382
- Dry::Validation.Schema do
383
- required(:first_name).filled
384
- end.call(params)
385
- end
386
-
387
- def build_record
388
- context[:profile] = dependencies[:current_account].profiles.build(params)
389
- context[:profile].force_name_validation = true
390
- end
391
-
392
- def create
393
- context[:profile] = context[:profile].save
394
- finish
395
- end
396
-
397
- def send_email
398
- return true unless dependencies[:mailer]
399
-
400
- dependencies[:mailer].send_mail(profile: context[:profile])
401
- end
402
-
403
- def output
404
- result.output(model: context[:profile])
405
- end
406
- end
407
- ```
408
- ##### Call
409
- ```ruby
410
- result = Profile::Create.call(params: {
411
- first_name: :foo,
412
- last_name: :bar
413
- }, dependencies: {
414
- current_account: Account.find(1)
415
- })
416
-
417
- #<Opera::Operation::Result:0x007fc2c59a8460 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :build_record, :create]>
418
- ```
419
-
420
- ## Failing transaction
421
-
422
- ```ruby
423
- class Profile::Create < Opera::Operation::Base
424
- configure do |config|
425
- config.transaction_class = Profile
426
- end
427
-
428
- validate :profile_schema
429
-
430
- transaction do
431
- step :create
432
- step :update
433
- end
434
-
435
- step :send_email
436
- step :output
437
-
438
- def profile_schema
439
- Dry::Validation.Schema do
440
- required(:first_name).filled
441
- end.call(params)
442
- end
443
-
444
- def create
445
- context[:profile] = dependencies[:current_account].profiles.create(params)
446
- end
447
-
448
- def update
449
- context[:profile].update(example_attr: :Example)
450
- end
451
-
452
- def send_email
453
- return true unless dependencies[:mailer]
454
-
455
- dependencies[:mailer].send_mail(profile: context[:profile])
456
- end
457
-
458
- def output
459
- result.output = { model: context[:profile] }
460
- end
461
- end
462
- ```
463
-
464
- #### Example with non-existing attribute
465
-
466
- ```ruby
467
- Profile::Create.call(params: {
468
- first_name: :foo,
469
- last_name: :bar
470
- }, dependencies: {
471
- mailer: ProfindaMailer,
472
- current_account: Account.find(1)
473
- })
474
-
475
- D, [2018-12-14T16:13:30.946466 #2504] DEBUG -- : Account Load (0.5ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
476
- D, [2018-12-14T16:13:30.960254 #2504] DEBUG -- : (0.2ms) BEGIN
477
- D, [2018-12-14T16:13:30.983981 #2504] DEBUG -- : SQL (0.7ms) INSERT INTO "profiles" ("first_name", "last_name", "created_at", "updated_at", "account_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["first_name", "foo"], ["last_name", "bar"], ["created_at", "2018-12-14 16:13:30.982289"], ["updated_at", "2018-12-14 16:13:30.982289"], ["account_id", 1]]
478
- D, [2018-12-14T16:13:30.986233 #2504] DEBUG -- : (0.2ms) ROLLBACK
479
- #<Opera::Operation::Result:0x00005650e89b7708 @errors={}, @exceptions={"Profile::Create#update"=>["unknown attribute 'example_attr' for Profile."], "Profile::Create#transaction"=>["Opera::Operation::Base::RollbackTransactionError"]}, @information={}, @executions=[:profile_schema, :create, :update]>
480
- ```
481
-
482
- ## Passing transaction
483
-
484
- ```ruby
485
- class Profile::Create < Opera::Operation::Base
486
- configure do |config|
487
- config.transaction_class = Profile
488
- end
489
-
490
- validate :profile_schema
491
-
492
- transaction do
493
- step :create
494
- step :update
495
- end
496
-
497
- step :send_email
498
- step :output
499
-
500
- def profile_schema
501
- Dry::Validation.Schema do
502
- required(:first_name).filled
503
- end.call(params)
504
- end
505
-
506
- def create
507
- context[:profile] = dependencies[:current_account].profiles.create(params)
508
- end
509
-
510
- def update
511
- context[:profile].update(updated_at: 1.day.ago)
512
- end
513
-
514
- def send_email
515
- return true unless dependencies[:mailer]
516
-
517
- dependencies[:mailer].send_mail(profile: context[:profile])
518
- end
519
-
520
- def output
521
- result.output = { model: context[:profile] }
522
- end
523
- end
524
- ```
525
-
526
- #### Example with updating timestamp
527
-
528
- ```ruby
529
- Profile::Create.call(params: {
530
- first_name: :foo,
531
- last_name: :bar
532
- }, dependencies: {
533
- mailer: ProfindaMailer,
534
- current_account: Account.find(1)
535
- })
536
- D, [2018-12-17T12:10:44.842392 #2741] DEBUG -- : Account Load (0.7ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
537
- D, [2018-12-17T12:10:44.856964 #2741] DEBUG -- : (0.2ms) BEGIN
538
- D, [2018-12-17T12:10:44.881332 #2741] DEBUG -- : SQL (0.7ms) INSERT INTO "profiles" ("first_name", "last_name", "created_at", "updated_at", "account_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["first_name", "foo"], ["last_name", "bar"], ["created_at", "2018-12-17 12:10:44.879684"], ["updated_at", "2018-12-17 12:10:44.879684"], ["account_id", 1]]
539
- D, [2018-12-17T12:10:44.886168 #2741] DEBUG -- : SQL (0.6ms) UPDATE "profiles" SET "updated_at" = $1 WHERE "profiles"."id" = $2 [["updated_at", "2018-12-16 12:10:44.883164"], ["id", 47]]
540
- D, [2018-12-17T12:10:44.898132 #2741] DEBUG -- : (10.3ms) COMMIT
541
- #<Opera::Operation::Result:0x0000556528f29058 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :create, :update, :send_email, :output], @output={:model=>#<Profile id: 47, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2018-12-17 12:10:44", updated_at: "2018-12-16 12:10:44", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
542
- ```
543
-
544
- ## Benchmark
545
-
546
- ```ruby
547
- class Profile::Create < Opera::Operation::Base
548
- validate :profile_schema
549
-
550
- step :create
551
- step :update
552
-
553
- benchmark do
554
- step :send_email
555
- step :output
556
- end
557
-
558
- def profile_schema
559
- Dry::Validation.Schema do
560
- required(:first_name).filled
561
- end.call(params)
562
- end
563
-
564
- def create
565
- context[:profile] = dependencies[:current_account].profiles.create(params)
566
- end
567
-
568
- def update
569
- context[:profile].update(updated_at: 1.day.ago)
570
- end
571
-
572
- def send_email
573
- return true unless dependencies[:mailer]
574
-
575
- dependencies[:mailer].send_mail(profile: context[:profile])
576
- end
577
-
578
- def output
579
- result.output = { model: context[:profile] }
580
- end
581
- end
582
- ```
583
-
584
- #### Example with information (real and total) from benchmark
585
-
586
- ```ruby
587
- Profile::Create.call(params: {
588
- first_name: :foo,
589
- last_name: :bar
590
- }, dependencies: {
591
- current_account: Account.find(1)
592
- })
593
- #<Opera::Operation::Result:0x007ff414a01238 @errors={}, @exceptions={}, @information={:real=>1.800013706088066e-05, :total=>0.0}, @executions=[:profile_schema, :create, :update, :send_email, :output], @output={:model=>#<Profile id: 30, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2018-12-19 10:46:00", updated_at: "2018-12-18 10:46:00", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
594
- ```
595
-
596
- ## Success
597
-
598
- ```ruby
599
- class Profile::Create < Opera::Operation::Base
600
- validate :profile_schema
601
-
602
- success :populate
603
-
604
- step :create
605
- step :update
606
-
607
- success do
608
- step :send_email
609
- step :output
610
- end
611
-
612
- def profile_schema
613
- Dry::Validation.Schema do
614
- required(:first_name).filled
615
- end.call(params)
616
- end
617
-
618
- def populate
619
- context[:attributes] = {}
620
- context[:valid] = false
621
- end
622
-
623
- def create
624
- context[:profile] = dependencies[:current_account].profiles.create(params)
625
- end
626
-
627
- def update
628
- context[:profile].update(updated_at: 1.day.ago)
629
- end
630
-
631
- # NOTE: We can add an error in this step and it won't break the execution
632
- def send_email
633
- result.add_error('mailer', 'Missing dependency')
634
- dependencies[:mailer]&.send_mail(profile: context[:profile])
635
- end
636
-
637
- def output
638
- result.output = { model: context[:profile] }
639
- end
640
- end
641
- ```
642
-
643
- #### Example with information (real and total) from benchmark
644
-
645
- ```ruby
646
- Profile::Create.call(params: {
647
- first_name: :foo,
648
- last_name: :bar
649
- }, dependencies: {
650
- current_account: Account.find(1)
651
- })
652
- #<Opera::Operation::Result:0x007fd0248e5638 @errors={"mailer"=>["Missing dependency"]}, @exceptions={}, @information={}, @executions=[:profile_schema, :populate, :create, :update, :send_email, :output], @output={:model=>#<Profile id: 40, user_id: nil, linkedin_uid: nil, picture: nil, headline: nil, summary: nil, first_name: "foo", last_name: "bar", created_at: "2019-01-03 12:21:35", updated_at: "2019-01-02 12:21:35", agree_to_terms_and_conditions: nil, registration_status: "", account_id: 1, start_date: nil, supervisor_id: nil, picture_processing: false, statistics: {}, data: {}, notification_timestamps: {}, suggestions: {}, notification_settings: {}, contact_information: []>}>
653
- ```
654
-
655
- ## Inner Operation
656
-
657
- ```ruby
658
- class Profile::Find < Opera::Operation::Base
659
- step :find
660
-
661
- def find
662
- result.output = Profile.find(params[:id])
663
- end
664
- end
665
-
666
- class Profile::Create < Opera::Operation::Base
667
- validate :profile_schema
668
-
669
- operation :find
670
-
671
- step :create
672
-
673
- step :output
674
-
675
- def profile_schema
676
- Dry::Validation.Schema do
677
- optional(:id).filled
678
- end.call(params)
679
- end
680
-
681
- def find
682
- Profile::Find.call(params: params, dependencies: dependencies)
683
- end
684
-
685
- def create
686
- return if context[:find_output]
687
- puts 'not found'
688
- end
689
-
690
- def output
691
- result.output = { model: context[:find_output] }
692
- end
693
- end
694
- ```
695
-
696
- #### Example with inner operation doing the find
697
-
698
- ```ruby
699
- Profile::Create.call(params: {
700
- id: 1
701
- }, dependencies: {
702
- current_account: Account.find(1)
703
- })
704
- #<Opera::Operation::Result:0x007f99b25f0f20 @errors={}, @exceptions={}, @information={}, @executions=[:profile_schema, :find, :create, :output], @output={:model=>{:id=>1, :user_id=>1, :linkedin_uid=>nil, ...}}>
705
- ```
706
-
707
- ## Inner Operations
708
- Expects that method returns array of `Opera::Operation::Result`
709
-
710
- ```ruby
711
- class Profile::Create < Opera::Operation::Base
712
- step :validate
713
- step :create
714
-
715
- def validate; end
716
-
717
- def create
718
- result.output = { model: "Profile #{Kernel.rand(100)}" }
719
- end
720
- end
721
-
722
- class Profile::CreateMultiple < Opera::Operation::Base
723
- operations :create_multiple
724
-
725
- step :output
726
-
727
- def create_multiple
728
- (0..params[:number]).map do
729
- Profile::Create.call
730
- end
731
- end
732
-
733
- def output
734
- result.output = context[:create_multiple_output]
735
- end
736
- end
737
- ```
738
-
739
- ```ruby
740
- Profile::CreateMultiple.call(params: { number: 3 })
741
-
742
- #<Opera::Operation::Result:0x0000564189f38c90 @errors={}, @exceptions={}, @information={}, @executions=[{:create_multiple=>[[:validate, :create], [:validate, :create], [:validate, :create], [:validate, :create]]}, :output], @output=[{:model=>"Profile 1"}, {:model=>"Profile 7"}, {:model=>"Profile 69"}, {:model=>"Profile 92"}]>
743
- ```
744
-
745
- ## Opera::Operation::Result - Instance Methods
746
-
747
- Sometimes it may be useful to be able to create an instance of the `Result` with preset `output`.
748
- It can be handy especially in specs. Then just include it in the initializer:
749
-
750
- ```
751
- Opera::Operation::Result.new(output: 'success')
752
- ```
753
-
754
- >
755
- - success? - [true, false] - Return true if no errors and no exceptions
756
- - failure? - [true, false] - Return true if any error or exception
757
- - output - [Anything] - Return Anything
758
- - output=(Anything) - Sets content of operation output
759
- - add_error(key, value) - Adds new error message
760
- - add_errors(Hash) - Adds multiple error messages
761
- - add_exception(method, message, classname: nil) - Adds new exception
762
- - add_exceptions(Hash) - Adds multiple exceptions
763
- - add_information(Hash) - Adss new information - Useful informations for developers
764
-
765
- ## Opera::Operation::Base - Class Methods
766
- >
767
- - step(Symbol) - single instruction
768
- - return [Truthly] - continue operation execution
769
- - return [False] - stops operation execution
770
- - raise Exception - exception gets captured and stops operation execution
771
- - operation(Symbol) - single instruction - requires to return Opera::Operation::Result object
772
- - return [Opera::Operation::Result] - stops operation STEPS execution if any error, exception
773
- - validate(Symbol) - single dry-validations - requires to return Dry::Validation::Result object
774
- - return [Dry::Validation::Result] - stops operation STEPS execution if any error but continue with other validations
775
- - transaction(*Symbols) - list of instructions to be wrapped in transaction
776
- - return [Truthly] - continue operation execution
777
- - return [False|Exception] - stops operation execution and breaks transaction/do rollback
778
- - call(params: Hash, dependencies: Hash?)
779
- - return [Opera::Operation::Result] - never raises an exception
780
-
781
- ## Opera::Operation::Base - Instance Methods
782
- >
783
- - context [Hash] - used to pass information between steps - only for internal usage
784
- - params [Hash] - immutable and received in call method
785
- - dependencies [Hash] - immutable and received in call method
786
- - finish - this method interrupts the execution of steps after is invoked