typed_params 1.1.1 → 1.2.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: ab9149f0354b3110bc3a5610b06785055ad0e3ec00cc5e352b2daef7be902178
4
- data.tar.gz: a48c899da8bc5d9fa9ee1041a2e35ff8f2f942b9ff083f7bf42e18e34e7813a2
3
+ metadata.gz: 014c42e82286c1ffc175d08aca51e631da96a5b2aee8e9bbf575fc0bea7e1d57
4
+ data.tar.gz: 3a0ea8bac6b1021143b768767763899a6f5328f16bb6011a87b2f1ed694b6325
5
5
  SHA512:
6
- metadata.gz: 4dabec975049677e23ab38f91c121f8f83a2dab36b753c9ad58f0693ad31ce780122b503b4b7554f6afe36568e3a85ef8c4d559591a8205bbadc9740e5cfd4b9
7
- data.tar.gz: a4c8be23f0472002c9e317924091b624ac7cd640f08bfc515f61db119b72d20d6312919a4f45b31b14560d8bde08dad55467be058422acd4f39e225b927fd539
6
+ metadata.gz: c563758456e6359e37c75926124925141c59f535fc77070be23d46d3f86e0772f2cf2c52d2e57f165e2ba11f93717c6a0b15f90e61fcbe00baa19b3c1985f2a8
7
+ data.tar.gz: a277c1c13a5d0ac14ef293fbc9611bec82eba5df00686f9afaf8e324e89148aef7c49fa672bf025570a9482ec277e330edc1049a1e59051e41a559a31a4b6584
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
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
+
3
8
  ## 1.1.1
4
9
 
5
10
  - Fix compatibility with Ruby 3.3.0 due to [#20091](https://bugs.ruby-lang.org/issues/20091).
data/README.md CHANGED
@@ -436,6 +436,7 @@ Parameters can have validations, transforms, and more.
436
436
  - [`:optional`](#optional-parameter)
437
437
  - [`:if` and `:unless`](#conditional-parameter)
438
438
  - [`:as`](#rename-parameter)
439
+ - [`:alias`](#alias-parameter)
439
440
  - [`:noop`](#noop-parameter)
440
441
  - [`:coerce`](#coerce-parameter)
441
442
  - [`:allow_blank`](#allow-blank)
@@ -448,6 +449,7 @@ Parameters can have validations, transforms, and more.
448
449
  - [`:length`](#length-validation)
449
450
  - [`:transform`](#transform-parameter)
450
451
  - [`:validate`](#validate-parameter)
452
+ - [`:polymorphic`](#polymorphic-parameter)
451
453
 
452
454
  #### Parameter key
453
455
 
@@ -520,6 +522,17 @@ typed_params # => { user_id: 1 }
520
522
  In this example, the parameter would be accepted as `:user`, but renamed
521
523
  to `:user_id` for use inside of the controller.
522
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
+
523
536
  #### Noop parameter
524
537
 
525
538
  The parameter is accepted but immediately thrown out.
@@ -674,6 +687,33 @@ param :invalid, type: :string, validate: -> v {
674
687
  }
675
688
  ```
676
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
+
677
717
  ### Shared options
678
718
 
679
719
  You can define a set of options that will be applied to immediate
@@ -748,7 +788,7 @@ which may be a nested schema.
748
788
 
749
789
  ```ruby
750
790
  # array of hashes
751
- param :boundless_array, type: :array do
791
+ param :endless_array, type: :array do
752
792
  items type: :hash do
753
793
  # ...
754
794
  end
@@ -14,7 +14,7 @@ module TypedParams
14
14
 
15
15
  def decorator? = decorator.present?
16
16
 
17
- delegate :arity, :call, to: :@transform
17
+ delegate :arity, :parameters, :call, to: :@transform
18
18
  end
19
19
  end
20
20
  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
- format_array_data(data)
38
+ child = schema.children.fetch(:data)
39
+
40
+ format_array_data(data, schema: child)
39
41
  in data: Hash => data
40
- format_hash_data(data)
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 { format_hash_data(_1) }
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
 
@@ -75,7 +75,16 @@ module TypedParams
75
75
  if formatter.present?
76
76
  v = case formatter.arity
77
77
  when 2
78
- formatter.call(v, controller:)
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.boundless? ? schema.children.first : nil }
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) { nil }
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[k] = Parameterizer.new(schema: child, parent: param).call(key: k, value: v)
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
@@ -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
@@ -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? || boundless?
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
- boundless!
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 boundless? = !!@boundless
269
- def indexed? = !boundless?
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 boundless! = @boundless = true
298
+ def endless! = @endless = true
289
299
  end
290
300
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TypedParams
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
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.1.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: 2024-01-01 00:00:00.000000000 Z
11
+ date: 2024-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails