iry 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/sig/iry.rbs ADDED
@@ -0,0 +1,340 @@
1
+ # Entrypoint of constraint validation, include in a class inheriting {ActiveRecord::Base} and the following class-level
2
+ # methods will be available:
3
+ # - {Macros#constraints}
4
+ # - {Macros#check_constraint}
5
+ # - {Macros#exclusion_constraint}
6
+ # - {Macros#foreign_key_constraint}
7
+ # - {Macros#unique_constraint}
8
+ #
9
+ # @example User unique constraint validation
10
+ # # The database schema has a unique constraint on email field
11
+ # class User < ActiveRecord::Base
12
+ # include Iry
13
+ #
14
+ # unique_constraint :email
15
+ # end
16
+ #
17
+ # user = User.create!(email: "user@example.com")
18
+ # fail_user = User.create(email: "user@example.com")
19
+ # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
20
+ module Iry
21
+ VERSION: String
22
+
23
+ # _@param_ `klass`
24
+ def self.included: (Module klass) -> void
25
+
26
+ # Class-level methods available to classes executing `include Iry`
27
+ module Macros
28
+ # Constraints by name
29
+ def constraints: () -> ::Hash[String, Constraint]
30
+
31
+ # Tracks check constraint for the given key and convert constraint errors into validation errors
32
+ #
33
+ # _@param_ `key` — key to apply validation errors to
34
+ #
35
+ # _@param_ `message` — the validation error message
36
+ #
37
+ # _@param_ `name` — constraint name. If omitted, it will be inferred using table name + key
38
+ def check_constraint: (Symbol key, ?name: String?, ?message: (Symbol | String)) -> void
39
+
40
+ # Tracks exclusion constraint for the given key and convert constraint errors into validation errors
41
+ #
42
+ # _@param_ `key` — key to apply validation errors to
43
+ #
44
+ # _@param_ `message` — the validation error message
45
+ #
46
+ # _@param_ `name` — constraint name. If omitted, it will be inferred using table name + key
47
+ def exclusion_constraint: (Symbol key, ?name: String?, ?message: (Symbol | String)) -> void
48
+
49
+ # Tracks foreign key constraint for the given key (or keys) and convert constraint errors into validation errors
50
+ #
51
+ # _@param_ `key_or_keys` — key or array of keys to track the foreign key constraint of
52
+ #
53
+ # _@param_ `message` — the validation error message
54
+ #
55
+ # _@param_ `name` — constraint name. If omitted, it will be inferred using table name + keys
56
+ #
57
+ # _@param_ `error_key` — key to which the validation error will be applied to. If omitted, it will be applied to the first key
58
+ def foreign_key_constraint: (
59
+ (Symbol | ::Array[Symbol]) key_or_keys,
60
+ ?name: String?,
61
+ ?message: (Symbol | String),
62
+ ?error_key: Symbol?
63
+ ) -> void
64
+
65
+ # Tracks uniqueness constraint for the given key (or keys) and convert constraint errors into validation errors
66
+ #
67
+ # _@param_ `key_or_keys` — key or array of keys to track the uniqueness constraint of
68
+ #
69
+ # _@param_ `message` — the validation error message
70
+ #
71
+ # _@param_ `name` — constraint name. If omitted, it will be inferred using table name + keys
72
+ #
73
+ # _@param_ `error_key` — key to which the validation error will be applied to. If omitted, it will be applied to the first key
74
+ def unique_constraint: (
75
+ (Symbol | ::Array[Symbol]) key_or_keys,
76
+ ?name: String?,
77
+ ?message: (Symbol | String),
78
+ ?error_key: Symbol?
79
+ ) -> void
80
+ end
81
+
82
+ module Handlers
83
+ # Interface for handlers of different database types
84
+ # @abstract
85
+ module Handler
86
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
87
+ # _@param_ `err` — possible constraint error to handle
88
+ #
89
+ # _@return_ — true if this database handler is the correct one for this exception
90
+ def handle?: (ActiveRecord::StatementInvalid err) -> bool
91
+
92
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
93
+ # _@param_ `err` — possible constraint error to handle
94
+ #
95
+ # _@param_ `model`
96
+ #
97
+ # _@return_ — true if this database handler handled the constraint error
98
+ def handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
99
+ end
100
+
101
+ # Interface of the model class. This class is usually inherits from {ActiveRecord::Base}
102
+ # @abstract
103
+ module ModelClass
104
+ def table_name: () -> String
105
+
106
+ def constraints: () -> ::Hash[String, Constraint]
107
+ end
108
+
109
+ # Interface of the model that should be used to handle constraints.
110
+ # This object is an instance of {ActiveRecord::Base}
111
+ # @abstract
112
+ module Model
113
+ # sord warn - ActiveModel::Errors wasn't able to be resolved to a constant in this project
114
+ def errors: () -> ActiveModel::Errors
115
+
116
+ def class: () -> ModelClass
117
+ end
118
+
119
+ # PostgreSQL handler through `pg` gem
120
+ # @private
121
+ module PG
122
+ extend Iry::Handlers::PG
123
+ REGEX: Regexp
124
+
125
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
126
+ # When true, the handler is able to handle this exception, representing a constraint error in PostgreSQL.
127
+ # This method must ensure not to raise exception in case the postgresql adapter is missing and as such, the
128
+ # postgres constant is undefined
129
+ #
130
+ # _@param_ `err`
131
+ def handle?: (ActiveRecord::StatementInvalid err) -> bool
132
+
133
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
134
+ # Appends constraint errors as model errors
135
+ #
136
+ # _@param_ `err`
137
+ #
138
+ # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
139
+ def handle: (ActiveRecord::StatementInvalid err, Model model) -> void
140
+
141
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
142
+ # When true, the handler is able to handle this exception, representing a constraint error in PostgreSQL.
143
+ # This method must ensure not to raise exception in case the postgresql adapter is missing and as such, the
144
+ # postgres constant is undefined
145
+ #
146
+ # _@param_ `err`
147
+ def self.handle?: (ActiveRecord::StatementInvalid err) -> bool
148
+
149
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
150
+ # Appends constraint errors as model errors
151
+ #
152
+ # _@param_ `err`
153
+ #
154
+ # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
155
+ def self.handle: (ActiveRecord::StatementInvalid err, Model model) -> void
156
+ end
157
+
158
+ # Catch-all handler for unrecognized database adapters
159
+ # @private
160
+ module Null
161
+ extend Iry::Handlers::Null
162
+
163
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
164
+ # Returns always true, catching any unhandled database exception
165
+ #
166
+ # _@param_ `err`
167
+ def handle?: ((StandardError | ActiveRecord::StatementInvalid) err) -> bool
168
+
169
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
170
+ # Return always false, failing to handle any constraint
171
+ #
172
+ # _@param_ `err`
173
+ #
174
+ # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
175
+ def handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
176
+
177
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
178
+ # Returns always true, catching any unhandled database exception
179
+ #
180
+ # _@param_ `err`
181
+ def self.handle?: ((StandardError | ActiveRecord::StatementInvalid) err) -> bool
182
+
183
+ # sord warn - ActiveRecord::StatementInvalid wasn't able to be resolved to a constant in this project
184
+ # Return always false, failing to handle any constraint
185
+ #
186
+ # _@param_ `err`
187
+ #
188
+ # _@param_ `model` — should inherit {ActiveRecord::Base} and`include Iry` to match the interface
189
+ def self.handle: (ActiveRecord::StatementInvalid err, Model model) -> bool
190
+ end
191
+ end
192
+
193
+ # Main function to kick-off **Iry** constraint-checking mechanism
194
+ # If interested in adding support for other databases beside Postgres, modify this file.
195
+ # @private
196
+ module Callbacks
197
+ extend Iry::Callbacks
198
+
199
+ # _@param_ `model`
200
+ def around_save: (Handlers::Model model) -> void
201
+
202
+ # _@param_ `model`
203
+ def self.around_save: (Handlers::Model model) -> void
204
+ end
205
+
206
+ # Interface representing a constraint.
207
+ # A constraint has a name and can apply errors to an object inheriting from {ActiveRecord::Base}
208
+ # @abstract
209
+ module Constraint
210
+ # Sets validation errors on the model
211
+ #
212
+ # _@param_ `model`
213
+ def apply: (Handlers::Model model) -> void
214
+
215
+ # Name of the constraint to be caught from the database
216
+ def name: () -> String
217
+
218
+ # Message to be attached as validation error to the model
219
+ # (see Handlers::Model)
220
+ def message: () -> (Symbol | String)
221
+
222
+ class Check
223
+ # Infers the check constraint name based on key and table name
224
+ #
225
+ # _@param_ `key`
226
+ #
227
+ # _@param_ `table_name`
228
+ def self.infer_name: (Symbol key, String table_name) -> String
229
+
230
+ # _@param_ `key` — key to apply error message for check constraint to
231
+ #
232
+ # _@param_ `message` — the validation error message
233
+ #
234
+ # _@param_ `name` — constraint name
235
+ def initialize: (Symbol key, name: String, ?message: (Symbol | String)) -> void
236
+
237
+ # _@param_ `model`
238
+ def apply: (Handlers::Model model) -> void
239
+
240
+ attr_accessor key: Symbol
241
+
242
+ attr_accessor message: (Symbol | String)
243
+
244
+ attr_accessor name: String
245
+ end
246
+
247
+ class Unique
248
+ # Infers the unique constraint name based on keys and table name
249
+ #
250
+ # _@param_ `keys`
251
+ #
252
+ # _@param_ `table_name`
253
+ def self.infer_name: (::Array[Symbol] keys, String table_name) -> String
254
+
255
+ # _@param_ `keys` — array of keys to track the uniqueness constraint of
256
+ #
257
+ # _@param_ `message` — the validation error message
258
+ #
259
+ # _@param_ `name` — constraint name
260
+ #
261
+ # _@param_ `error_key` — key to which the validation error will be applied to
262
+ def initialize: (
263
+ ::Array[Symbol] keys,
264
+ name: String,
265
+ error_key: Symbol,
266
+ ?message: (Symbol | String)
267
+ ) -> void
268
+
269
+ # _@param_ `model`
270
+ def apply: (Handlers::Model model) -> void
271
+
272
+ attr_accessor keys: ::Array[Symbol]
273
+
274
+ attr_accessor message: (Symbol | String)
275
+
276
+ attr_accessor name: String
277
+
278
+ attr_accessor error_key: Symbol
279
+ end
280
+
281
+ class Exclusion
282
+ # Infers the exclusion constraint name based on key and table name
283
+ #
284
+ # _@param_ `key`
285
+ #
286
+ # _@param_ `table_name`
287
+ def self.infer_name: (Symbol key, String table_name) -> String
288
+
289
+ # _@param_ `key` — key to apply error message for exclusion constraint to
290
+ #
291
+ # _@param_ `message` — the validation error message
292
+ #
293
+ # _@param_ `name` — constraint name
294
+ def initialize: (Symbol key, name: String, ?message: (Symbol | String)) -> void
295
+
296
+ # _@param_ `model`
297
+ def apply: (Handlers::Model model) -> void
298
+
299
+ attr_accessor key: Symbol
300
+
301
+ attr_accessor message: (Symbol | String)
302
+
303
+ attr_accessor name: String
304
+ end
305
+
306
+ class ForeignKey
307
+ # Infers the unique constraint name based on keys and table name
308
+ #
309
+ # _@param_ `keys`
310
+ #
311
+ # _@param_ `table_name`
312
+ def self.infer_name: (::Array[Symbol] keys, String table_name) -> String
313
+
314
+ # _@param_ `keys` — array of keys to track the uniqueness constraint of
315
+ #
316
+ # _@param_ `message` — the validation error message
317
+ #
318
+ # _@param_ `name` — constraint name
319
+ #
320
+ # _@param_ `error_key` — key to which the validation error will be applied to
321
+ def initialize: (
322
+ ::Array[Symbol] keys,
323
+ name: String,
324
+ error_key: Symbol,
325
+ ?message: (Symbol | String)
326
+ ) -> void
327
+
328
+ # _@param_ `model`
329
+ def apply: (Handlers::Model model) -> void
330
+
331
+ attr_accessor keys: ::Array[Symbol]
332
+
333
+ attr_accessor message: (Symbol | String)
334
+
335
+ attr_accessor name: String
336
+
337
+ attr_accessor error_key: Symbol
338
+ end
339
+ end
340
+ end
data/sorbet/config ADDED
@@ -0,0 +1,10 @@
1
+ --dir
2
+ .
3
+ --ignore=tmp/
4
+ --ignore=vendor/
5
+ --ignore=bin/
6
+ --ignore=binstubs/
7
+ --ignore=doc/
8
+ --ignore=Rakefile
9
+ --ignore=Gemfile
10
+ --ignore=iry.gemspec
@@ -0,0 +1,64 @@
1
+ gem:
2
+ all: false
3
+ exclude:
4
+ # annotated
5
+ # - activemodel
6
+ # annotated
7
+ # - activerecord
8
+ # annotated
9
+ # - activesupport
10
+ - ast
11
+ - byebug
12
+ - coderay
13
+ - commander
14
+ # - concurrent-ruby
15
+ # - csv
16
+ - diff-lcs
17
+ - erubi
18
+ # - fileutils
19
+ - ffi
20
+ - highline
21
+ - i18n
22
+ - language_server-protocol
23
+ - listen
24
+ - method_source
25
+ # - minitest-power_assert
26
+ # - minitest
27
+ - netrc
28
+ - parallel
29
+ - parlour
30
+ - parser
31
+ # - pg
32
+ # - power_assert
33
+ - prettier_print
34
+ - pry-byebug
35
+ - pry
36
+ - racc
37
+ - rainbow
38
+ - rake
39
+ - rbi
40
+ - rbs
41
+ - rb-fsevent
42
+ - rb-inotify
43
+ - sord
44
+ - spoom
45
+ - steep
46
+ - strscan
47
+ - syntax_tree
48
+ - tapioca
49
+ - terminal-table
50
+ - thor
51
+ - tzinfo
52
+ - unicode-display_width
53
+ - unparser
54
+ - webrick
55
+ - yard-sorbet
56
+ - yard
57
+ doc: true
58
+ workers: 8
59
+ dsl:
60
+ # Add your `dsl` command parameters here:
61
+ #
62
+ # exclude:
63
+ # - SomeGeneratorName
64
+ # workers: 5
@@ -0,0 +1,5 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "active_record"
5
+ require "securerandom"
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Francesco Belladonna
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-power_assert
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '13'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '13'
83
+ description: Transform database constraint errors into activerecord validation errors
84
+ email:
85
+ - francesco@fc5.me
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".envrc.example"
91
+ - ".yardopts"
92
+ - CHANGELOG.md
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - Steepfile
97
+ - VERSION
98
+ - db/schema.pgsql
99
+ - lib/iry.rb
100
+ - lib/iry/callbacks.rb
101
+ - lib/iry/constraint.rb
102
+ - lib/iry/constraint/check.rb
103
+ - lib/iry/constraint/exclusion.rb
104
+ - lib/iry/constraint/foreign_key.rb
105
+ - lib/iry/constraint/unique.rb
106
+ - lib/iry/handlers.rb
107
+ - lib/iry/handlers/null.rb
108
+ - lib/iry/handlers/pg.rb
109
+ - lib/iry/macros.rb
110
+ - lib/iry/version.rb
111
+ - rbi/iry.rbi
112
+ - sig/iry.rbs
113
+ - sorbet/config
114
+ - sorbet/tapioca/config.yml
115
+ - sorbet/tapioca/require.rb
116
+ homepage: https://github.com/Fire-Dragon-DoL/iry
117
+ licenses: []
118
+ metadata:
119
+ allowed_push_host: https://rubygems.org/
120
+ homepage_uri: https://github.com/Fire-Dragon-DoL/iry
121
+ source_code_uri: https://github.com/Fire-Dragon-DoL/iry
122
+ changelog_uri: https://github.com/Fire-Dragon-DoL/iry/blob/main/CHANGELOG.md
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.7.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.4.15
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Transform database constraint errors into activerecord validation errors
142
+ test_files: []