iry 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cabc0965e3b746552dee09d6fcf0356bb0f166114e3cb9d696c00c033742016
4
- data.tar.gz: 0171d5388f8a7ee89d942e1ea959e2e309f3ef15fc869dba804dba8e6de0877f
3
+ metadata.gz: 8c37af75076323e55b59756a3929843bbbca04cd0bc43bc49ae89ef68e9d1665
4
+ data.tar.gz: 2b4ca6aef3667fc9f6215d1d828d732dac0c8930044e88f8234cf690b5b7a514
5
5
  SHA512:
6
- metadata.gz: ef0954dca71dbdeacd8588256939faa6a18b16ff85d1b913980c23e5058c54ceaf946959de3bbb0b9f421b5b5b3f57dea5d4d001295d6e2ad17fbfeda688771d
7
- data.tar.gz: cd3117ad1717f98fbe96d823920a25742aca1a3f10948f60ae47f9567a31c7e55633d7b2dc3ee8d151cb60e7416bd9cdb840211e8e81cd44d63ced15b199bdc1
6
+ metadata.gz: 8a9d1bb387cfc7d5809235378f80f84d8961a53cba63c9dddc6f8538352412cb02ab59d87e8fea16d5ac6c87ce1a243541ea421f4a1f14ce568331c8d1c77d70
7
+ data.tar.gz: 0fe39194ef0b3f17719f9d66a6a7881eafd8cb02e3ef50cd42c154a18875ebc726e31155a570d3fc0687547bf01b158bf7267adb4c19ac3422b9fe5aa86e1394
data/.yardopts CHANGED
@@ -1 +1 @@
1
- --no-private 'lib/**/*.rb' - 'README.md' 'CHANGELOG.md' VERSION LICENSE '.envrc.example' Gemfile 'Gemfile.lock' 'db/schema.pgsql' 'iry.gemspec'
1
+ --no-private 'lib/**/*.rb' - 'README.md' VERSION LICENSE '.envrc.example' Gemfile 'Gemfile.lock' 'db/schema.pgsql' 'iry.gemspec'
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/frames
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
- The following constraint can be used on the `User` class:
26
+ Set the following constraint on the `User` class:
28
27
 
29
28
  ```ruby
30
29
  class User < ActiveRecord::Base
@@ -36,14 +35,22 @@ 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
+ - [`destroy`](#destroy)
43
+
39
44
  When saving a new `User` record or updating it, in case constraint exceptions are raised, these will be rescued and
40
45
  validation errors will be applied to the record, like in the following example:
41
46
 
42
47
  ```ruby
43
48
  user = User.create!(unique_text: "some unique text")
49
+ fail_user = User.new(unique_text: "some unique text")
44
50
 
45
- fail_user = User.create(unique_text: "some unique text")
51
+ success = Iry.save(fail_user)
46
52
 
53
+ success #=> false
47
54
  fail_user.errors.details.fetch(:unique_text) #=> [{error: :taken}]
48
55
  ```
49
56
 
@@ -62,7 +69,7 @@ The class method `.constraints` is also available, that returns all the constrai
62
69
 
63
70
  ### [`check_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:check_constraint)
64
71
 
65
- ```rbs
72
+ ```ruby
66
73
  check_constraint(key, name: nil, message: :invalid) ⇒ void
67
74
  ```
68
75
 
@@ -74,7 +81,7 @@ Catches a specific check constraint violation.
74
81
 
75
82
  ### [`exclusion_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:exclusion_constraint)
76
83
 
77
- ```rbs
84
+ ```ruby
78
85
  exclusion_constraint(key, name: nil, message: :taken) ⇒ void
79
86
  ```
80
87
 
@@ -86,7 +93,7 @@ Catches a specific exclusion constraint violation.
86
93
 
87
94
  ### [`foreign_key_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:foreign_key_constraint)
88
95
 
89
- ```rbs
96
+ ```ruby
90
97
  foreign_key_constraint(key_or_keys, name: nil, message: :required, error_key: nil) ⇒ void
91
98
  ```
92
99
 
@@ -99,7 +106,7 @@ Catches a specific foreign key constraint violation.
99
106
 
100
107
  ### [`unique_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:unique_constraint)
101
108
 
102
- ```rbs
109
+ ```ruby
103
110
  unique_constraint(key_or_keys, name: nil, message: :taken, error_key: nil) ⇒ void
104
111
  ```
105
112
 
@@ -110,12 +117,42 @@ Catches a specific foreign key constraint violation.
110
117
  - **message** (optional `String` or `Symbol`) error message, defaults to `:taken`
111
118
  - **error_key** (optional `Symbol`) which key will have validation errors added to
112
119
 
120
+ ## Advanced Usage
121
+
122
+ ### [`handle_constraints!`](https://rubydoc.info/gems/iry/Iry.handle_constraints)
123
+
124
+ ```ruby
125
+ .handle_constraints(model) { ... } ⇒ nil, Handlers::Model
126
+ ```
127
+
128
+ Serving as base for `save` and `save!`, it will detects constraint violations, halt the execution of the block, convert
129
+ violations to validation errors and return `nil` when violations are detected, otherwise the model object provided as
130
+ argument.
131
+
132
+ ### [`save`](https://rubydoc.info/gems/iry/Iry.save)
133
+
134
+ Acts the same as `ActiveRecord::Base#save`, accepting the same arguments and returning the same values.
135
+ In addition, it will return `false` if a constraint violation of the tracked constraints is detected and validation
136
+ errors will be added to `errors`.
137
+
138
+ ### [`save!`](https://rubydoc.info/gems/iry/Iry.save!)
139
+
140
+ Acts the same as `ActiveRecord::Base#save!`, accepting the same arguments and returning the same values.
141
+ In addition, it will raise `Iry::ConstraintViolation` when constraint violations are detected.
142
+
143
+ ### [`destroy`](https://rubydoc.info/gems/iry/Iry.destroy)
144
+
145
+ Acts the same as `ActiveRecord::Base#destroy`.
146
+ In addition, it will return `false` if a constraint violation of the tracked constraints is detected and validation
147
+ errors will be added to `errors`.
148
+
113
149
  ## Limitations
114
150
 
115
151
  - `valid?` will not check for constraints. If calling `valid?` right after a `save` operation, keep in mind `errors`
116
152
  are cleared
117
- - `create!` and `update!` will raise `ActiveRecord::RecordNotSaved` for constraints that are caught by `iry`, instead
118
- of `ActiveModel::ValidationError`
153
+ - It is recommended to avoid transactions when using `Iry`, because if a violation is detected, anything after
154
+ `Iry.save/save!/handle_constraints` will result in `ActiveRecord::StatementInvalid`, since the transaction is
155
+ aborted
119
156
  - Currently only PostgreSQL is supported with the `pg` gem, but it should be simple to add support for other databases.
120
157
 
121
158
  ## Installation
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.5.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,
@@ -13,7 +13,7 @@ module Iry
13
13
  exclusion\sconstraint|
14
14
  foreign\skey\sconstraint
15
15
  )
16
- \s"(.+)"
16
+ \s"([^"]+)"
17
17
  }x
18
18
 
19
19
  # When true, the handler is able to handle this exception, representing a constraint error in PostgreSQL.
data/lib/iry/patch.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Iry
2
+ # Overrides private API method {ActiveRecord#create_or_update} to handle
3
+ # constraints and attach errors to the including model
4
+ module Patch
5
+ # Takes attributes as named arguments
6
+ # @return [Boolean] true if successful
7
+ def create_or_update(...)
8
+ result = false
9
+ Iry.handle_constraints!(self) { result = super }
10
+ result
11
+ end
12
+ end
13
+ end
data/lib/iry.rb CHANGED
@@ -11,6 +11,7 @@ require_relative "iry/constraint/check"
11
11
  require_relative "iry/constraint/exclusion"
12
12
  require_relative "iry/constraint/foreign_key"
13
13
  require_relative "iry/constraint/unique"
14
+ require_relative "iry/patch"
14
15
 
15
16
  # Entrypoint of constraint validation, include in a class inheriting {ActiveRecord::Base} and the following class-level
16
17
  # methods will be available:
@@ -29,12 +30,28 @@ require_relative "iry/constraint/unique"
29
30
  # end
30
31
  #
31
32
  # user = User.create!(email: "user@example.com")
32
- # fail_user = User.create(email: "user@example.com")
33
+ # fail_user = User.new(email: "user@example.com")
34
+ # Iry.save(fail_user)
33
35
  # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
34
36
  module Iry
35
- # Raised when constraint errors have been violated and have been converted to
37
+ # Included in all exceptions triggered by Iry, this allows to rescue any
38
+ # gem-related exception by rescuing {Iry::Error}
39
+ module Error
40
+ end
41
+
42
+ # Raised when constraints have been violated and have been converted to
36
43
  # model errors
37
- class RecordInvalid < ActiveRecord::RecordInvalid
44
+ class ConstraintViolation < ActiveRecord::RecordInvalid
45
+ include Error
46
+
47
+ # @!method record
48
+ # Inherited from {ActiveRecord::RecordInvalid}, returns the model for
49
+ # which the constraint violations have been detected
50
+ # @return [Handlers::Model]
51
+ end
52
+
53
+ class StatementInvalid < ActiveRecord::StatementInvalid
54
+ include Error
38
55
  end
39
56
 
40
57
  # @param klass [Module]
@@ -46,6 +63,7 @@ module Iry
46
63
  class_attribute(:constraints)
47
64
  self.constraints = {}
48
65
  extend(Iry::Macros)
66
+ include(Iry::Patch)
49
67
  end
50
68
  end
51
69
 
@@ -56,7 +74,32 @@ module Iry
56
74
  # @yield block must perform the save operation, usually with `save`
57
75
  # @return [nil, Handlers::Model] the `model` or `nil` if a a constraint is
58
76
  # violated
77
+ # @example Handle constraints for unique user
78
+ # # The database schema has a unique constraint on email field
79
+ # class User < ActiveRecord::Base
80
+ # include Iry
81
+ #
82
+ # unique_constraint :email
83
+ # end
84
+ #
85
+ # user = User.create!(email: "user@example.com")
86
+ # fail_user = User.new(email: "user@example.com")
87
+ # result = Iry.handle_constraints(fail_user) { fail_user.save }
88
+ # result #=> nil
89
+ # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
59
90
  def self.handle_constraints(model, &block)
91
+ handle_constraints!(model, &block)
92
+ rescue StatementInvalid
93
+ return nil
94
+ end
95
+
96
+ # Executes block and in case of constraints violations on `model`, block is
97
+ # halted, errors are appended to `model` and {StatementInvalid} is raised
98
+ # @param model [Handlers::Model] model object for which constraints should be
99
+ # monitored and for which errors should be added to
100
+ # @yield block must perform the save operation, usually with `save`
101
+ # @return [Handlers::Model] returns `model` parameter
102
+ def self.handle_constraints!(model, &block)
60
103
  raise ArgumentError, "Block required" if block.nil?
61
104
 
62
105
  block.()
@@ -71,11 +114,12 @@ module Iry
71
114
 
72
115
  is_handled = handler.handle(err, model)
73
116
 
117
+ # This constraint is not handled by Iry and should raise normally
74
118
  if !is_handled
75
119
  raise
76
120
  end
77
121
 
78
- return nil
122
+ raise StatementInvalid.new(err.message, sql: err.sql, binds: err.binds)
79
123
  end
80
124
 
81
125
  # Similar to {ActiveRecord::Base#save} but in case of constraint violations,
@@ -96,12 +140,12 @@ module Iry
96
140
  end
97
141
 
98
142
  # Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
99
- # it raises {RecordInvalid} and `errors` are populated.
143
+ # it raises {ConstraintViolation} and `errors` are populated.
100
144
  # Aside from `model`, it takes the same arguments as
101
145
  # {ActiveRecord::Base#save!}
102
146
  # @param model [Handlers::Model] model to save
103
147
  # @return [true]
104
- # @raise [RecordInvalid] {RecordInvalid} inherits from
148
+ # @raise [ConstraintViolation] {ConstraintViolation} inherits from
105
149
  # {ActiveRecord::RecordInvalid} but it's triggered only when a constraint
106
150
  # violation happens
107
151
  # @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
@@ -113,6 +157,20 @@ module Iry
113
157
  return true
114
158
  end
115
159
 
116
- raise RecordInvalid.new(model)
160
+ raise ConstraintViolation.new(model)
161
+ end
162
+
163
+ # Similar to {ActiveRecord::Base#destroy} but in case of constraint
164
+ # violations, `false` is returned and `errors` are populated.
165
+ # @param model [Handlers::Model] model to destroy
166
+ # @return [Handlers::Model] the destroyed model
167
+ 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
117
175
  end
118
176
  end
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "iry",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "iry",
9
- "version": "0.3.0",
9
+ "version": "0.5.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.0",
3
+ "version": "0.5.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
@@ -16,15 +16,78 @@
16
16
  # end
17
17
  #
18
18
  # user = User.create!(email: "user@example.com")
19
- # fail_user = User.create(email: "user@example.com")
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.create(email: "user@example.com")
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.3.0
4
+ version: 0.5.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-09 00:00:00.000000000 Z
11
+ date: 2023-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -89,7 +89,6 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - ".envrc.example"
91
91
  - ".yardopts"
92
- - CHANGELOG.md
93
92
  - LICENSE
94
93
  - README.md
95
94
  - Rakefile
@@ -107,6 +106,7 @@ files:
107
106
  - lib/iry/handlers/null.rb
108
107
  - lib/iry/handlers/pg.rb
109
108
  - lib/iry/macros.rb
109
+ - lib/iry/patch.rb
110
110
  - lib/iry/version.rb
111
111
  - package-lock.json
112
112
  - package.json
@@ -122,7 +122,6 @@ metadata:
122
122
  allowed_push_host: https://rubygems.org/
123
123
  homepage_uri: https://github.com/Fire-Dragon-DoL/iry
124
124
  source_code_uri: https://github.com/Fire-Dragon-DoL/iry
125
- changelog_uri: https://github.com/Fire-Dragon-DoL/iry/blob/main/CHANGELOG.md
126
125
  post_install_message:
127
126
  rdoc_options: []
128
127
  require_paths:
data/CHANGELOG.md DELETED
@@ -1,15 +0,0 @@
1
- # [0.2.0](https://github.com/Fire-Dragon-DoL/iry/compare/8a133c2c19b99881619a9e1c7c11076030755f66...v0.2.0) (2023-07-08)
2
-
3
-
4
- ### Features
5
-
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))
10
- * **project:** setup ([8a133c2](https://github.com/Fire-Dragon-DoL/iry/commit/8a133c2c19b99881619a9e1c7c11076030755f66))
11
- * **ruby:** version is forced to >= 2.7 ([9b20ed8](https://github.com/Fire-Dragon-DoL/iry/commit/9b20ed8ec0ae2a9906bdefe28cf674d4700f4d67))
12
- * **unique-constraint:** test is implemented ([c4266b9](https://github.com/Fire-Dragon-DoL/iry/commit/c4266b910757b6adef18db41dfa5dfd9353c1037))
13
-
14
-
15
-