Skip to content

Commit 8035695

Browse files
fix: bug coercing boolean strings (#126)
- fields with a type of T::Boolean were getting caught in the T.any conditional block and failing to activate the BooleanCoercer class. I moved the `select_coercer_by` call up to the serializer so we can handle the case where the type alias matches a coercer, falling back to checking each of the individual types in the alias if no top-level coercer is found.
1 parent 8446c13 commit 8035695

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

lib/typed/serializer.rb

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,19 @@ def serialize(struct)
3434
def deserialize_from_creation_params(creation_params)
3535
results = schema.fields.map do |field|
3636
value = creation_params.fetch(field.name, nil)
37+
coercer = Coercion::CoercerRegistry.instance.select_coercer_by(type: field.type)
3738

3839
if value.nil? && !field.default.nil?
3940
Success.new(Validations::ValidatedValue.new(name: field.name, value: field.default))
4041
elsif value.nil? || field.works_with?(value)
4142
field.validate(value)
43+
elsif !coercer.nil?
44+
result = coercer.new.coerce(type: field.type, value:)
45+
if result.success?
46+
field.validate(result.payload)
47+
else
48+
Failure.new(Validations::ValidationError.new(result.error.message))
49+
end
4250
elsif field.type.class <= T::Types::Union
4351
errors = []
4452
validated_value = T.let(nil, T.nilable(Typed::Result[Typed::Validations::ValidatedValue, Typed::Validations::ValidationError]))
@@ -60,13 +68,7 @@ def deserialize_from_creation_params(creation_params)
6068

6169
validated_value.nil? ? Failure.new(Validations::ValidationError.new(errors.map(&:message).join(", "))) : validated_value
6270
else
63-
coercion_result = Coercion.coerce(type: field.type, value:)
64-
65-
if coercion_result.success?
66-
field.validate(coercion_result.payload)
67-
else
68-
Failure.new(Validations::ValidationError.new(coercion_result.error.message))
69-
end
71+
Failure.new(Validations::ValidationError.new("Coercer not found for type #{field.type}."))
7072
end
7173
end
7274

test/typed/hash_serializer_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ def test_with_boolean_it_can_deserialize
109109
assert_payload(NEW_YORK_CITY, result)
110110
end
111111

112+
def test_with_boolean_string_false_it_can_deserialize
113+
result = Typed::HashSerializer.new(schema: Typed::Schema.from_struct(City)).deserialize({name: "New York", capital: "false"})
114+
115+
assert_success(result)
116+
assert_payload(NEW_YORK_CITY, result)
117+
end
118+
119+
def test_with_boolean_string_true_it_can_deserialize
120+
result = Typed::HashSerializer.new(schema: Typed::Schema.from_struct(City)).deserialize({name: "DC", capital: "true"})
121+
122+
assert_success(result)
123+
assert_payload(DC_CITY, result)
124+
end
125+
112126
def test_with_array_it_can_deserialize
113127
result = Typed::HashSerializer.new(schema: Typed::Schema.from_struct(Country)).deserialize({name: "US", cities: [NEW_YORK_CITY, DC_CITY], national_items: {bird: "bald eagle", anthem: "The Star-Spangled Banner"}})
114128

test/typed/json_serializer_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ def test_with_boolean_it_can_deserialize
6060
assert_payload(NEW_YORK_CITY, result)
6161
end
6262

63+
def test_with_boolean_string_false_it_can_deserialize
64+
result = Typed::JSONSerializer.new(schema: Typed::Schema.from_struct(City)).deserialize('{"name":"New York","capital":"false"}')
65+
66+
assert_success(result)
67+
assert_payload(NEW_YORK_CITY, result)
68+
end
69+
70+
def test_with_boolean_string_true_it_can_deserialize
71+
result = Typed::JSONSerializer.new(schema: Typed::Schema.from_struct(City)).deserialize('{"name":"DC","capital":"true"}')
72+
73+
assert_success(result)
74+
assert_payload(DC_CITY, result)
75+
end
76+
6377
def test_with_array_it_can_deep_deserialize
6478
result = Typed::JSONSerializer.new(schema: Typed::Schema.from_struct(Country)).deserialize('{"name":"US","cities":[{"name":"New York","capital":false},{"name":"DC","capital":true}],"national_items":{"bird":"bald eagle","anthem":"The Star-Spangled Banner"}}')
6579

0 commit comments

Comments
 (0)