iry 0.3.0 → 0.4.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/README.md +40 -10
- data/VERSION +1 -1
- data/db/schema.pgsql +1 -0
- data/lib/iry.rb +32 -6
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/rbi/iry.rbi +64 -1
- data/sig/iry.rbs +60 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e4fc1d3dfa1e63a0ac7c38443301f2635ac7d60866d5799a1a6a78b5cdb9326
|
4
|
+
data.tar.gz: 7b4a3e8b2118dfb0788f15579e61ca35b1e32277cd571fb53e83c2905e23cc49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27cc273db8893f605a6d3480305a0e575f214a4c88562a701b0ba1b00b4a98b004735f7f776428b246722c0a26706ba2681405028f0454658085cf562e94fd7b
|
7
|
+
data.tar.gz: 01b82838cf8c8e02432fe038086fa3a96db7ff83a128e5e3ac1aacc5524e2e9a76c908f0af72e85eac19bbed6ccc0972718ba9f49e69ab5d81775fc508a946e6
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Convert constraint errors into Rails model validation errors.
|
|
6
6
|
|
7
7
|
## Documentation
|
8
8
|
|
9
|
-
https://rubydoc.info/gems/iry
|
9
|
+
https://rubydoc.info/gems/iry
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
@@ -14,7 +14,6 @@ Given the following database schema:
|
|
14
14
|
|
15
15
|
```sql
|
16
16
|
create extension if not exists "pgcrypto";
|
17
|
-
create extension if not exists "btree_gist";
|
18
17
|
|
19
18
|
create table if not exists users (
|
20
19
|
id uuid primary key default gen_random_uuid(),
|
@@ -24,7 +23,7 @@ create table if not exists users (
|
|
24
23
|
);
|
25
24
|
```
|
26
25
|
|
27
|
-
|
26
|
+
Set the following constraint on the `User` class:
|
28
27
|
|
29
28
|
```ruby
|
30
29
|
class User < ActiveRecord::Base
|
@@ -36,14 +35,21 @@ class User < ActiveRecord::Base
|
|
36
35
|
end
|
37
36
|
```
|
38
37
|
|
38
|
+
Now one of the saving mechanisms can be used:
|
39
|
+
- [`handle_constraints`](#handle_constraints)
|
40
|
+
- [`save`](#save)
|
41
|
+
- [`save!`](#save!)
|
42
|
+
|
39
43
|
When saving a new `User` record or updating it, in case constraint exceptions are raised, these will be rescued and
|
40
44
|
validation errors will be applied to the record, like in the following example:
|
41
45
|
|
42
46
|
```ruby
|
43
47
|
user = User.create!(unique_text: "some unique text")
|
48
|
+
fail_user = User.new(unique_text: "some unique text")
|
44
49
|
|
45
|
-
|
50
|
+
success = Iry.save(fail_user)
|
46
51
|
|
52
|
+
success #=> false
|
47
53
|
fail_user.errors.details.fetch(:unique_text) #=> [{error: :taken}]
|
48
54
|
```
|
49
55
|
|
@@ -62,7 +68,7 @@ The class method `.constraints` is also available, that returns all the constrai
|
|
62
68
|
|
63
69
|
### [`check_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:check_constraint)
|
64
70
|
|
65
|
-
```
|
71
|
+
```ruby
|
66
72
|
check_constraint(key, name: nil, message: :invalid) ⇒ void
|
67
73
|
```
|
68
74
|
|
@@ -74,7 +80,7 @@ Catches a specific check constraint violation.
|
|
74
80
|
|
75
81
|
### [`exclusion_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:exclusion_constraint)
|
76
82
|
|
77
|
-
```
|
83
|
+
```ruby
|
78
84
|
exclusion_constraint(key, name: nil, message: :taken) ⇒ void
|
79
85
|
```
|
80
86
|
|
@@ -86,7 +92,7 @@ Catches a specific exclusion constraint violation.
|
|
86
92
|
|
87
93
|
### [`foreign_key_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:foreign_key_constraint)
|
88
94
|
|
89
|
-
```
|
95
|
+
```ruby
|
90
96
|
foreign_key_constraint(key_or_keys, name: nil, message: :required, error_key: nil) ⇒ void
|
91
97
|
```
|
92
98
|
|
@@ -99,7 +105,7 @@ Catches a specific foreign key constraint violation.
|
|
99
105
|
|
100
106
|
### [`unique_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:unique_constraint)
|
101
107
|
|
102
|
-
```
|
108
|
+
```ruby
|
103
109
|
unique_constraint(key_or_keys, name: nil, message: :taken, error_key: nil) ⇒ void
|
104
110
|
```
|
105
111
|
|
@@ -110,12 +116,36 @@ Catches a specific foreign key constraint violation.
|
|
110
116
|
- **message** (optional `String` or `Symbol`) error message, defaults to `:taken`
|
111
117
|
- **error_key** (optional `Symbol`) which key will have validation errors added to
|
112
118
|
|
119
|
+
## Advanced Usage
|
120
|
+
|
121
|
+
### [`handle_constraints!`](https://rubydoc.info/gems/iry/Iry.handle_constraints)
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
.handle_constraints(model) { ... } ⇒ nil, Handlers::Model
|
125
|
+
```
|
126
|
+
|
127
|
+
Serving as base for `save` and `save!`, it will detects constraint violations, halt the execution of the block, convert
|
128
|
+
violations to validation errors and return `nil` when violations are detected, otherwise the model object provided as
|
129
|
+
argument.
|
130
|
+
|
131
|
+
### [`save`](https://rubydoc.info/gems/iry/Iry.save)
|
132
|
+
|
133
|
+
Acts the same as `ActiveRecord::Base#save`, accepting the same arguments and returning the same values.
|
134
|
+
In addition, it will return `false` if a constraint violation of the tracked constraints is detected and validation
|
135
|
+
errors will be added to `errors`.
|
136
|
+
|
137
|
+
### [`save!`](https://rubydoc.info/gems/iry/Iry.save!)
|
138
|
+
|
139
|
+
Acts the same as `ActiveRecord::Base#save!`, accepting the same arguments and returning the same values.
|
140
|
+
In addition, it will raise `Iry::ConstraintViolation` when constraint violations are detected.
|
141
|
+
|
113
142
|
## Limitations
|
114
143
|
|
115
144
|
- `valid?` will not check for constraints. If calling `valid?` right after a `save` operation, keep in mind `errors`
|
116
145
|
are cleared
|
117
|
-
-
|
118
|
-
|
146
|
+
- It is recommended to avoid transactions when using `Iry`, because if a violation is detected, anything after
|
147
|
+
`Iry.save/save!/handle_constraints` will result in `ActiveRecord::StatementInvalid`, since the transaction is
|
148
|
+
aborted
|
119
149
|
- Currently only PostgreSQL is supported with the `pg` gem, but it should be simple to add support for other databases.
|
120
150
|
|
121
151
|
## Installation
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/db/schema.pgsql
CHANGED
@@ -7,6 +7,7 @@ create table if not exists users (
|
|
7
7
|
exclude_text text not null default gen_random_uuid()::text,
|
8
8
|
user_id uuid references users (id),
|
9
9
|
untracked_text text unique not null default gen_random_uuid()::text,
|
10
|
+
free_text text not null default '',
|
10
11
|
friend_user_id uuid references users (id),
|
11
12
|
created_at timestamp(6) not null,
|
12
13
|
updated_at timestamp(6) not null,
|
data/lib/iry.rb
CHANGED
@@ -29,12 +29,24 @@ require_relative "iry/constraint/unique"
|
|
29
29
|
# end
|
30
30
|
#
|
31
31
|
# user = User.create!(email: "user@example.com")
|
32
|
-
# fail_user = User.
|
32
|
+
# fail_user = User.new(email: "user@example.com")
|
33
|
+
# Iry.save(fail_user)
|
33
34
|
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
34
35
|
module Iry
|
35
|
-
#
|
36
|
+
# Included in all exceptions triggered by Iry, this allows to rescue any
|
37
|
+
# gem-related exception by rescuing {Iry::Error}
|
38
|
+
module Error
|
39
|
+
end
|
40
|
+
|
41
|
+
# Raised when constraints have been violated and have been converted to
|
36
42
|
# model errors
|
37
|
-
class
|
43
|
+
class ConstraintViolation < ActiveRecord::RecordInvalid
|
44
|
+
include Error
|
45
|
+
|
46
|
+
# @!method record
|
47
|
+
# Inherited from {ActiveRecord::RecordInvalid}, returns the model for
|
48
|
+
# which the constraint violations have been detected
|
49
|
+
# @return [Handlers::Model]
|
38
50
|
end
|
39
51
|
|
40
52
|
# @param klass [Module]
|
@@ -56,6 +68,19 @@ module Iry
|
|
56
68
|
# @yield block must perform the save operation, usually with `save`
|
57
69
|
# @return [nil, Handlers::Model] the `model` or `nil` if a a constraint is
|
58
70
|
# violated
|
71
|
+
# @example Handle constraints for unique user
|
72
|
+
# # The database schema has a unique constraint on email field
|
73
|
+
# class User < ActiveRecord::Base
|
74
|
+
# include Iry
|
75
|
+
#
|
76
|
+
# unique_constraint :email
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# user = User.create!(email: "user@example.com")
|
80
|
+
# fail_user = User.new(email: "user@example.com")
|
81
|
+
# result = Iry.handle_constraints(fail_user) { fail_user.save }
|
82
|
+
# result #=> nil
|
83
|
+
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
59
84
|
def self.handle_constraints(model, &block)
|
60
85
|
raise ArgumentError, "Block required" if block.nil?
|
61
86
|
|
@@ -71,6 +96,7 @@ module Iry
|
|
71
96
|
|
72
97
|
is_handled = handler.handle(err, model)
|
73
98
|
|
99
|
+
# This constraint is not handled by Iry and should raise normally
|
74
100
|
if !is_handled
|
75
101
|
raise
|
76
102
|
end
|
@@ -96,12 +122,12 @@ module Iry
|
|
96
122
|
end
|
97
123
|
|
98
124
|
# Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
|
99
|
-
# it raises {
|
125
|
+
# it raises {ConstraintViolation} and `errors` are populated.
|
100
126
|
# Aside from `model`, it takes the same arguments as
|
101
127
|
# {ActiveRecord::Base#save!}
|
102
128
|
# @param model [Handlers::Model] model to save
|
103
129
|
# @return [true]
|
104
|
-
# @raise [
|
130
|
+
# @raise [ConstraintViolation] {ConstraintViolation} inherits from
|
105
131
|
# {ActiveRecord::RecordInvalid} but it's triggered only when a constraint
|
106
132
|
# violation happens
|
107
133
|
# @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
|
@@ -113,6 +139,6 @@ module Iry
|
|
113
139
|
return true
|
114
140
|
end
|
115
141
|
|
116
|
-
raise
|
142
|
+
raise ConstraintViolation.new(model)
|
117
143
|
end
|
118
144
|
end
|
data/package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "iry",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "iry",
|
9
|
-
"version": "0.
|
9
|
+
"version": "0.4.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
@@ -16,15 +16,78 @@
|
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# user = User.create!(email: "user@example.com")
|
19
|
-
# fail_user = User.
|
19
|
+
# fail_user = User.new(email: "user@example.com")
|
20
|
+
# Iry.save(fail_user)
|
20
21
|
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
21
22
|
module Iry
|
22
23
|
VERSION = T.let(File.read(File.expand_path("../../VERSION", __dir__)).strip.freeze, T.untyped)
|
23
24
|
|
25
|
+
# Inherited from {ActiveRecord::RecordInvalid}, returns the model for
|
26
|
+
# which the constraint violations have been detected
|
27
|
+
sig { returns(Handlers::Model) }
|
28
|
+
def record; end
|
29
|
+
|
24
30
|
# _@param_ `klass`
|
25
31
|
sig { params(klass: Module).void }
|
26
32
|
def self.included(klass); end
|
27
33
|
|
34
|
+
# Executes block and in case of constraints violations on `model`, block is
|
35
|
+
# halted and errors are appended to `model`
|
36
|
+
#
|
37
|
+
# _@param_ `model` — model object for which constraints should be monitored and for which errors should be added to
|
38
|
+
#
|
39
|
+
# _@return_ — the `model` or `nil` if a a constraint is
|
40
|
+
# violated
|
41
|
+
#
|
42
|
+
# Handle constraints for unique user
|
43
|
+
# ```ruby
|
44
|
+
# # The database schema has a unique constraint on email field
|
45
|
+
# class User < ActiveRecord::Base
|
46
|
+
# include Iry
|
47
|
+
#
|
48
|
+
# unique_constraint :email
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# user = User.create!(email: "user@example.com")
|
52
|
+
# fail_user = User.new(email: "user@example.com")
|
53
|
+
# result = Iry.handle_constraints(fail_user) { fail_user.save }
|
54
|
+
# result #=> nil
|
55
|
+
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
56
|
+
# ```
|
57
|
+
sig { params(model: Handlers::Model, block: T.untyped).void }
|
58
|
+
def self.handle_constraints(model, &block); end
|
59
|
+
|
60
|
+
# Similar to {ActiveRecord::Base#save} but in case of constraint violations,
|
61
|
+
# `false` is returned and `errors` are populated.
|
62
|
+
# Aside from `model`, it takes the same arguments as
|
63
|
+
# {ActiveRecord::Base#save}
|
64
|
+
#
|
65
|
+
# _@param_ `model` — model to save
|
66
|
+
#
|
67
|
+
# _@return_ — `true` if successful
|
68
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
69
|
+
def self.save(model); end
|
70
|
+
|
71
|
+
# Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
|
72
|
+
# it raises {ConstraintViolation} and `errors` are populated.
|
73
|
+
# Aside from `model`, it takes the same arguments as
|
74
|
+
# {ActiveRecord::Base#save!}
|
75
|
+
#
|
76
|
+
# _@param_ `model` — model to save
|
77
|
+
sig { params(model: Handlers::Model).returns(T::Boolean) }
|
78
|
+
def self.save!(model); end
|
79
|
+
|
80
|
+
# Included in all exceptions triggered by Iry, this allows to rescue any
|
81
|
+
# gem-related exception by rescuing {Iry::Error}
|
82
|
+
module Error
|
83
|
+
end
|
84
|
+
|
85
|
+
# Raised when constraints have been violated and have been converted to
|
86
|
+
# model errors
|
87
|
+
class ConstraintViolation < ActiveRecord::RecordInvalid
|
88
|
+
include Iry::Error
|
89
|
+
end
|
90
|
+
|
28
91
|
# Class-level methods available to classes executing `include Iry`
|
29
92
|
module Macros
|
30
93
|
# Constraints by name
|
data/sig/iry.rbs
CHANGED
@@ -15,14 +15,73 @@
|
|
15
15
|
# end
|
16
16
|
#
|
17
17
|
# user = User.create!(email: "user@example.com")
|
18
|
-
# fail_user = User.
|
18
|
+
# fail_user = User.new(email: "user@example.com")
|
19
|
+
# Iry.save(fail_user)
|
19
20
|
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
20
21
|
module Iry
|
21
22
|
VERSION: String
|
22
23
|
|
24
|
+
# Inherited from {ActiveRecord::RecordInvalid}, returns the model for
|
25
|
+
# which the constraint violations have been detected
|
26
|
+
def record: () -> Handlers::Model
|
27
|
+
|
23
28
|
# _@param_ `klass`
|
24
29
|
def self.included: (Module klass) -> void
|
25
30
|
|
31
|
+
# Executes block and in case of constraints violations on `model`, block is
|
32
|
+
# halted and errors are appended to `model`
|
33
|
+
#
|
34
|
+
# _@param_ `model` — model object for which constraints should be monitored and for which errors should be added to
|
35
|
+
#
|
36
|
+
# _@return_ — the `model` or `nil` if a a constraint is
|
37
|
+
# violated
|
38
|
+
#
|
39
|
+
# Handle constraints for unique user
|
40
|
+
# ```ruby
|
41
|
+
# # The database schema has a unique constraint on email field
|
42
|
+
# class User < ActiveRecord::Base
|
43
|
+
# include Iry
|
44
|
+
#
|
45
|
+
# unique_constraint :email
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# user = User.create!(email: "user@example.com")
|
49
|
+
# fail_user = User.new(email: "user@example.com")
|
50
|
+
# result = Iry.handle_constraints(fail_user) { fail_user.save }
|
51
|
+
# result #=> nil
|
52
|
+
# fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
|
53
|
+
# ```
|
54
|
+
def self.handle_constraints: (Handlers::Model model) -> void
|
55
|
+
|
56
|
+
# Similar to {ActiveRecord::Base#save} but in case of constraint violations,
|
57
|
+
# `false` is returned and `errors` are populated.
|
58
|
+
# Aside from `model`, it takes the same arguments as
|
59
|
+
# {ActiveRecord::Base#save}
|
60
|
+
#
|
61
|
+
# _@param_ `model` — model to save
|
62
|
+
#
|
63
|
+
# _@return_ — `true` if successful
|
64
|
+
def self.save: (Handlers::Model model) -> bool
|
65
|
+
|
66
|
+
# Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
|
67
|
+
# it raises {ConstraintViolation} and `errors` are populated.
|
68
|
+
# Aside from `model`, it takes the same arguments as
|
69
|
+
# {ActiveRecord::Base#save!}
|
70
|
+
#
|
71
|
+
# _@param_ `model` — model to save
|
72
|
+
def self.save!: (Handlers::Model model) -> bool
|
73
|
+
|
74
|
+
# Included in all exceptions triggered by Iry, this allows to rescue any
|
75
|
+
# gem-related exception by rescuing {Iry::Error}
|
76
|
+
module Error
|
77
|
+
end
|
78
|
+
|
79
|
+
# Raised when constraints have been violated and have been converted to
|
80
|
+
# model errors
|
81
|
+
class ConstraintViolation < ActiveRecord::RecordInvalid
|
82
|
+
include Iry::Error
|
83
|
+
end
|
84
|
+
|
26
85
|
# Class-level methods available to classes executing `include Iry`
|
27
86
|
module Macros
|
28
87
|
# Constraints by name
|