openapi_parameters 0.8.0 → 0.9.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: ee2751342867fef145f12b7b8cd681cca155ba396a89c69f6c476d5566967cff
4
- data.tar.gz: 7f00815807f40d26a66b9aac7c58565ad568adb4a7d91b497805168d9b4e9def
3
+ metadata.gz: 6e4a1690610c9bbbd5f901f5521b8d5c417d5679b2d3c22bf7c3b4fe5863a9a4
4
+ data.tar.gz: 37cadc3d8d9ff17c11082d1fe14db177b1778d14f0b89698fe5ad2292b5927db
5
5
  SHA512:
6
- metadata.gz: 27e43f8835d7759baef4deb7969a6517fedcf6e7456916369c4d6aeae4ff624ce77eaff7968c5ab01f36edbcd92b1bbc9388d3af14170d8c0130c874621f882d
7
- data.tar.gz: 107e3ffa3b290342b68ae3a6228a4b780e2cbd7be26c12ee42aa276d1be0128a4f024b724424f6e2330578d833995644a23e0f9907b3cf145f1978f8916acb4b
6
+ metadata.gz: b842ce9afd9246033103fddc51a26e888d9154eb4e694722f55c3ad3cb6a8226b3315e738411e71a21c516b5ef4f3bd8d86699d4638016b7c5aa5cec52b252c8
7
+ data.tar.gz: '09dd12da6978846a76a680fb22a859f339fb398bc3733682bf5924ff42d6de39e13b3f2f231552f777e175a1894fe9a915cd449dc7157b0ae2d37de21bd7b1b9'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.9.0] - 2025-11-07
4
+
5
+ - Add support for unpacking query parameters that use deepObject and oneOf,andOf,anyOf,if-them-else
6
+
3
7
  ## [0.8.0] - 2025-09-17
4
8
 
5
9
  - No longer parse more than one level of nested objects when parsing `deepObject` parameters. This is actually in line with what `deepObject` supports.
@@ -2,13 +2,7 @@
2
2
 
3
3
  module OpenapiParameters
4
4
  # @visibility private
5
- class ArrayConverter
6
- def initialize(schema)
7
- @schema = schema
8
- end
9
-
10
- attr_reader :schema
11
-
5
+ ArrayConverter = Data.define(:schema) do
12
6
  def call(value)
13
7
  return [] if value.nil? || value.empty?
14
8
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'array_converter'
4
+ require_relative 'object_converter'
4
5
 
5
6
  module OpenapiParameters
6
7
  # Tries to convert a request parameter value (string) to the type specified in the JSON Schema.
@@ -33,26 +34,18 @@ module OpenapiParameters
33
34
  value == 'false' ? false : value
34
35
  end
35
36
  when 'object'
36
- convert_object(value, schema)
37
+ ObjectConverter.new(schema).call(value)
37
38
  when 'array'
38
39
  ArrayConverter.new(schema).call(value)
39
40
  else
40
- if schema['properties']
41
- convert_object(value, schema)
41
+ if schema['properties'] || schema['oneOf'] || schema['allOf'] || schema['anyOf']
42
+ ObjectConverter.new(schema).call(value)
42
43
  else
43
44
  value
44
45
  end
45
46
  end
46
47
  end
47
48
 
48
- def convert_object(value, schema)
49
- return value unless value.is_a?(Hash)
50
-
51
- value.each_with_object({}) do |(key, val), hsh|
52
- hsh[key] = Converter.convert(val, schema['properties']&.fetch(key, nil))
53
- end
54
- end
55
-
56
49
  private
57
50
 
58
51
  def type(schema)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiParameters
4
+ # @visibility private
5
+ ObjectConverter = Data.define(:schema) do
6
+ def self.get_properties(schema) # rubocop:disable Metrics
7
+ return nil if schema.nil? || schema.empty?
8
+
9
+ direct_props = schema['properties']
10
+ additional_props = schema['additionalProperties']
11
+
12
+ composition_props = []
13
+
14
+ %w[allOf oneOf anyOf].each do |keyword|
15
+ next unless (array = schema[keyword])
16
+
17
+ array.each do |sub_schema|
18
+ if (props = sub_schema['properties'])
19
+ composition_props << props
20
+ end
21
+ end
22
+ end
23
+
24
+ %w[then else].each do |keyword|
25
+ next unless (sub_schema = schema[keyword])
26
+
27
+ if (props = sub_schema['properties'])
28
+ composition_props << props
29
+ end
30
+ if (add_props = sub_schema['additionalProperties']) && add_props.is_a?(Hash) && !add_props.empty?
31
+ composition_props << add_props
32
+ end
33
+ end
34
+
35
+ composition_props << additional_props if additional_props.is_a?(Hash) && !additional_props.empty?
36
+
37
+ return direct_props if composition_props.empty? && direct_props
38
+ return nil if direct_props.nil? && composition_props.empty?
39
+
40
+ result = direct_props ? direct_props.dup : {}
41
+ composition_props.each { |props| result.merge!(props) }
42
+ result
43
+ end
44
+
45
+ def call(value)
46
+ return value unless value.is_a?(Hash)
47
+
48
+ properties = self.class.get_properties(schema)
49
+
50
+ value.each_with_object({}) do |(key, val), hsh|
51
+ hsh[key] = Converter.convert(val, properties&.fetch(key, nil))
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rack'
4
+ require_relative 'converter'
4
5
 
5
6
  module OpenapiParameters
6
7
  # Query parses query parameters from a http query strings.
@@ -11,7 +12,6 @@ module OpenapiParameters
11
12
  @parameters = parameters.map { Parameter.new(_1) }
12
13
  @convert = convert
13
14
  @remove_array_brackets = rack_array_compat
14
- @any_deep_object = @parameters.any?(&:deep_object?)
15
15
  end
16
16
 
17
17
  def unpack(query_string) # rubocop:disable Metrics/AbcSize
@@ -35,14 +35,10 @@ module OpenapiParameters
35
35
  end
36
36
 
37
37
  attr_reader :parameters
38
- private attr_reader :remove_array_brackets
38
+ private attr_reader :remove_array_brackets, :parameter_property_schemas
39
39
 
40
40
  private
41
41
 
42
- def any_deep_object?
43
- @any_deep_object
44
- end
45
-
46
42
  def parse_query(query_string)
47
43
  Rack::Utils.parse_query(query_string) do |s|
48
44
  Rack::Utils.unescape(s)
@@ -51,22 +47,34 @@ module OpenapiParameters
51
47
  end
52
48
  end
53
49
 
50
+ def build_properties_schema(parameter)
51
+ schema = parameter.schema
52
+ ObjectConverter.get_properties(schema) if schema
53
+ end
54
+
55
+ DEEP_PROP = '\[([\w-]+)\]$'
56
+ private_constant :DEEP_PROP
57
+
54
58
  def parse_deep_object(parameter, parsed_query)
55
- schema_props = parameter.schema['properties'] || {}
56
59
  name = parameter.name
57
- schema_props.each.with_object({}) do |(prop, schema), result|
58
- key = "#{name}[#{prop}]"
60
+ prop_regx = /^#{name}#{DEEP_PROP}/
61
+ properties_schema = build_properties_schema(parameter)
62
+
63
+ parsed_query.each.with_object({}) do |(key, value), result|
59
64
  next unless parsed_query.key?(key)
60
65
 
61
- value = explode_value(parsed_query[key], parameter, schema)
62
- result[prop] = value
66
+ prop_key = key.match(prop_regx)&.[](1)
67
+ next if prop_key.nil?
68
+
69
+ is_array = properties_schema&.dig(prop_key, 'type') == 'array'
70
+ value = explode_value(value, parameter, is_array)
71
+ result[prop_key] = value
63
72
  end
64
73
  end
65
74
 
66
- def explode_value(value, parameter, schema)
67
- type = schema['type']
75
+ def explode_value(value, parameter, is_array)
68
76
  value = Array(value).map! { |v| Rack::Utils.unescape(v) }
69
- if type == 'array'
77
+ if is_array
70
78
  return value if parameter.explode?
71
79
 
72
80
  return [value.last]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiParameters
4
- VERSION = '0.8.0'
4
+ VERSION = '0.9.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_parameters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-09-17 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rack
@@ -43,6 +42,7 @@ files:
43
42
  - lib/openapi_parameters/header.rb
44
43
  - lib/openapi_parameters/headers_hash.rb
45
44
  - lib/openapi_parameters/not_supported_error.rb
45
+ - lib/openapi_parameters/object_converter.rb
46
46
  - lib/openapi_parameters/parameter.rb
47
47
  - lib/openapi_parameters/path.rb
48
48
  - lib/openapi_parameters/query.rb
@@ -56,7 +56,6 @@ metadata:
56
56
  source_code_uri: https://github.com/ahx/openapi_parameters
57
57
  changelog_uri: https://github.com/ahx/openapi_parameters/blob/main/CHANGELOG.md
58
58
  rubygems_mfa_required: 'true'
59
- post_install_message:
60
59
  rdoc_options: []
61
60
  require_paths:
62
61
  - lib
@@ -64,15 +63,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
64
63
  requirements:
65
64
  - - ">="
66
65
  - !ruby/object:Gem::Version
67
- version: 3.1.0
66
+ version: 3.2.0
68
67
  required_rubygems_version: !ruby/object:Gem::Requirement
69
68
  requirements:
70
69
  - - ">="
71
70
  - !ruby/object:Gem::Version
72
71
  version: '0'
73
72
  requirements: []
74
- rubygems_version: 3.4.6
75
- signing_key:
73
+ rubygems_version: 3.6.7
76
74
  specification_version: 4
77
75
  summary: openapi_parameters is an OpenAPI aware parameter parser
78
76
  test_files: []