iry 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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
-