Skip to content

Commit 2e4e440

Browse files
basjanssengeemus
andauthored
Add date coercion (#188)
* Add date coercion * Fix error class for invalid date format * feat(config): add date coerce class type method - Extends configuration interface with optional date coercion class - Provides type flexibility for date parsing and handling - Complements existing `datetime_coerce_class` method --------- Co-authored-by: Wesley Beary <[email protected]>
1 parent 2361ec7 commit 2e4e440

File tree

9 files changed

+45
-15
lines changed

9 files changed

+45
-15
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ request_operation.path_params
2727
# => {"template_name"=>"1"}
2828

2929
# coerce parameter
30-
root = OpenAPIParser.parse(YAML.load_file('open_api_3/schema.yml'), {coerce_value: true, datetime_coerce_class: DateTime})
30+
root = OpenAPIParser.parse(YAML.load_file('open_api_3/schema.yml'), {coerce_value: true, datetime_coerce_class: DateTime, date_coerce_class: Date})
3131
request_operation = root.request_operation(:get, '/string_params_coercer')
3232
request_operation.validate_request_parameter({'integer_1' => '1', 'datetime_string' => '2016-04-01T16:00:00+09:00'})
3333
# => {"integer_1"=>1, "datetime_string"=>#<DateTime: 2016-04-01T16:00:00+09:00 ((2457480j,25200s,0n),+32400s,2299161j)>

lib/openapi_parser/config.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ def datetime_coerce_class
1919
@config[:datetime_coerce_class]
2020
end
2121

22+
def date_coerce_class
23+
@config[:date_coerce_class]
24+
end
25+
2226
def coerce_value
2327
@config[:coerce_value]
2428
end
@@ -46,6 +50,7 @@ def request_validator_options
4650
@request_validator_options ||= OpenAPIParser::SchemaValidator::Options.new(allow_empty_date_and_datetime: allow_empty_date_and_datetime,
4751
coerce_value: coerce_value,
4852
datetime_coerce_class: datetime_coerce_class,
53+
date_coerce_class: date_coerce_class,
4954
validate_header: validate_header)
5055
end
5156

lib/openapi_parser/schema_validator.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def initialize(value, schema, options)
5656
@allow_empty_date_and_datetime = options.allow_empty_date_and_datetime
5757
@coerce_value = options.coerce_value
5858
@datetime_coerce_class = options.datetime_coerce_class
59+
@date_coerce_class = options.date_coerce_class
5960
end
6061

6162
# execute validate data
@@ -121,7 +122,7 @@ def validator(value, schema)
121122
end
122123

123124
def string_validator
124-
@string_validator ||= OpenAPIParser::SchemaValidator::StringValidator.new(self, @allow_empty_date_and_datetime, @coerce_value, @datetime_coerce_class)
125+
@string_validator ||= OpenAPIParser::SchemaValidator::StringValidator.new(self, @allow_empty_date_and_datetime, @coerce_value, @datetime_coerce_class, @date_coerce_class)
125126
end
126127

127128
def integer_validator

lib/openapi_parser/schema_validator/options.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ class Options
66
# @return [Boolean] coerce value option on/off
77
# @!attribute [r] datetime_coerce_class
88
# @return [Object, nil] coerce datetime string by this Object class
9+
# @!attribute [r] date_coerce_class
10+
# @return [Object, nil] coerce date string by this Object class
911
# @!attribute [r] validate_header
1012
# @return [Boolean] validate header or not
11-
attr_reader :allow_empty_date_and_datetime, :coerce_value, :datetime_coerce_class, :validate_header
13+
attr_reader :allow_empty_date_and_datetime, :coerce_value, :datetime_coerce_class, :validate_header, :date_coerce_class
1214

13-
def initialize(allow_empty_date_and_datetime: false, coerce_value: nil, datetime_coerce_class: nil, validate_header: true)
15+
def initialize(allow_empty_date_and_datetime: false, coerce_value: nil, datetime_coerce_class: nil, validate_header: true, date_coerce_class: nil)
1416
@allow_empty_date_and_datetime = allow_empty_date_and_datetime
1517
@coerce_value = coerce_value
1618
@datetime_coerce_class = datetime_coerce_class
19+
@date_coerce_class = date_coerce_class
1720
@validate_header = validate_header
1821
end
1922
end

lib/openapi_parser/schema_validator/string_validator.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ class OpenAPIParser::SchemaValidator
22
class StringValidator < Base
33
include ::OpenAPIParser::SchemaValidator::Enumable
44

5-
def initialize(validator, allow_empty_date_and_datetime, coerce_value, datetime_coerce_class)
5+
def initialize(validator, allow_empty_date_and_datetime, coerce_value, datetime_coerce_class, date_coerce_class)
66
super(validator, coerce_value)
77
@allow_empty_date_and_datetime = allow_empty_date_and_datetime
88
@datetime_coerce_class = datetime_coerce_class
9+
@date_coerce_class = date_coerce_class
910
end
1011

1112
def coerce_and_validate(value, schema, **_keyword_args)
@@ -90,16 +91,18 @@ def validate_date_format(value, schema)
9091
return [nil, OpenAPIParser::InvalidDateFormat.new(value, schema.object_reference)] unless value =~ /^\d{4}-\d{2}-\d{2}$/
9192

9293
begin
93-
parsed_date = Date.iso8601(value)
94+
if @date_coerce_class.nil?
95+
# validate only
96+
Date.iso8601(value)
97+
[value, nil]
98+
else
99+
# validate and coerce
100+
[@date_coerce_class.iso8601(value), nil]
101+
end
94102
rescue ArgumentError
95-
return [nil, OpenAPIParser::InvalidDateFormat.new(value, schema.object_reference)]
96-
end
97-
98-
unless parsed_date.strftime('%Y-%m-%d') == value
99-
return [nil, OpenAPIParser::InvalidDateFormat.new(value, schema.object_reference)]
103+
# when rfc3339(value) failed
104+
[nil, OpenAPIParser::InvalidDateFormat.new(value, schema.object_reference)]
100105
end
101-
102-
return [value, nil]
103106
end
104107

105108
def validate_datetime_format(value, schema)

sig/openapi_parser/config.rbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module OpenAPIParser
99

1010
def initialize: (untyped config) -> untyped
1111
def allow_empty_date_and_datetime: -> bool
12+
def date_coerce_class: -> (singleton(Object) | nil)
1213
def datetime_coerce_class: -> (singleton(Object) | nil)
1314
def coerce_value: -> bool
1415
def expand_reference: -> bool

sig/openapi_parser/schema_validator.rbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module OpenAPIParser
66
@schema: OpenAPIParser::Schemas::Schema
77
@coerce_value: bool | nil
88
@datetime_coerce_class: singleton(Object) | nil
9+
@date_coerce_class: singleton(Object) | nil
910
@string_validator: OpenAPIParser::SchemaValidator::StringValidator | nil
1011
@integer_validator: OpenAPIParser::SchemaValidator::IntegerValidator | nil
1112
@float_validator: OpenAPIParser::SchemaValidator::FloatValidator | nil

sig/openapi_parser/schema_validators/options.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module OpenAPIParser
66
attr_reader coerce_value: bool | nil
77
attr_reader datetime_coerce_class: singleton(Object) | nil
88
attr_reader validate_header: bool
9-
def initialize: (?allow_empty_date_and_datetime: bool | nil, ?coerce_value: bool | nil, ?datetime_coerce_class: singleton(Object) | nil, ?validate_header: bool) -> untyped
9+
def initialize: (?allow_empty_date_and_datetime: bool | nil, ?coerce_value: bool | nil, ?datetime_coerce_class: singleton(Object) | nil, ?date_coerce_class: singleton(Object) | nil, ?validate_header: bool) -> untyped
1010
end
1111

1212
class ResponseValidateOptions

spec/openapi_parser/schema_validator/string_validator_spec.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,24 @@
224224
end
225225

226226
context 'correct' do
227+
let(:options) { ::OpenAPIParser::SchemaValidator::Options.new(coerce_value: true, date_coerce_class: date_coerce_class) }
227228
let(:params) { { 'date_str' => '2021-02-12' } }
228-
it { expect(subject).to eq({ 'date_str' => '2021-02-12' }) }
229+
230+
context 'when date_coerce_class is nil' do
231+
let(:date_coerce_class) { nil }
232+
233+
it 'return String' do
234+
expect(subject).to eq({ 'date_str' => '2021-02-12' })
235+
end
236+
end
237+
238+
context 'when date_coerce_class is Date' do
239+
let(:date_coerce_class) { Date }
240+
241+
it 'return Date' do
242+
expect(subject).to eq({ 'date_str' => Date.iso8601('2021-02-12') })
243+
end
244+
end
229245
end
230246

231247
context 'invalid' do

0 commit comments

Comments
 (0)