iry 0.5.1 → 0.7.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/VERSION +1 -1
- data/db/schema.pgsql +17 -4
- data/lib/iry/constraint/check.rb +8 -2
- data/lib/iry/constraint/exclusion.rb +1 -1
- data/lib/iry/constraint/foreign_key.rb +12 -2
- data/lib/iry/constraint/unique.rb +22 -2
- data/lib/iry/constraint.rb +1 -1
- data/lib/iry/handlers/null.rb +2 -2
- data/lib/iry/handlers/pg.rb +5 -5
- data/lib/iry/handlers.rb +2 -1
- data/lib/iry/patch.rb +1 -1
- data/lib/iry/transform_constraints.rb +139 -0
- data/lib/iry.rb +27 -46
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/rbi/iry.rbi +119 -10
- data/sig/iry.rbs +102 -10
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ba546c69426b3b1d4c530d79ed5cfed56b5f3ea5dfe629a37b5061a90213b33
|
4
|
+
data.tar.gz: 65aa3e75c36b7fae90d81e20126c0bc134ff16ee7ddc009349754cd17cc14c29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef79029f7a9f7a51dbb20964ad407ea146417a10de1c7c4d9149a9d83acece6e9db2abe2f3ca6779c684e31554bea9e22e6496579b5cc16eaf53ec787d6b4d17
|
7
|
+
data.tar.gz: a7daca1aca5c175224affa28884e83c19fcdfd4b01369c8b28f6cea2cfd5cea476fca77d433eb84fa53518a3812c03bc12448617bbd2a104b49dcaec1757cf44
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/db/schema.pgsql
CHANGED
@@ -3,14 +3,27 @@ create extension if not exists "btree_gist";
|
|
3
3
|
|
4
4
|
create table if not exists users (
|
5
5
|
id uuid primary key default gen_random_uuid(),
|
6
|
-
unique_text text
|
6
|
+
unique_text text not null default gen_random_uuid()::text,
|
7
7
|
exclude_text text not null default gen_random_uuid()::text,
|
8
|
-
user_id uuid
|
9
|
-
untracked_text text
|
8
|
+
user_id uuid,
|
9
|
+
untracked_text text not null default gen_random_uuid()::text,
|
10
10
|
free_text text not null default '',
|
11
|
-
friend_user_id uuid
|
11
|
+
friend_user_id uuid,
|
12
12
|
created_at timestamp(6) not null,
|
13
13
|
updated_at timestamp(6) not null,
|
14
14
|
-- acts similar to unique constraint
|
15
15
|
exclude using gist (exclude_text with =)
|
16
16
|
);
|
17
|
+
|
18
|
+
create unique index if not exists
|
19
|
+
index_users_on_unique_text on users(unique_text);
|
20
|
+
create unique index if not exists
|
21
|
+
index_users_on_untracked_text on users(untracked_text);
|
22
|
+
alter table users
|
23
|
+
add constraint chk_rails_15df0d7772 check (unique_text != 'invalid');
|
24
|
+
alter table users
|
25
|
+
add constraint fk_rails_6d0b8b3c2f
|
26
|
+
foreign key (user_id) references users(id);
|
27
|
+
alter table users
|
28
|
+
add constraint fk_rails_d3f200176b
|
29
|
+
foreign key (friend_user_id) references users(id);
|
data/lib/iry/constraint/check.rb
CHANGED
@@ -6,7 +6,13 @@ module Iry
|
|
6
6
|
# @param table_name [String]
|
7
7
|
# @return [String]
|
8
8
|
def self.infer_name(key, table_name)
|
9
|
-
|
9
|
+
# PostgreSQL convention:
|
10
|
+
# "#{table_name}_#{key}_check"
|
11
|
+
# Rails convention
|
12
|
+
id = "#{table_name}_#{key}_chk"
|
13
|
+
hashed_id = OpenSSL::Digest::SHA256.hexdigest(id)[0..9]
|
14
|
+
|
15
|
+
"chk_rails_#{hashed_id}"
|
10
16
|
end
|
11
17
|
|
12
18
|
# @return [Symbol]
|
@@ -30,7 +36,7 @@ module Iry
|
|
30
36
|
end
|
31
37
|
|
32
38
|
# @param model [Handlers::Model]
|
33
|
-
# @return [
|
39
|
+
# @return [ActiveModel::Error]
|
34
40
|
def apply(model)
|
35
41
|
model.errors.add(key, message)
|
36
42
|
end
|
@@ -6,7 +6,17 @@ module Iry
|
|
6
6
|
# @param table_name [String]
|
7
7
|
# @return [String]
|
8
8
|
def self.infer_name(keys, table_name)
|
9
|
-
|
9
|
+
if keys.size > 1
|
10
|
+
# PostgreSQL convention:
|
11
|
+
return "#{table_name}_#{keys.join("_")}_fkey"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Rails convention:
|
15
|
+
column = keys.first
|
16
|
+
id = "#{table_name}_#{column}_fk"
|
17
|
+
hashed_id = OpenSSL::Digest::SHA256.hexdigest(id)[0..9]
|
18
|
+
|
19
|
+
"fk_rails_#{hashed_id}"
|
10
20
|
end
|
11
21
|
|
12
22
|
# @return [<Symbol>]
|
@@ -35,7 +45,7 @@ module Iry
|
|
35
45
|
end
|
36
46
|
|
37
47
|
# @param model [Handlers::Model]
|
38
|
-
# @return [
|
48
|
+
# @return [ActiveModel::Error]
|
39
49
|
def apply(model)
|
40
50
|
model.errors.add(error_key, message)
|
41
51
|
end
|
@@ -1,12 +1,32 @@
|
|
1
1
|
module Iry
|
2
2
|
module Constraint
|
3
3
|
class Unique
|
4
|
+
MAX_INFER_NAME_BYTE_SIZE = 62
|
5
|
+
|
4
6
|
# Infers the unique constraint name based on keys and table name
|
5
7
|
# @param keys [<Symbol>]
|
6
8
|
# @param table_name [String]
|
7
9
|
# @return [String]
|
8
10
|
def self.infer_name(keys, table_name)
|
9
|
-
|
11
|
+
# PostgreSQL convention:
|
12
|
+
# "#{table_name}_#{keys.join("_")}_key"
|
13
|
+
|
14
|
+
# Rails convention:
|
15
|
+
# index_trip_hikers_on_trip_id_and_hiker_card_id
|
16
|
+
# index_TABLENAME_on_COLUMN1_and_COLUMN2
|
17
|
+
name = "index_#{table_name}_on_#{keys.join("_and_")}"
|
18
|
+
if name.bytesize <= MAX_INFER_NAME_BYTE_SIZE
|
19
|
+
return name
|
20
|
+
end
|
21
|
+
|
22
|
+
digest = OpenSSL::Digest::SHA256.hexdigest(name)[0..9]
|
23
|
+
hashed_id = "_#{digest}"
|
24
|
+
name = "idx_on_#{keys.join("_")}"
|
25
|
+
|
26
|
+
short_limit = max_index_name_size - hashed_identifier.bytesize
|
27
|
+
short_name = name.mb_chars.limit(short_limit).to_s
|
28
|
+
|
29
|
+
"#{short_name}#{hashed_identifier}"
|
10
30
|
end
|
11
31
|
|
12
32
|
# @return [<Symbol>]
|
@@ -35,7 +55,7 @@ module Iry
|
|
35
55
|
end
|
36
56
|
|
37
57
|
# @param model [Handlers::Model]
|
38
|
-
# @return [
|
58
|
+
# @return [ActiveModel::Error]
|
39
59
|
def apply(model)
|
40
60
|
model.errors.add(error_key, message)
|
41
61
|
end
|
data/lib/iry/constraint.rb
CHANGED
data/lib/iry/handlers/null.rb
CHANGED
@@ -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 [
|
18
|
+
# @return [nil, ActiveModel::Error]
|
19
19
|
def handle(err, model)
|
20
|
-
return
|
20
|
+
return nil
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/lib/iry/handlers/pg.rb
CHANGED
@@ -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 [
|
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
|
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 [
|
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
@@ -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
@@ -1,4 +1,5 @@
|
|
1
1
|
require "active_record"
|
2
|
+
require "openssl"
|
2
3
|
|
3
4
|
require_relative "iry/version"
|
4
5
|
require_relative "iry/handlers"
|
@@ -12,6 +13,7 @@ require_relative "iry/constraint/exclusion"
|
|
12
13
|
require_relative "iry/constraint/foreign_key"
|
13
14
|
require_relative "iry/constraint/unique"
|
14
15
|
require_relative "iry/patch"
|
16
|
+
require_relative "iry/transform_constraints"
|
15
17
|
|
16
18
|
# Entrypoint of constraint validation, include in a class inheriting {ActiveRecord::Base} and the following class-level
|
17
19
|
# methods will be available:
|
@@ -40,7 +42,8 @@ module Iry
|
|
40
42
|
end
|
41
43
|
|
42
44
|
# Raised when constraints have been violated and have been converted to
|
43
|
-
# model errors
|
45
|
+
# model errors, on {ActiveRecord::Base#save!} calls, to simulate a behavior
|
46
|
+
# similar to {ActiveRecord::RecordInvalid} when it's raised
|
44
47
|
class ConstraintViolation < ActiveRecord::RecordInvalid
|
45
48
|
include Error
|
46
49
|
|
@@ -50,8 +53,26 @@ module Iry
|
|
50
53
|
# @return [Handlers::Model]
|
51
54
|
end
|
52
55
|
|
56
|
+
# Raised when constraints errors happen and go through Iry, even if these
|
57
|
+
# are not handled. This class inherits from {ActiveRecord::StatementInvalid}
|
58
|
+
# to maximize compatibility with existing code
|
53
59
|
class StatementInvalid < ActiveRecord::StatementInvalid
|
54
60
|
include Error
|
61
|
+
|
62
|
+
# @return [Handlers::Model] model affected by the constraint violation
|
63
|
+
attr_reader :record
|
64
|
+
# @return [ActiveModel::Error] error attached to the `record` for the
|
65
|
+
# constraint violation
|
66
|
+
attr_reader :error
|
67
|
+
|
68
|
+
# @param message [nil, String]
|
69
|
+
# @param record [Handlers::Model]
|
70
|
+
# @param error [ActiveModel::Error]
|
71
|
+
def initialize(message = nil, record:, error:, **kwargs)
|
72
|
+
@record = record
|
73
|
+
@error = error
|
74
|
+
super(message, **kwargs)
|
75
|
+
end
|
55
76
|
end
|
56
77
|
|
57
78
|
# @param klass [Module]
|
@@ -88,9 +109,7 @@ module Iry
|
|
88
109
|
# result #=> nil
|
89
110
|
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
90
111
|
def self.handle_constraints(model, &block)
|
91
|
-
handle_constraints
|
92
|
-
rescue StatementInvalid
|
93
|
-
return nil
|
112
|
+
TransformConstraints.handle_constraints(model, &block)
|
94
113
|
end
|
95
114
|
|
96
115
|
# Executes block and in case of constraints violations on `model`, block is
|
@@ -100,26 +119,7 @@ module Iry
|
|
100
119
|
# @yield block must perform the save operation, usually with `save`
|
101
120
|
# @return [Handlers::Model] returns `model` parameter
|
102
121
|
def self.handle_constraints!(model, &block)
|
103
|
-
|
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)
|
122
|
+
TransformConstraints.handle_constraints!(model, &block)
|
123
123
|
end
|
124
124
|
|
125
125
|
# Similar to {ActiveRecord::Base#save} but in case of constraint violations,
|
@@ -129,14 +129,7 @@ module Iry
|
|
129
129
|
# @param model [Handlers::Model] model to save
|
130
130
|
# @return [Boolean] `true` if successful
|
131
131
|
def self.save(model, ...)
|
132
|
-
|
133
|
-
constraint_model = handle_constraints(model) { success = model.save(...) }
|
134
|
-
|
135
|
-
if constraint_model
|
136
|
-
return success
|
137
|
-
end
|
138
|
-
|
139
|
-
return false
|
132
|
+
TransformConstraints.save(model, ...)
|
140
133
|
end
|
141
134
|
|
142
135
|
# Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
|
@@ -151,13 +144,7 @@ module Iry
|
|
151
144
|
# @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
|
152
145
|
# raised, but not a constraint violation
|
153
146
|
def self.save!(model, ...)
|
154
|
-
|
155
|
-
|
156
|
-
if constraint_model
|
157
|
-
return true
|
158
|
-
end
|
159
|
-
|
160
|
-
raise ConstraintViolation.new(model)
|
147
|
+
TransformConstraints.save!(model, ...)
|
161
148
|
end
|
162
149
|
|
163
150
|
# Similar to {ActiveRecord::Base#destroy} but in case of constraint
|
@@ -165,12 +152,6 @@ module Iry
|
|
165
152
|
# @param model [Handlers::Model] model to destroy
|
166
153
|
# @return [Handlers::Model] the destroyed model
|
167
154
|
def self.destroy(model)
|
168
|
-
|
169
|
-
|
170
|
-
if constraint_result.nil?
|
171
|
-
return false
|
172
|
-
end
|
173
|
-
|
174
|
-
return constraint_result
|
155
|
+
TransformConstraints.destroy(model)
|
175
156
|
end
|
176
157
|
end
|
data/package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "iry",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.7.0",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "iry",
|
9
|
-
"version": "0.
|
9
|
+
"version": "0.7.0",
|
10
10
|
"license": "MIT",
|
11
11
|
"devDependencies": {
|
12
12
|
"conventional-changelog-cli": ">= 3.0.0",
|
data/package.json
CHANGED
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_ —
|
205
|
-
|
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).
|
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).
|
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).
|
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).
|
415
|
+
sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
|
374
416
|
def apply(model); end
|
375
417
|
|
376
418
|
sig { returns(Symbol) }
|
@@ -384,6 +426,8 @@ module Iry
|
|
384
426
|
end
|
385
427
|
|
386
428
|
class Unique
|
429
|
+
MAX_INFER_NAME_BYTE_SIZE = T.let(62, T.untyped)
|
430
|
+
|
387
431
|
# Infers the unique constraint name based on keys and table name
|
388
432
|
#
|
389
433
|
# _@param_ `keys`
|
@@ -409,8 +453,9 @@ module Iry
|
|
409
453
|
end
|
410
454
|
def initialize(keys, name:, error_key:, message: :taken); end
|
411
455
|
|
456
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
412
457
|
# _@param_ `model`
|
413
|
-
sig { params(model: Handlers::Model).
|
458
|
+
sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
|
414
459
|
def apply(model); end
|
415
460
|
|
416
461
|
sig { returns(T::Array[Symbol]) }
|
@@ -443,8 +488,9 @@ module Iry
|
|
443
488
|
sig { params(key: Symbol, name: String, message: T.any(Symbol, String)).void }
|
444
489
|
def initialize(key, name:, message: :taken); end
|
445
490
|
|
491
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
446
492
|
# _@param_ `model`
|
447
|
-
sig { params(model: Handlers::Model).
|
493
|
+
sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
|
448
494
|
def apply(model); end
|
449
495
|
|
450
496
|
sig { returns(Symbol) }
|
@@ -483,8 +529,9 @@ module Iry
|
|
483
529
|
end
|
484
530
|
def initialize(keys, name:, error_key:, message: :required); end
|
485
531
|
|
532
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
486
533
|
# _@param_ `model`
|
487
|
-
sig { params(model: Handlers::Model).
|
534
|
+
sig { params(model: Handlers::Model).returns(ActiveModel::Error) }
|
488
535
|
def apply(model); end
|
489
536
|
|
490
537
|
sig { returns(T::Array[Symbol]) }
|
@@ -500,4 +547,66 @@ module Iry
|
|
500
547
|
attr_accessor :error_key
|
501
548
|
end
|
502
549
|
end
|
550
|
+
|
551
|
+
# Implementation of {Iry} methods, helps ensuring the main module focus on
|
552
|
+
# documentation
|
553
|
+
module TransformConstraints
|
554
|
+
extend Iry::TransformConstraints
|
555
|
+
|
556
|
+
# _@param_ `model`
|
557
|
+
sig { params(model: Handlers::Model, block: T.untyped).void }
|
558
|
+
def handle_constraints(model, &block); end
|
559
|
+
|
560
|
+
# _@param_ `model`
|
561
|
+
sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
|
562
|
+
def handle_constraints!(model, &block); end
|
563
|
+
|
564
|
+
# Tracks constraints of models saved as a consequence of saving another
|
565
|
+
# model. This usually represents a situation of model using
|
566
|
+
# `accepts_nested_attributes_for`
|
567
|
+
#
|
568
|
+
# _@param_ `model`
|
569
|
+
sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
|
570
|
+
def nested_constraints!(model, &block); end
|
571
|
+
|
572
|
+
# _@param_ `model`
|
573
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
574
|
+
def save(model); end
|
575
|
+
|
576
|
+
# _@param_ `model`
|
577
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
578
|
+
def save!(model); end
|
579
|
+
|
580
|
+
# _@param_ `model`
|
581
|
+
sig { params(model: Handlers::Model).returns(Handlers::Model) }
|
582
|
+
def destroy(model); end
|
583
|
+
|
584
|
+
# _@param_ `model`
|
585
|
+
sig { params(model: Handlers::Model, block: T.untyped).void }
|
586
|
+
def self.handle_constraints(model, &block); end
|
587
|
+
|
588
|
+
# _@param_ `model`
|
589
|
+
sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
|
590
|
+
def self.handle_constraints!(model, &block); end
|
591
|
+
|
592
|
+
# Tracks constraints of models saved as a consequence of saving another
|
593
|
+
# model. This usually represents a situation of model using
|
594
|
+
# `accepts_nested_attributes_for`
|
595
|
+
#
|
596
|
+
# _@param_ `model`
|
597
|
+
sig { params(model: Handlers::Model, block: T.untyped).returns(Handlers::Model) }
|
598
|
+
def self.nested_constraints!(model, &block); end
|
599
|
+
|
600
|
+
# _@param_ `model`
|
601
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
602
|
+
def self.save(model); end
|
603
|
+
|
604
|
+
# _@param_ `model`
|
605
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
606
|
+
def self.save!(model); end
|
607
|
+
|
608
|
+
# _@param_ `model`
|
609
|
+
sig { params(model: Handlers::Model).returns(Handlers::Model) }
|
610
|
+
def self.destroy(model); end
|
611
|
+
end
|
503
612
|
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_ —
|
186
|
-
|
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) ->
|
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) ->
|
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) ->
|
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) ->
|
363
|
+
def apply: (Handlers::Model model) -> ActiveModel::Error
|
327
364
|
|
328
365
|
attr_accessor key: Symbol
|
329
366
|
|
@@ -333,6 +370,8 @@ module Iry
|
|
333
370
|
end
|
334
371
|
|
335
372
|
class Unique
|
373
|
+
MAX_INFER_NAME_BYTE_SIZE: untyped
|
374
|
+
|
336
375
|
# Infers the unique constraint name based on keys and table name
|
337
376
|
#
|
338
377
|
# _@param_ `keys`
|
@@ -354,8 +393,9 @@ module Iry
|
|
354
393
|
?message: (Symbol | String)
|
355
394
|
) -> void
|
356
395
|
|
396
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
357
397
|
# _@param_ `model`
|
358
|
-
def apply: (Handlers::Model model) ->
|
398
|
+
def apply: (Handlers::Model model) -> ActiveModel::Error
|
359
399
|
|
360
400
|
attr_accessor keys: ::Array[Symbol]
|
361
401
|
|
@@ -381,8 +421,9 @@ module Iry
|
|
381
421
|
# _@param_ `name` — constraint name
|
382
422
|
def initialize: (Symbol key, name: String, ?message: (Symbol | String)) -> void
|
383
423
|
|
424
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
384
425
|
# _@param_ `model`
|
385
|
-
def apply: (Handlers::Model model) ->
|
426
|
+
def apply: (Handlers::Model model) -> ActiveModel::Error
|
386
427
|
|
387
428
|
attr_accessor key: Symbol
|
388
429
|
|
@@ -413,8 +454,9 @@ module Iry
|
|
413
454
|
?message: (Symbol | String)
|
414
455
|
) -> void
|
415
456
|
|
457
|
+
# sord warn - ActiveModel::Error wasn't able to be resolved to a constant in this project
|
416
458
|
# _@param_ `model`
|
417
|
-
def apply: (Handlers::Model model) ->
|
459
|
+
def apply: (Handlers::Model model) -> ActiveModel::Error
|
418
460
|
|
419
461
|
attr_accessor keys: ::Array[Symbol]
|
420
462
|
|
@@ -425,4 +467,54 @@ module Iry
|
|
425
467
|
attr_accessor error_key: Symbol
|
426
468
|
end
|
427
469
|
end
|
470
|
+
|
471
|
+
# Implementation of {Iry} methods, helps ensuring the main module focus on
|
472
|
+
# documentation
|
473
|
+
module TransformConstraints
|
474
|
+
extend Iry::TransformConstraints
|
475
|
+
|
476
|
+
# _@param_ `model`
|
477
|
+
def handle_constraints: (Handlers::Model model) -> void
|
478
|
+
|
479
|
+
# _@param_ `model`
|
480
|
+
def handle_constraints!: (Handlers::Model model) -> Handlers::Model
|
481
|
+
|
482
|
+
# Tracks constraints of models saved as a consequence of saving another
|
483
|
+
# model. This usually represents a situation of model using
|
484
|
+
# `accepts_nested_attributes_for`
|
485
|
+
#
|
486
|
+
# _@param_ `model`
|
487
|
+
def nested_constraints!: (Handlers::Model model) -> Handlers::Model
|
488
|
+
|
489
|
+
# _@param_ `model`
|
490
|
+
def save: (Handlers::Model model) -> bool
|
491
|
+
|
492
|
+
# _@param_ `model`
|
493
|
+
def save!: (Handlers::Model model) -> bool
|
494
|
+
|
495
|
+
# _@param_ `model`
|
496
|
+
def destroy: (Handlers::Model model) -> Handlers::Model
|
497
|
+
|
498
|
+
# _@param_ `model`
|
499
|
+
def self.handle_constraints: (Handlers::Model model) -> void
|
500
|
+
|
501
|
+
# _@param_ `model`
|
502
|
+
def self.handle_constraints!: (Handlers::Model model) -> Handlers::Model
|
503
|
+
|
504
|
+
# Tracks constraints of models saved as a consequence of saving another
|
505
|
+
# model. This usually represents a situation of model using
|
506
|
+
# `accepts_nested_attributes_for`
|
507
|
+
#
|
508
|
+
# _@param_ `model`
|
509
|
+
def self.nested_constraints!: (Handlers::Model model) -> Handlers::Model
|
510
|
+
|
511
|
+
# _@param_ `model`
|
512
|
+
def self.save: (Handlers::Model model) -> bool
|
513
|
+
|
514
|
+
# _@param_ `model`
|
515
|
+
def self.save!: (Handlers::Model model) -> bool
|
516
|
+
|
517
|
+
# _@param_ `model`
|
518
|
+
def self.destroy: (Handlers::Model model) -> Handlers::Model
|
519
|
+
end
|
428
520
|
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.
|
4
|
+
version: 0.7.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
|
+
date: 2023-07-14 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
|