typed_params 1.1.0 → 1.2.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/CHANGELOG.md +14 -1
- data/README.md +42 -1
- data/lib/typed_params/formatters/formatter.rb +1 -1
- data/lib/typed_params/formatters/jsonapi.rb +18 -8
- data/lib/typed_params/mapper.rb +4 -4
- data/lib/typed_params/memoize.rb +2 -2
- data/lib/typed_params/parameter.rb +10 -1
- data/lib/typed_params/parameterizer.rb +3 -3
- data/lib/typed_params/schema.rb +16 -6
- data/lib/typed_params/version.rb +1 -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: 014c42e82286c1ffc175d08aca51e631da96a5b2aee8e9bbf575fc0bea7e1d57
|
4
|
+
data.tar.gz: 3a0ea8bac6b1021143b768767763899a6f5328f16bb6011a87b2f1ed694b6325
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c563758456e6359e37c75926124925141c59f535fc77070be23d46d3f86e0772f2cf2c52d2e57f165e2ba11f93717c6a0b15f90e61fcbe00baa19b3c1985f2a8
|
7
|
+
data.tar.gz: a277c1c13a5d0ac14ef293fbc9611bec82eba5df00686f9afaf8e324e89148aef7c49fa672bf025570a9482ec277e330edc1049a1e59051e41a559a31a4b6584
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.2.0
|
4
|
+
|
5
|
+
- Add `aliases:` keyword to `#param` to allow the schema to be accessible by different names.
|
6
|
+
- Add `polymorphic:` keyword to `#param` to define a polymorphic schema.
|
7
|
+
|
8
|
+
## 1.1.1
|
9
|
+
|
10
|
+
- Fix compatibility with Ruby 3.3.0 due to [#20091](https://bugs.ruby-lang.org/issues/20091).
|
11
|
+
|
12
|
+
## 1.1.0
|
13
|
+
|
14
|
+
- Add memoization to `#typed_params` and `#typed_query` methods.
|
15
|
+
|
3
16
|
## 1.0.3
|
4
17
|
|
5
18
|
- Revert 0b0aaa6b66edd3e4c3336e51fa340592e7ef9e86.
|
@@ -18,4 +31,4 @@
|
|
18
31
|
|
19
32
|
## 0.2.0
|
20
33
|
|
21
|
-
- Test release.
|
34
|
+
- Test release.
|
data/README.md
CHANGED
@@ -110,6 +110,7 @@ _We're working on improving the docs._
|
|
110
110
|
- Reuse schemas across controllers by defining named schemas.
|
111
111
|
- Run validations on params, similar to active model validations.
|
112
112
|
- Run transforms on params before they hit your controller.
|
113
|
+
- Support formatters such as JSON:API.
|
113
114
|
|
114
115
|
## Usage
|
115
116
|
|
@@ -435,6 +436,7 @@ Parameters can have validations, transforms, and more.
|
|
435
436
|
- [`:optional`](#optional-parameter)
|
436
437
|
- [`:if` and `:unless`](#conditional-parameter)
|
437
438
|
- [`:as`](#rename-parameter)
|
439
|
+
- [`:alias`](#alias-parameter)
|
438
440
|
- [`:noop`](#noop-parameter)
|
439
441
|
- [`:coerce`](#coerce-parameter)
|
440
442
|
- [`:allow_blank`](#allow-blank)
|
@@ -447,6 +449,7 @@ Parameters can have validations, transforms, and more.
|
|
447
449
|
- [`:length`](#length-validation)
|
448
450
|
- [`:transform`](#transform-parameter)
|
449
451
|
- [`:validate`](#validate-parameter)
|
452
|
+
- [`:polymorphic`](#polymorphic-parameter)
|
450
453
|
|
451
454
|
#### Parameter key
|
452
455
|
|
@@ -519,6 +522,17 @@ typed_params # => { user_id: 1 }
|
|
519
522
|
In this example, the parameter would be accepted as `:user`, but renamed
|
520
523
|
to `:user_id` for use inside of the controller.
|
521
524
|
|
525
|
+
#### Alias parameter
|
526
|
+
|
527
|
+
Allow a parameter to be provided via an alias.
|
528
|
+
|
529
|
+
```ruby
|
530
|
+
param :owner_id, type: :integer, alias: :user_id
|
531
|
+
```
|
532
|
+
|
533
|
+
In this example, the parameter would be accepted as both `:owner_id` and
|
534
|
+
`:user_id`, but accessible as `:owner_id` inside the controller.
|
535
|
+
|
522
536
|
#### Noop parameter
|
523
537
|
|
524
538
|
The parameter is accepted but immediately thrown out.
|
@@ -673,6 +687,33 @@ param :invalid, type: :string, validate: -> v {
|
|
673
687
|
}
|
674
688
|
```
|
675
689
|
|
690
|
+
#### Polymorphic parameter
|
691
|
+
|
692
|
+
***Currently, this option is only utilized by the JSONAPI formatter. Define
|
693
|
+
a polymorphic parameter, used when formatting JSONAPI relationships.***
|
694
|
+
|
695
|
+
```ruby
|
696
|
+
format :jsonapi
|
697
|
+
|
698
|
+
param :data, type: :hash do
|
699
|
+
param :relationships, type: :hash do
|
700
|
+
param :owner, type: :hash, polymorphic: true do
|
701
|
+
param :data, type: :hash do
|
702
|
+
param :type, type: :string, inclusion: { in: %w[users user] }
|
703
|
+
param :id, type: :integer
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
typed_params # => { owner_type: 'User', owner_id: 1 }
|
710
|
+
```
|
711
|
+
|
712
|
+
In this example, a polymorphic `:owner` relationship is defined. When run
|
713
|
+
through the JSONAPI formatter, instead of formatting the relationship
|
714
|
+
into the `:owner_id` key, it also includes the `:owner_type` key
|
715
|
+
for a polymorphic association.
|
716
|
+
|
676
717
|
### Shared options
|
677
718
|
|
678
719
|
You can define a set of options that will be applied to immediate
|
@@ -747,7 +788,7 @@ which may be a nested schema.
|
|
747
788
|
|
748
789
|
```ruby
|
749
790
|
# array of hashes
|
750
|
-
param :
|
791
|
+
param :endless_array, type: :array do
|
751
792
|
items type: :hash do
|
752
793
|
# ...
|
753
794
|
end
|
@@ -32,12 +32,16 @@ module TypedParams
|
|
32
32
|
# }
|
33
33
|
#
|
34
34
|
module JSONAPI
|
35
|
-
def self.call(params)
|
35
|
+
def self.call(params, schema:)
|
36
36
|
case params
|
37
37
|
in data: Array => data
|
38
|
-
|
38
|
+
child = schema.children.fetch(:data)
|
39
|
+
|
40
|
+
format_array_data(data, schema: child)
|
39
41
|
in data: Hash => data
|
40
|
-
|
42
|
+
child = schema.children.fetch(:data)
|
43
|
+
|
44
|
+
format_hash_data(data, schema: child)
|
41
45
|
else
|
42
46
|
params
|
43
47
|
end
|
@@ -45,11 +49,15 @@ module TypedParams
|
|
45
49
|
|
46
50
|
private
|
47
51
|
|
48
|
-
def self.format_array_data(data)
|
49
|
-
data.map
|
52
|
+
def self.format_array_data(data, schema:)
|
53
|
+
data.each_with_index.map do |value, i|
|
54
|
+
child = schema.children.fetch(i) { schema.endless? ? schema.children.first : nil }
|
55
|
+
|
56
|
+
format_hash_data(value, schema: child)
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
|
-
def self.format_hash_data(data)
|
60
|
+
def self.format_hash_data(data, schema:)
|
53
61
|
rels = data[:relationships]
|
54
62
|
attrs = data[:attributes]
|
55
63
|
res = data.except(
|
@@ -69,6 +77,8 @@ module TypedParams
|
|
69
77
|
# relationship data only contains :type and :id, otherwise it
|
70
78
|
# will use the x_attributes key.
|
71
79
|
rels&.each do |key, rel|
|
80
|
+
child = schema.children.dig(:relationships, key)
|
81
|
+
|
72
82
|
case rel
|
73
83
|
# FIXME(ezekg) We need https://bugs.ruby-lang.org/issues/18961 to
|
74
84
|
# clean this up (i.e. remove the if guard).
|
@@ -77,7 +87,7 @@ module TypedParams
|
|
77
87
|
in data: []
|
78
88
|
res[:"#{key.to_s.singularize}_ids"] = []
|
79
89
|
# FIXME(ezekg) Not sure how to make this cleaner, but this handles polymorphic relationships.
|
80
|
-
in data: { type:, id:, **nil } if key.to_s.underscore.classify != type.underscore.classify
|
90
|
+
in data: { type:, id:, **nil } if key.to_s.underscore.classify != type.underscore.classify && child.polymorphic?
|
81
91
|
res[:"#{key}_type"], res[:"#{key}_id"] = type.underscore.classify, id
|
82
92
|
in data: { type:, id:, **nil }
|
83
93
|
res[:"#{key}_id"] = id
|
@@ -86,7 +96,7 @@ module TypedParams
|
|
86
96
|
else
|
87
97
|
# NOTE(ezekg) Embedded relationships are non-standard as per the
|
88
98
|
# JSONAPI spec, but I don't really care. :)
|
89
|
-
res[:"#{key}_attributes"] = call(rel)
|
99
|
+
res[:"#{key}_attributes"] = call(rel, schema: child)
|
90
100
|
end
|
91
101
|
end
|
92
102
|
|
data/lib/typed_params/mapper.rb
CHANGED
@@ -47,7 +47,7 @@ module TypedParams
|
|
47
47
|
# │ 1 ││ 2 │ │ 5 │
|
48
48
|
# └───┘└───┘ └───┘
|
49
49
|
#
|
50
|
-
def depth_first_map(param, &)
|
50
|
+
def depth_first_map(param, &block)
|
51
51
|
return if param.nil?
|
52
52
|
|
53
53
|
# Postorder DFS, so we'll visit the children first.
|
@@ -55,12 +55,12 @@ module TypedParams
|
|
55
55
|
case param.schema.children
|
56
56
|
in Array if param.array?
|
57
57
|
if param.schema.indexed?
|
58
|
-
param.schema.children.each_with_index { |v, i| self.class.call(param[i], schema: v, controller:, &) }
|
58
|
+
param.schema.children.each_with_index { |v, i| self.class.call(param[i], schema: v, controller:, &block) }
|
59
59
|
else
|
60
|
-
param.value.each { |v| self.class.call(v, schema: param.schema.children.first, controller:, &) }
|
60
|
+
param.value.each { |v| self.class.call(v, schema: param.schema.children.first, controller:, &block) }
|
61
61
|
end
|
62
62
|
in Hash if param.hash?
|
63
|
-
param.schema.children.each { |k, v| self.class.call(param[k], schema: v, controller:, &) }
|
63
|
+
param.schema.children.each { |k, v| self.class.call(param[k], schema: v, controller:, &block) }
|
64
64
|
else
|
65
65
|
end
|
66
66
|
end
|
data/lib/typed_params/memoize.rb
CHANGED
@@ -34,7 +34,7 @@ module TypedParams
|
|
34
34
|
end
|
35
35
|
|
36
36
|
klass.singleton_class.send(:alias_method, :"unmemoized_#{method_name}", method_name)
|
37
|
-
klass.class_eval
|
37
|
+
klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
38
38
|
def self.#{method_name}(*args, **kwargs, &block)
|
39
39
|
key = args.hash ^ kwargs.hash ^ block.hash
|
40
40
|
|
@@ -72,7 +72,7 @@ module TypedParams
|
|
72
72
|
end
|
73
73
|
|
74
74
|
klass.alias_method :"unmemoized_#{method_name}", method_name
|
75
|
-
klass.class_eval
|
75
|
+
klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
76
76
|
def #{method_name}(*args, **kwargs, &block)
|
77
77
|
key = args.hash ^ kwargs.hash ^ block.hash
|
78
78
|
|
@@ -75,7 +75,16 @@ module TypedParams
|
|
75
75
|
if formatter.present?
|
76
76
|
v = case formatter.arity
|
77
77
|
when 2
|
78
|
-
formatter.
|
78
|
+
case formatter.parameters
|
79
|
+
in [[:req, *], [:keyreq | :key, :controller], [:keyreq | :key, :schema]]
|
80
|
+
formatter.call(v, controller:, schema:)
|
81
|
+
in [[:req, *], [:keyreq | :key, :schema], [:keyreq | :key, :controller]]
|
82
|
+
formatter.call(v, schema:, controller:)
|
83
|
+
in [[:req, *], [:keyreq | :key, :controller]]
|
84
|
+
formatter.call(v, controller:)
|
85
|
+
in [[:req, *], [:keyreq | :key, :schema]]
|
86
|
+
formatter.call(v, schema:)
|
87
|
+
end
|
79
88
|
when 1
|
80
89
|
formatter.call(v)
|
81
90
|
end
|
@@ -38,7 +38,7 @@ module TypedParams
|
|
38
38
|
|
39
39
|
value.each_with_index do |v, i|
|
40
40
|
unless schema.children.nil?
|
41
|
-
child = schema.children.fetch(i) { schema.
|
41
|
+
child = schema.children.fetch(i) { schema.endless? ? schema.children.first : nil }
|
42
42
|
if child.nil?
|
43
43
|
raise UnpermittedParameterError.new('unpermitted parameter', path: Path.new(*param.path.keys, i), source: schema.source) if
|
44
44
|
schema.strict?
|
@@ -63,7 +63,7 @@ module TypedParams
|
|
63
63
|
|
64
64
|
value.each do |k, v|
|
65
65
|
unless schema.children.nil?
|
66
|
-
child = schema.children.fetch(k) {
|
66
|
+
child = schema.children.fetch(k) { schema.children.values.find { _1.alias == k } }
|
67
67
|
if child.nil?
|
68
68
|
raise UnpermittedParameterError.new('unpermitted parameter', path: Path.new(*param.path.keys, k), source: schema.source) if
|
69
69
|
schema.strict?
|
@@ -71,7 +71,7 @@ module TypedParams
|
|
71
71
|
next
|
72
72
|
end
|
73
73
|
|
74
|
-
param[
|
74
|
+
param[child.key] = Parameterizer.new(schema: child, parent: param).call(key: child.key, value: v)
|
75
75
|
else
|
76
76
|
param[k] = Parameter.new(key: k, value: v, schema:, parent: param)
|
77
77
|
end
|
data/lib/typed_params/schema.rb
CHANGED
@@ -10,6 +10,7 @@ module TypedParams
|
|
10
10
|
:source,
|
11
11
|
:type,
|
12
12
|
:key,
|
13
|
+
:alias,
|
13
14
|
:if,
|
14
15
|
:unless
|
15
16
|
|
@@ -22,6 +23,7 @@ module TypedParams
|
|
22
23
|
key: nil,
|
23
24
|
optional: false,
|
24
25
|
coerce: false,
|
26
|
+
polymorphic: false,
|
25
27
|
allow_blank: false,
|
26
28
|
allow_nil: false,
|
27
29
|
allow_non_scalars: false,
|
@@ -36,6 +38,7 @@ module TypedParams
|
|
36
38
|
if: nil,
|
37
39
|
unless: nil,
|
38
40
|
as: nil,
|
41
|
+
alias: nil,
|
39
42
|
casing: TypedParams.config.key_transform,
|
40
43
|
&block
|
41
44
|
)
|
@@ -77,8 +80,10 @@ module TypedParams
|
|
77
80
|
@strict = strict
|
78
81
|
@parent = parent
|
79
82
|
@key = key
|
83
|
+
@alias = binding.local_variable_get(:alias)
|
80
84
|
@optional = optional
|
81
85
|
@coerce = coerce && @type.coercable?
|
86
|
+
@polymorphic = polymorphic
|
82
87
|
@allow_blank = key == ROOT || allow_blank
|
83
88
|
@allow_nil = allow_nil
|
84
89
|
@allow_non_scalars = allow_non_scalars
|
@@ -211,7 +216,7 @@ module TypedParams
|
|
211
216
|
|
212
217
|
##
|
213
218
|
# params defines multiple like-parameters for a hash schema.
|
214
|
-
def params(*keys, **kwargs, &) = keys.each { param(_1, **kwargs, &) }
|
219
|
+
def params(*keys, **kwargs, &block) = keys.each { param(_1, **kwargs, &block) }
|
215
220
|
|
216
221
|
##
|
217
222
|
# item defines an indexed parameter for an array schema.
|
@@ -220,7 +225,7 @@ module TypedParams
|
|
220
225
|
Types.array?(children)
|
221
226
|
|
222
227
|
raise ArgumentError, "index #{key} has already been defined" if
|
223
|
-
children[key].present? ||
|
228
|
+
children[key].present? || endless?
|
224
229
|
|
225
230
|
children << Schema.new(**options, **kwargs, key:, type:, strict:, source:, casing:, parent: self, &block)
|
226
231
|
end
|
@@ -230,7 +235,7 @@ module TypedParams
|
|
230
235
|
def items(**kwargs, &)
|
231
236
|
item(0, **kwargs, &)
|
232
237
|
|
233
|
-
|
238
|
+
endless!
|
234
239
|
end
|
235
240
|
|
236
241
|
def path
|
@@ -261,12 +266,14 @@ module TypedParams
|
|
261
266
|
def optional? = !!@optional
|
262
267
|
def required? = !optional?
|
263
268
|
def coerce? = !!@coerce
|
269
|
+
def polymorphic? = !!@polymorphic
|
270
|
+
def aliased? = !!@alias
|
264
271
|
def allow_blank? = !!@allow_blank
|
265
272
|
def allow_nil? = !!@allow_nil
|
266
273
|
def allow_non_scalars? = !!@allow_non_scalars
|
267
274
|
def nilify_blanks? = !!@nilify_blanks
|
268
|
-
def
|
269
|
-
def indexed? = !
|
275
|
+
def endless? = !!@endless
|
276
|
+
def indexed? = !endless?
|
270
277
|
def if? = !@if.nil?
|
271
278
|
def unless? = !@unless.nil?
|
272
279
|
def array? = Types.array?(type)
|
@@ -278,6 +285,9 @@ module TypedParams
|
|
278
285
|
"#<#{self.class.name} key=#{key.inspect} type=#{type.inspect} children=#{children.inspect}>"
|
279
286
|
end
|
280
287
|
|
288
|
+
# @private
|
289
|
+
def dig(*keys) = children.dig(*keys)
|
290
|
+
|
281
291
|
private
|
282
292
|
|
283
293
|
attr_reader :controller,
|
@@ -285,6 +295,6 @@ module TypedParams
|
|
285
295
|
:strict,
|
286
296
|
:casing
|
287
297
|
|
288
|
-
def
|
298
|
+
def endless! = @endless = true
|
289
299
|
end
|
290
300
|
end
|
data/lib/typed_params/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typed_params
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zeke Gabrielse
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|