iry 0.5.1 → 0.6.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: 5ca6d5b931545ba2bb0b9f1e9e7ad77da308e7d0ffe8a64d1df2c1e6378cd1a7
4
- data.tar.gz: 4747d18e4a249735907597277bad301e9177dffa5aa00e3410355be13d523683
3
+ metadata.gz: 592290e30f1db830217241ebde319fbf952ee459ac05c3bc1e87b4b47a73e143
4
+ data.tar.gz: '09cabb7faf8e78a91e7d2443bdfd5466d7e8f63bc90fcfeb2abdb72f93bd79bf'
5
5
  SHA512:
6
- metadata.gz: c2b72c6a64b044c606b3940181971a28fd90fdb1ba7859566adb9f5b7ac17f58aa46544908d06715dbc15105972ee0b272ac65d608dd06ee42fd829799c3ff95
7
- data.tar.gz: 2f5c703a19785a8e7fc5689354c80b91d3d3658f00a031edbddad7ca06c36094959f494bbc157c8b40bce4fd3655fd37fa5769ec1fc02e6b7c74524118ebc37b
6
+ metadata.gz: 915d87f39809daa1a0a76ea66c4718e20afe6dbef4ced1853df47e9457927a464a06204cd4c0abd71dad861d8df6f23c974b2a75796ff7136b17f94875fb36ae
7
+ data.tar.gz: f8b10f525eab24f478a3bb6ee2c1039258b65d532eb5475d584f68bec23cf6c2e305e47033b4621dfe49be563da584c488683905d12c9abf529c07ec194d46bc
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.1
1
+ 0.6.0
@@ -30,7 +30,7 @@ module Iry
30
30
  end
31
31
 
32
32
  # @param model [Handlers::Model]
33
- # @return [void]
33
+ # @return [ActiveModel::Error]
34
34
  def apply(model)
35
35
  model.errors.add(key, message)
36
36
  end
@@ -30,7 +30,7 @@ module Iry
30
30
  end
31
31
 
32
32
  # @param model [Handlers::Model]
33
- # @return [void]
33
+ # @return [ActiveModel::Error]
34
34
  def apply(model)
35
35
  model.errors.add(key, message)
36
36
  end
@@ -35,7 +35,7 @@ module Iry
35
35
  end
36
36
 
37
37
  # @param model [Handlers::Model]
38
- # @return [void]
38
+ # @return [ActiveModel::Error]
39
39
  def apply(model)
40
40
  model.errors.add(error_key, message)
41
41
  end
@@ -35,7 +35,7 @@ module Iry
35
35
  end
36
36
 
37
37
  # @param model [Handlers::Model]
38
- # @return [void]
38
+ # @return [ActiveModel::Error]
39
39
  def apply(model)
40
40
  model.errors.add(error_key, message)
41
41
  end
@@ -6,7 +6,7 @@ module Iry
6
6
  # Sets validation errors on the model
7
7
  # @abstract
8
8
  # @param model [Handlers::Model]
9
- # @return [void]
9
+ # @return [ActiveModel::Error]
10
10
  def apply(model)
11
11
  end
12
12
 
@@ -15,9 +15,9 @@ module Iry
15
15
  # Return always false, failing to handle any constraint
16
16
  # @param err [ActiveRecord::StatementInvalid]
17
17
  # @param model [Model] should inherit {ActiveRecord::Base} and`include Iry` to match the interface
18
- # @return [Boolean]
18
+ # @return [nil, ActiveModel::Error]
19
19
  def handle(err, model)
20
- return false
20
+ return nil
21
21
  end
22
22
  end
23
23
  end
@@ -36,7 +36,9 @@ module Iry
36
36
  # Appends constraint errors as model errors
37
37
  # @param err [ActiveRecord::StatementInvalid]
38
38
  # @param model [Model] should inherit {ActiveRecord::Base} and`include Iry` to match the interface
39
- # @return [void]
39
+ # @return [nil, ActiveModel::Error] if handled constraint, returns the
40
+ # error attached to the model. If constraint wasn't handled or handling
41
+ # failed, `nil` is returned
40
42
  def handle(err, model)
41
43
  pgerr = err.cause
42
44
  constraint_name_msg = pgerr.result.error_field(::PG::Constants::PG_DIAG_MESSAGE_PRIMARY)
@@ -44,12 +46,10 @@ module Iry
44
46
  constraint_name = match[1]
45
47
  constraint = model.class.constraints[constraint_name]
46
48
  if constraint.nil?
47
- return false
49
+ return nil
48
50
  end
49
51
 
50
- constraint.apply(model)
51
-
52
- return true
52
+ return constraint.apply(model)
53
53
  end
54
54
  end
55
55
  end
data/lib/iry/handlers.rb CHANGED
@@ -12,7 +12,8 @@ module Iry
12
12
  # @abstract
13
13
  # @param err [ActiveRecord::StatementInvalid] possible constraint error to handle
14
14
  # @param model [Model]
15
- # @return [Boolean] true if this database handler handled the constraint error
15
+ # @return [nil, ActiveModel::Error] `nil` if couldn't handle the error,
16
+ # otherwise the {ActiveModel::Error} added to the model
16
17
  def handle(err, model)
17
18
  end
18
19
  end
data/lib/iry/patch.rb CHANGED
@@ -6,7 +6,7 @@ module Iry
6
6
  # @return [Boolean] true if successful
7
7
  def create_or_update(...)
8
8
  result = false
9
- Iry.handle_constraints!(self) { result = super }
9
+ TransformConstraints.nested_constraints!(self) { result = super }
10
10
  result
11
11
  end
12
12
  end
@@ -0,0 +1,139 @@
1
+ module Iry
2
+ # Implementation of {Iry} methods, helps ensuring the main module focus on
3
+ # documentation
4
+ module TransformConstraints
5
+ extend self
6
+
7
+ # @param model [Handlers::Model]
8
+ # @yield
9
+ # @return [nil, Handlers::Model]
10
+ def handle_constraints(model, &block)
11
+ handle_constraints!(model, &block)
12
+ rescue StatementInvalid
13
+ return nil
14
+ end
15
+
16
+ # @param model [Handlers::Model]
17
+ # @yield
18
+ # @return [Handlers::Model]
19
+ def handle_constraints!(model, &block)
20
+ # Allows checking if Iry has been activated (handling).
21
+ # Number is used to support nested handle_constraints!
22
+ Thread.current[:iry] ||= 0
23
+ Thread.current[:iry] += 1
24
+
25
+ nested_constraints!(model, &block)
26
+ rescue StatementInvalid => err
27
+ # Imports errors from "nested" models back into the parent, to ensure
28
+ # `errors` is populated and the record is considered invalid
29
+
30
+ # Skip if error has been added to the same object being handled
31
+ if err.record.object_id == model.object_id
32
+ raise
33
+ end
34
+
35
+ # Adds the error only if it hasn't been added already
36
+ already_imported = model
37
+ .errors
38
+ .each
39
+ .lazy
40
+ .select { |ae| ae.respond_to?(:inner_error) }
41
+ .map { |ae| ae.inner_error }
42
+ .include?(err.error)
43
+ if !already_imported
44
+ model.errors.import(err.error)
45
+ end
46
+
47
+ raise
48
+ ensure
49
+ # "Pop" handle_constraints! usage, when 0, no constraint handling should
50
+ # happen
51
+ Thread.current[:iry] -= 1
52
+ end
53
+
54
+ # Tracks constraints of models saved as a consequence of saving another
55
+ # model. This usually represents a situation of model using
56
+ # `accepts_nested_attributes_for`
57
+ # @param model [Handlers::Model]
58
+ # @yield
59
+ # @return [Handlers::Model]
60
+ # @private
61
+ def nested_constraints!(model, &block)
62
+ raise ArgumentError, "Block required" if block.nil?
63
+
64
+ block.()
65
+
66
+ return model
67
+ rescue ActiveRecord::StatementInvalid => err
68
+ # Exit immediately if Iry hasn't been activated
69
+ if Thread.current[:iry].nil? || Thread.current[:iry] == 0
70
+ raise
71
+ end
72
+
73
+ # Exception might be an unknown constraint that is not handled by Iry
74
+ # yet. If that's the case, Null handler will ensure that everything
75
+ # proceeds as if Iry wasn't involved
76
+ handler = Handlers::Null
77
+ case
78
+ when Handlers::PG.handle?(err)
79
+ handler = Handlers::PG
80
+ end
81
+
82
+ model_error = handler.handle(err, model)
83
+
84
+ # This constraint is not handled by Iry and should raise normally
85
+ if model_error.nil?
86
+ raise
87
+ end
88
+
89
+ raise(
90
+ StatementInvalid.new(
91
+ err.message,
92
+ sql: err.sql,
93
+ binds: err.binds,
94
+ record: model,
95
+ error: model_error
96
+ )
97
+ )
98
+ end
99
+
100
+ # @param model [Handlers::Model]
101
+ # @return [Boolean]
102
+ def save(model, ...)
103
+ success = nil
104
+ constraint_model = handle_constraints(model) { success = model.save(...) }
105
+
106
+ if constraint_model
107
+ return success
108
+ end
109
+
110
+ return false
111
+ end
112
+
113
+ # @param model [Handlers::Model]
114
+ # @return [true]
115
+ # @raise [ConstraintViolation]
116
+ # @raise [ActiveRecord::RecordInvalid]
117
+ def save!(model, ...)
118
+ constraint_model = handle_constraints(model) { model.save!(...) }
119
+
120
+ if constraint_model
121
+ return true
122
+ end
123
+
124
+ raise ConstraintViolation.new(model)
125
+ end
126
+
127
+ # @param model [Handlers::Model]
128
+ # @return [Handlers::Model]
129
+ def destroy(model)
130
+ constraint_result = handle_constraints(model) { model.destroy }
131
+
132
+ if constraint_result.nil?
133
+ return false
134
+ end
135
+
136
+ return constraint_result
137
+ end
138
+ end
139
+ end
data/lib/iry.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "iry/constraint/exclusion"
12
12
  require_relative "iry/constraint/foreign_key"
13
13
  require_relative "iry/constraint/unique"
14
14
  require_relative "iry/patch"
15
+ require_relative "iry/transform_constraints"
15
16
 
16
17
  # Entrypoint of constraint validation, include in a class inheriting {ActiveRecord::Base} and the following class-level
17
18
  # methods will be available:
@@ -40,7 +41,8 @@ module Iry
40
41
  end
41
42
 
42
43
  # Raised when constraints have been violated and have been converted to
43
- # model errors
44
+ # model errors, on {ActiveRecord::Base#save!} calls, to simulate a behavior
45
+ # similar to {ActiveRecord::RecordInvalid} when it's raised
44
46
  class ConstraintViolation < ActiveRecord::RecordInvalid
45
47
  include Error
46
48
 
@@ -50,8 +52,26 @@ module Iry
50
52
  # @return [Handlers::Model]
51
53
  end
52
54
 
55
+ # Raised when constraints errors happen and go through Iry, even if these
56
+ # are not handled. This class inherits from {ActiveRecord::StatementInvalid}
57
+ # to maximize compatibility with existing code
53
58
  class StatementInvalid < ActiveRecord::StatementInvalid
54
59
  include Error
60
+
61
+ # @return [Handlers::Model] model affected by the constraint violation
62
+ attr_reader :record
63
+ # @return [ActiveModel::Error] error attached to the `record` for the
64
+ # constraint violation
65
+ attr_reader :error
66
+
67
+ # @param message [nil, String]
68
+ # @param record [Handlers::Model]
69
+ # @param error [ActiveModel::Error]
70
+ def initialize(message = nil, record:, error:, **kwargs)
71
+ @record = record
72
+ @error = error
73
+ super(message, **kwargs)
74
+ end
55
75
  end
56
76
 
57
77
  # @param klass [Module]
@@ -88,9 +108,7 @@ module Iry
88
108
  # result #=> nil
89
109
  # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
90
110
  def self.handle_constraints(model, &block)
91
- handle_constraints!(model, &block)
92
- rescue StatementInvalid
93
- return nil
111
+ TransformConstraints.handle_constraints(model, &block)
94
112
  end
95
113
 
96
114
  # Executes block and in case of constraints violations on `model`, block is
@@ -100,26 +118,7 @@ module Iry
100
118
  # @yield block must perform the save operation, usually with `save`
101
119
  # @return [Handlers::Model] returns `model` parameter
102
120
  def self.handle_constraints!(model, &block)
103
- raise ArgumentError, "Block required" if block.nil?
104
-
105
- block.()
106
-
107
- return model
108
- rescue ActiveRecord::StatementInvalid => err
109
- handler = Handlers::Null
110
- case
111
- when Handlers::PG.handle?(err)
112
- handler = Handlers::PG
113
- end
114
-
115
- is_handled = handler.handle(err, model)
116
-
117
- # This constraint is not handled by Iry and should raise normally
118
- if !is_handled
119
- raise
120
- end
121
-
122
- raise StatementInvalid.new(err.message, sql: err.sql, binds: err.binds)
121
+ TransformConstraints.handle_constraints!(model, &block)
123
122
  end
124
123
 
125
124
  # Similar to {ActiveRecord::Base#save} but in case of constraint violations,
@@ -129,14 +128,7 @@ module Iry
129
128
  # @param model [Handlers::Model] model to save
130
129
  # @return [Boolean] `true` if successful
131
130
  def self.save(model, ...)
132
- success = nil
133
- constraint_model = handle_constraints(model) { success = model.save(...) }
134
-
135
- if constraint_model
136
- return success
137
- end
138
-
139
- return false
131
+ TransformConstraints.save(model, ...)
140
132
  end
141
133
 
142
134
  # Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
@@ -151,13 +143,7 @@ module Iry
151
143
  # @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
152
144
  # raised, but not a constraint violation
153
145
  def self.save!(model, ...)
154
- constraint_model = handle_constraints(model) { model.save!(...) }
155
-
156
- if constraint_model
157
- return true
158
- end
159
-
160
- raise ConstraintViolation.new(model)
146
+ TransformConstraints.save!(model, ...)
161
147
  end
162
148
 
163
149
  # Similar to {ActiveRecord::Base#destroy} but in case of constraint
@@ -165,12 +151,6 @@ module Iry
165
151
  # @param model [Handlers::Model] model to destroy
166
152
  # @return [Handlers::Model] the destroyed model
167
153
  def self.destroy(model)
168
- constraint_result = handle_constraints(model) { model.destroy }
169
-
170
- if constraint_result.nil?
171
- return false
172
- end
173
-
174
- return constraint_result
154
+ TransformConstraints.destroy(model)
175
155
  end
176
156
  end
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "iry",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "iry",
9
- "version": "0.5.1",
9
+ "version": "0.6.0",
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
12
  "conventional-changelog-cli": ">= 3.0.0",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iry",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Transform database constraint errors into activerecord validation errors",
5
5
  "private": true,
6
6
  "main": "index.js",
data/rbi/iry.rbi CHANGED
@@ -101,13 +101,44 @@ module Iry
101
101
  end
102
102
 
103
103
  # Raised when constraints have been violated and have been converted to
104
- # model errors
104
+ # model errors, on {ActiveRecord::Base#save!} calls, to simulate a behavior
105
+ # similar to {ActiveRecord::RecordInvalid} when it's raised
105
106
  class ConstraintViolation < ActiveRecord::RecordInvalid
106
107
  include Iry::Error
107
108
  end
108
109
 
110
+ # Raised when constraints errors happen and go through Iry, even if these
111
+ # are not handled. This class inherits from {ActiveRecord::StatementInvalid}
112
+ # to maximize compatibility with existing code
109
113
  class StatementInvalid < ActiveRecord::StatementInvalid
110
114
  include Iry::Error
115
+
116
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
117
+ # sord omit - no YARD type given for "**kwargs", using untyped
118
+ # _@param_ `message`
119
+ #
120
+ # _@param_ `record`
121
+ #
122
+ # _@param_ `error`
123
+ sig do
124
+ params(
125
+ message: T.nilable(String),
126
+ record: Handlers::Model,
127
+ error: ActiveModel::Error,
128
+ kwargs: T.untyped
129
+ ).void
130
+ end
131
+ def initialize(message = nil, record:, error:, **kwargs); end
132
+
133
+ # _@return_ — model affected by the constraint violation
134
+ sig { returns(Handlers::Model) }
135
+ attr_reader :record
136
+
137
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
138
+ # _@return_ — error attached to the `record` for the
139
+ # constraint violation
140
+ sig { returns(ActiveModel::Error) }
141
+ attr_reader :error
111
142
  end
112
143
 
113
144
  # Overrides private API method {ActiveRecord#create_or_update} to handle
@@ -201,8 +232,9 @@ module Iry
201
232
  #
202
233
  # _@param_ `model`
203
234
  #
204
- # _@return_ — true if this database handler handled the constraint error
205
- sig { params(err: ActiveRecord::StatementInvalid, model: Model).returns(T::Boolean) }
235
+ # _@return_ — `nil` if couldn't handle the error,
236
+ # otherwise the {ActiveModel::Error} added to the model
237
+ sig { params(err: ActiveRecord::StatementInvalid, model: Model).void }
206
238
  def handle(err, model); end
207
239
  end
208
240
 
@@ -257,6 +289,10 @@ module Iry
257
289
  # _@param_ `err`
258
290
  #
259
291
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
292
+ #
293
+ # _@return_ — if handled constraint, returns the
294
+ # error attached to the model. If constraint wasn't handled or handling
295
+ # failed, `nil` is returned
260
296
  sig { params(err: ActiveRecord::StatementInvalid, model: Model).void }
261
297
  def handle(err, model); end
262
298
 
@@ -275,6 +311,10 @@ module Iry
275
311
  # _@param_ `err`
276
312
  #
277
313
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
314
+ #
315
+ # _@return_ — if handled constraint, returns the
316
+ # error attached to the model. If constraint wasn't handled or handling
317
+ # failed, `nil` is returned
278
318
  sig { params(err: ActiveRecord::StatementInvalid, model: Model).void }
279
319
  def self.handle(err, model); end
280
320
  end
@@ -297,7 +337,7 @@ module Iry
297
337
  # _@param_ `err`
298
338
  #
299
339
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
300
- sig { params(err: ActiveRecord::StatementInvalid, model: Model).returns(T::Boolean) }
340
+ sig { params(err: ActiveRecord::StatementInvalid, model: Model).void }
301
341
  def handle(err, model); end
302
342
 
303
343
  # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
@@ -313,7 +353,7 @@ module Iry
313
353
  # _@param_ `err`
314
354
  #
315
355
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
316
- sig { params(err: ActiveRecord::StatementInvalid, model: Model).returns(T::Boolean) }
356
+ sig { params(err: ActiveRecord::StatementInvalid, model: Model).void }
317
357
  def self.handle(err, model); end
318
358
  end
319
359
  end
@@ -337,10 +377,11 @@ module Iry
337
377
  # A constraint has a name and can apply errors to an object inheriting from {ActiveRecord::Base}
338
378
  # @abstract
339
379
  module Constraint
380
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
340
381
  # Sets validation errors on the model
341
382
  #
342
383
  # _@param_ `model`
343
- sig { params(model: Handlers::Model).void }
384
+ sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
344
385
  def apply(model); end
345
386
 
346
387
  # Name of the constraint to be caught from the database
@@ -369,8 +410,9 @@ module Iry
369
410
  sig { params(key: Symbol, name: String, message: T.any(Symbol, String)).void }
370
411
  def initialize(key, name:, message: :invalid); end
371
412
 
413
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
372
414
  # _@param_ `model`
373
- sig { params(model: Handlers::Model).void }
415
+ sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
374
416
  def apply(model); end
375
417
 
376
418
  sig { returns(Symbol) }
@@ -409,8 +451,9 @@ module Iry
409
451
  end
410
452
  def initialize(keys, name:, error_key:, message: :taken); end
411
453
 
454
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
412
455
  # _@param_ `model`
413
- sig { params(model: Handlers::Model).void }
456
+ sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
414
457
  def apply(model); end
415
458
 
416
459
  sig { returns(T::Array[Symbol]) }
@@ -443,8 +486,9 @@ module Iry
443
486
  sig { params(key: Symbol, name: String, message: T.any(Symbol, String)).void }
444
487
  def initialize(key, name:, message: :taken); end
445
488
 
489
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
446
490
  # _@param_ `model`
447
- sig { params(model: Handlers::Model).void }
491
+ sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
448
492
  def apply(model); end
449
493
 
450
494
  sig { returns(Symbol) }
@@ -483,8 +527,9 @@ module Iry
483
527
  end
484
528
  def initialize(keys, name:, error_key:, message: :required); end
485
529
 
530
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
486
531
  # _@param_ `model`
487
- sig { params(model: Handlers::Model).void }
532
+ sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
488
533
  def apply(model); end
489
534
 
490
535
  sig { returns(T::Array[Symbol]) }
@@ -500,4 +545,66 @@ module Iry
500
545
  attr_accessor :error_key
501
546
  end
502
547
  end
548
+
549
+ # Implementation of {Iry} methods, helps ensuring the main module focus on
550
+ # documentation
551
+ module TransformConstraints
552
+ extend Iry::TransformConstraints
553
+
554
+ # _@param_ `model`
555
+ sig { params(model: Handlers::Model, block: T.untyped).void }
556
+ def handle_constraints(model, &block); end
557
+
558
+ # _@param_ `model`
559
+ sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
560
+ def handle_constraints!(model, &block); end
561
+
562
+ # Tracks constraints of models saved as a consequence of saving another
563
+ # model. This usually represents a situation of model using
564
+ # `accepts_nested_attributes_for`
565
+ #
566
+ # _@param_ `model`
567
+ sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
568
+ def nested_constraints!(model, &block); end
569
+
570
+ # _@param_ `model`
571
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
572
+ def save(model); end
573
+
574
+ # _@param_ `model`
575
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
576
+ def save!(model); end
577
+
578
+ # _@param_ `model`
579
+ sig { params(model: Handlers::Model).returns(Handlers::Model) }
580
+ def destroy(model); end
581
+
582
+ # _@param_ `model`
583
+ sig { params(model: Handlers::Model, block: T.untyped).void }
584
+ def self.handle_constraints(model, &block); end
585
+
586
+ # _@param_ `model`
587
+ sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
588
+ def self.handle_constraints!(model, &block); end
589
+
590
+ # Tracks constraints of models saved as a consequence of saving another
591
+ # model. This usually represents a situation of model using
592
+ # `accepts_nested_attributes_for`
593
+ #
594
+ # _@param_ `model`
595
+ sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
596
+ def self.nested_constraints!(model, &block); end
597
+
598
+ # _@param_ `model`
599
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
600
+ def self.save(model); end
601
+
602
+ # _@param_ `model`
603
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
604
+ def self.save!(model); end
605
+
606
+ # _@param_ `model`
607
+ sig { params(model: Handlers::Model).returns(Handlers::Model) }
608
+ def self.destroy(model); end
609
+ end
503
610
  end
data/sig/iry.rbs CHANGED
@@ -93,13 +93,39 @@ module Iry
93
93
  end
94
94
 
95
95
  # Raised when constraints have been violated and have been converted to
96
- # model errors
96
+ # model errors, on {ActiveRecord::Base#save!} calls, to simulate a behavior
97
+ # similar to {ActiveRecord::RecordInvalid} when it's raised
97
98
  class ConstraintViolation < ActiveRecord::RecordInvalid
98
99
  include Iry::Error
99
100
  end
100
101
 
102
+ # Raised when constraints errors happen and go through Iry, even if these
103
+ # are not handled. This class inherits from {ActiveRecord::StatementInvalid}
104
+ # to maximize compatibility with existing code
101
105
  class StatementInvalid < ActiveRecord::StatementInvalid
102
106
  include Iry::Error
107
+
108
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
109
+ # sord omit - no YARD type given for "**kwargs", using untyped
110
+ # _@param_ `message`
111
+ #
112
+ # _@param_ `record`
113
+ #
114
+ # _@param_ `error`
115
+ def initialize: (
116
+ ?String? message,
117
+ record: Handlers::Model,
118
+ error: ActiveModel::Error,
119
+ **untyped kwargs
120
+ ) -> void
121
+
122
+ # _@return_ — model affected by the constraint violation
123
+ attr_reader record: Handlers::Model
124
+
125
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
126
+ # _@return_ — error attached to the `record` for the
127
+ # constraint violation
128
+ attr_reader error: ActiveModel::Error
103
129
  end
104
130
 
105
131
  # Overrides private API method {ActiveRecord#create_or_update} to handle
@@ -182,8 +208,9 @@ module Iry
182
208
  #
183
209
  # _@param_ `model`
184
210
  #
185
- # _@return_ — true if this database handler handled the constraint error
186
- def handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
211
+ # _@return_ — `nil` if couldn't handle the error,
212
+ # otherwise the {ActiveModel::Error} added to the model
213
+ def handle: (ActiveRecord::StatementInvalid err, Model model) -> void
187
214
  end
188
215
 
189
216
  # Interface of the model class. This class is usually inherits from {ActiveRecord::Base}
@@ -224,6 +251,10 @@ module Iry
224
251
  # _@param_ `err`
225
252
  #
226
253
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
254
+ #
255
+ # _@return_ — if handled constraint, returns the
256
+ # error attached to the model. If constraint wasn't handled or handling
257
+ # failed, `nil` is returned
227
258
  def handle: (ActiveRecord::StatementInvalid err, Model model) -> void
228
259
 
229
260
  # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
@@ -240,6 +271,10 @@ module Iry
240
271
  # _@param_ `err`
241
272
  #
242
273
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
274
+ #
275
+ # _@return_ — if handled constraint, returns the
276
+ # error attached to the model. If constraint wasn't handled or handling
277
+ # failed, `nil` is returned
243
278
  def self.handle: (ActiveRecord::StatementInvalid err, Model model) -> void
244
279
  end
245
280
 
@@ -260,7 +295,7 @@ module Iry
260
295
  # _@param_ `err`
261
296
  #
262
297
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
263
- def handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
298
+ def handle: (ActiveRecord::StatementInvalid err, Model model) -> void
264
299
 
265
300
  # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
266
301
  # Returns always true, catching any unhandled database exception
@@ -274,7 +309,7 @@ module Iry
274
309
  # _@param_ `err`
275
310
  #
276
311
  # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
277
- def self.handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
312
+ def self.handle: (ActiveRecord::StatementInvalid err, Model model) -> void
278
313
  end
279
314
  end
280
315
 
@@ -295,10 +330,11 @@ module Iry
295
330
  # A constraint has a name and can apply errors to an object inheriting from {ActiveRecord::Base}
296
331
  # @abstract
297
332
  module Constraint
333
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
298
334
  # Sets validation errors on the model
299
335
  #
300
336
  # _@param_ `model`
301
- def apply: (Handlers::Model model) -> void
337
+ def apply: (Handlers::Model model) -> ActiveModel::Error
302
338
 
303
339
  # Name of the constraint to be caught from the database
304
340
  def name: () -> String
@@ -322,8 +358,9 @@ module Iry
322
358
  # _@param_ `name` — constraint name
323
359
  def initialize: (Symbol key, name: String, ?message: (Symbol | String)) -> void
324
360
 
361
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
325
362
  # _@param_ `model`
326
- def apply: (Handlers::Model model) -> void
363
+ def apply: (Handlers::Model model) -> ActiveModel::Error
327
364
 
328
365
  attr_accessor key: Symbol
329
366
 
@@ -354,8 +391,9 @@ module Iry
354
391
  ?message: (Symbol | String)
355
392
  ) -> void
356
393
 
394
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
357
395
  # _@param_ `model`
358
- def apply: (Handlers::Model model) -> void
396
+ def apply: (Handlers::Model model) -> ActiveModel::Error
359
397
 
360
398
  attr_accessor keys: ::Array[Symbol]
361
399
 
@@ -381,8 +419,9 @@ module Iry
381
419
  # _@param_ `name` — constraint name
382
420
  def initialize: (Symbol key, name: String, ?message: (Symbol | String)) -> void
383
421
 
422
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
384
423
  # _@param_ `model`
385
- def apply: (Handlers::Model model) -> void
424
+ def apply: (Handlers::Model model) -> ActiveModel::Error
386
425
 
387
426
  attr_accessor key: Symbol
388
427
 
@@ -413,8 +452,9 @@ module Iry
413
452
  ?message: (Symbol | String)
414
453
  ) -> void
415
454
 
455
+ # sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
416
456
  # _@param_ `model`
417
- def apply: (Handlers::Model model) -> void
457
+ def apply: (Handlers::Model model) -> ActiveModel::Error
418
458
 
419
459
  attr_accessor keys: ::Array[Symbol]
420
460
 
@@ -425,4 +465,54 @@ module Iry
425
465
  attr_accessor error_key: Symbol
426
466
  end
427
467
  end
468
+
469
+ # Implementation of {Iry} methods, helps ensuring the main module focus on
470
+ # documentation
471
+ module TransformConstraints
472
+ extend Iry::TransformConstraints
473
+
474
+ # _@param_ `model`
475
+ def handle_constraints: (Handlers::Model model) -> void
476
+
477
+ # _@param_ `model`
478
+ def handle_constraints!: (Handlers::Model model) -> Handlers::Model
479
+
480
+ # Tracks constraints of models saved as a consequence of saving another
481
+ # model. This usually represents a situation of model using
482
+ # `accepts_nested_attributes_for`
483
+ #
484
+ # _@param_ `model`
485
+ def nested_constraints!: (Handlers::Model model) -> Handlers::Model
486
+
487
+ # _@param_ `model`
488
+ def save: (Handlers::Model model) -> bool
489
+
490
+ # _@param_ `model`
491
+ def save!: (Handlers::Model model) -> bool
492
+
493
+ # _@param_ `model`
494
+ def destroy: (Handlers::Model model) -> Handlers::Model
495
+
496
+ # _@param_ `model`
497
+ def self.handle_constraints: (Handlers::Model model) -> void
498
+
499
+ # _@param_ `model`
500
+ def self.handle_constraints!: (Handlers::Model model) -> Handlers::Model
501
+
502
+ # Tracks constraints of models saved as a consequence of saving another
503
+ # model. This usually represents a situation of model using
504
+ # `accepts_nested_attributes_for`
505
+ #
506
+ # _@param_ `model`
507
+ def self.nested_constraints!: (Handlers::Model model) -> Handlers::Model
508
+
509
+ # _@param_ `model`
510
+ def self.save: (Handlers::Model model) -> bool
511
+
512
+ # _@param_ `model`
513
+ def self.save!: (Handlers::Model model) -> bool
514
+
515
+ # _@param_ `model`
516
+ def self.destroy: (Handlers::Model model) -> Handlers::Model
517
+ end
428
518
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Belladonna
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-11 00:00:00.000000000 Z
11
+ date: 2023-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -107,6 +107,7 @@ files:
107
107
  - lib/iry/handlers/pg.rb
108
108
  - lib/iry/macros.rb
109
109
  - lib/iry/patch.rb
110
+ - lib/iry/transform_constraints.rb
110
111
  - lib/iry/version.rb
111
112
  - package-lock.json
112
113
  - package.json