Skip to content

Commit

Permalink
Add Union.from_json_object_key? (#15411)
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota authored Feb 9, 2025
1 parent 0cc0264 commit a2573f9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
17 changes: 17 additions & 0 deletions spec/std/json/serialization_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,23 @@ describe "JSON serialization" do
Hash(BigDecimal, String).from_json(%({"1234567890.123456789": "x"})).should eq({"1234567890.123456789".to_big_d => "x"})
end

describe "Hash with union key (Union.from_json_object_key?)" do
it "string deprioritized" do
Hash(String | Int32, Nil).from_json(%({"1": null})).should eq({1 => nil})
Hash(String | UInt32, Nil).from_json(%({"1": null})).should eq({1 => nil})
end

it "string without alternative" do
Hash(String | Int32, Nil).from_json(%({"foo": null})).should eq({"foo" => nil})
end

it "no match" do
expect_raises JSON::ParseException, %(Can't convert "foo" into (Float64 | Int32) at line 1, column 2) do
Hash(Float64 | Int32, Nil).from_json(%({"foo": null}))
end
end
end

it "raises an error Hash(String, Int32)#from_json with null value" do
expect_raises(JSON::ParseException, "Expected Int but was Null") do
Hash(String, Int32).from_json(%({"foo": 1, "bar": 2, "baz": null}))
Expand Down
22 changes: 22 additions & 0 deletions src/json/from_json.cr
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,28 @@ def Union.new(pull : JSON::PullParser)
{% end %}
end

def Union.from_json_object_key?(key : String)
{% begin %}
# String must come last because any key can be parsed into a String.
# So, we give a chance first to other types in the union to be parsed.
{% string_type = T.find { |type| type == ::String } %}

{% for type in T %}
{% unless type == string_type %}
if result = {{ type }}.from_json_object_key?(key)
return result
end
{% end %}
{% end %}

{% if string_type %}
if result = {{ string_type }}.from_json_object_key?(key)
return result
end
{% end %}
{% end %}
end

# Reads a string from JSON parser as a time formatted according to [RFC 3339](https://tools.ietf.org/html/rfc3339)
# or other variations of [ISO 8601](http://xml.coverpages.org/ISO-FDIS-8601.pdf).
#
Expand Down

0 comments on commit a2573f9

Please sign in to comment.