iry 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -10
- data/README.md +40 -10
- data/VERSION +1 -1
- data/db/schema.pgsql +1 -0
- data/lib/iry/callbacks.rb +5 -1
- data/lib/iry/macros.rb +3 -5
- data/lib/iry.rb +102 -4
- data/package-lock.json +2 -2
- data/package.json +3 -2
- data/rbi/iry.rbi +64 -1
- data/sig/iry.rbs +60 -1
- metadata +2 -2
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/CHANGELOG.md
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# [0.1.0](https://github.com/Fire-Dragon-DoL/iry/compare/8a133c2c19b99881619a9e1c7c11076030755f66...v0.1.0) (2023-07-07)
|
1
|
+
# [0.2.0](https://github.com/Fire-Dragon-DoL/iry/compare/8a133c2c19b99881619a9e1c7c11076030755f66...v0.2.0) (2023-07-08)
|
6
2
|
|
7
3
|
|
8
4
|
### Features
|
9
5
|
|
10
|
-
* **constraints:** check constraint is present ([
|
11
|
-
* **constraints:** exclusion constraint is present ([
|
12
|
-
* **constraints:** foreign key constraint is present ([
|
13
|
-
* **deps:** dependency surface is reduced ([
|
6
|
+
* **constraints:** check constraint is present ([d0cc380](https://github.com/Fire-Dragon-DoL/iry/commit/d0cc3803fdcda45df964f6431890f8831d3641e5))
|
7
|
+
* **constraints:** exclusion constraint is present ([1894e85](https://github.com/Fire-Dragon-DoL/iry/commit/1894e85bfa11e272be9b5f0f8efc170f7ce57a48))
|
8
|
+
* **constraints:** foreign key constraint is present ([e637b06](https://github.com/Fire-Dragon-DoL/iry/commit/e637b0603bb6fd34e2732426544fc31904bb5409))
|
9
|
+
* **deps:** dependency surface is reduced ([2dfc595](https://github.com/Fire-Dragon-DoL/iry/commit/2dfc595ebd221aedb072398e1ace8460208d06ac))
|
14
10
|
* **project:** setup ([8a133c2](https://github.com/Fire-Dragon-DoL/iry/commit/8a133c2c19b99881619a9e1c7c11076030755f66))
|
15
|
-
* **ruby:** version is forced to >= 2.7 ([
|
11
|
+
* **ruby:** version is forced to >= 2.7 ([9b20ed8](https://github.com/Fire-Dragon-DoL/iry/commit/9b20ed8ec0ae2a9906bdefe28cf674d4700f4d67))
|
16
12
|
* **unique-constraint:** test is implemented ([c4266b9](https://github.com/Fire-Dragon-DoL/iry/commit/c4266b910757b6adef18db41dfa5dfd9353c1037))
|
13
|
+
|
14
|
+
|
15
|
+
|
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/callbacks.rb
CHANGED
@@ -19,7 +19,11 @@ module Iry
|
|
19
19
|
|
20
20
|
is_handled = handler.handle(err, model)
|
21
21
|
|
22
|
-
if
|
22
|
+
if is_handled
|
23
|
+
# Rolling back allows to keep using SQL in other callbacks, which
|
24
|
+
# otherwise would raise PG::InFailedSqlTransaction
|
25
|
+
raise ActiveRecord::Rollback
|
26
|
+
else
|
23
27
|
raise
|
24
28
|
end
|
25
29
|
end
|
data/lib/iry/macros.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
module Iry
|
2
2
|
# Class-level methods available to classes executing `include Iry`
|
3
3
|
module Macros
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
@constraints ||= {}
|
8
|
-
end
|
4
|
+
# @!method constraints
|
5
|
+
# Constraints by name
|
6
|
+
# @return [{String => Constraint}]
|
9
7
|
|
10
8
|
# Tracks check constraint for the given key and convert constraint errors into validation errors
|
11
9
|
# @param key [Symbol] key to apply validation errors to
|
data/lib/iry.rb
CHANGED
@@ -29,18 +29,116 @@ 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
|
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
|
42
|
+
# model errors
|
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]
|
50
|
+
end
|
51
|
+
|
35
52
|
# @param klass [Module]
|
36
53
|
# @return [void]
|
37
54
|
# @private
|
38
55
|
def self.included(klass)
|
39
56
|
klass.class_eval do
|
57
|
+
# From activesupport
|
58
|
+
class_attribute(:constraints)
|
59
|
+
self.constraints = {}
|
40
60
|
extend(Iry::Macros)
|
41
|
-
# Prepend ensures around save happens before all around_save callbacks
|
42
|
-
# adding the errors as soon as possible
|
43
|
-
around_save(Iry::Callbacks, prepend: true)
|
44
61
|
end
|
45
62
|
end
|
63
|
+
|
64
|
+
# Executes block and in case of constraints violations on `model`, block is
|
65
|
+
# halted and errors are appended to `model`
|
66
|
+
# @param model [Handlers::Model] model object for which constraints should be
|
67
|
+
# monitored and for which errors should be added to
|
68
|
+
# @yield block must perform the save operation, usually with `save`
|
69
|
+
# @return [nil, Handlers::Model] the `model` or `nil` if a a constraint is
|
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}]
|
84
|
+
def self.handle_constraints(model, &block)
|
85
|
+
raise ArgumentError, "Block required" if block.nil?
|
86
|
+
|
87
|
+
block.()
|
88
|
+
|
89
|
+
return model
|
90
|
+
rescue ActiveRecord::StatementInvalid => err
|
91
|
+
handler = Handlers::Null
|
92
|
+
case
|
93
|
+
when Handlers::PG.handle?(err)
|
94
|
+
handler = Handlers::PG
|
95
|
+
end
|
96
|
+
|
97
|
+
is_handled = handler.handle(err, model)
|
98
|
+
|
99
|
+
# This constraint is not handled by Iry and should raise normally
|
100
|
+
if !is_handled
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
|
104
|
+
return nil
|
105
|
+
end
|
106
|
+
|
107
|
+
# Similar to {ActiveRecord::Base#save} but in case of constraint violations,
|
108
|
+
# `false` is returned and `errors` are populated.
|
109
|
+
# Aside from `model`, it takes the same arguments as
|
110
|
+
# {ActiveRecord::Base#save}
|
111
|
+
# @param model [Handlers::Model] model to save
|
112
|
+
# @return [Boolean] `true` if successful
|
113
|
+
def self.save(model, ...)
|
114
|
+
success = nil
|
115
|
+
constraint_model = handle_constraints(model) { success = model.save(...) }
|
116
|
+
|
117
|
+
if constraint_model
|
118
|
+
return success
|
119
|
+
end
|
120
|
+
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
|
124
|
+
# Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
|
125
|
+
# it raises {ConstraintViolation} and `errors` are populated.
|
126
|
+
# Aside from `model`, it takes the same arguments as
|
127
|
+
# {ActiveRecord::Base#save!}
|
128
|
+
# @param model [Handlers::Model] model to save
|
129
|
+
# @return [true]
|
130
|
+
# @raise [ConstraintViolation] {ConstraintViolation} inherits from
|
131
|
+
# {ActiveRecord::RecordInvalid} but it's triggered only when a constraint
|
132
|
+
# violation happens
|
133
|
+
# @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
|
134
|
+
# raised, but not a constraint violation
|
135
|
+
def self.save!(model, ...)
|
136
|
+
constraint_model = handle_constraints(model) { model.save!(...) }
|
137
|
+
|
138
|
+
if constraint_model
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
|
142
|
+
raise ConstraintViolation.new(model)
|
143
|
+
end
|
46
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
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "iry",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"description": "Transform database constraint errors into activerecord validation errors",
|
5
5
|
"private": true,
|
6
6
|
"main": "index.js",
|
@@ -10,7 +10,8 @@
|
|
10
10
|
"test": "test"
|
11
11
|
},
|
12
12
|
"scripts": {
|
13
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
14
|
+
"version-get": "echo \"$npm_package_version\""
|
14
15
|
},
|
15
16
|
"repository": {
|
16
17
|
"type": "git",
|
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
|
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.4.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-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|