-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix oneOf/allOf/anyOf and schema module in Discriminator mapping #455
Conversation
Co-authored-by: Mike Buhot <m.buhot@gmail.com>
chore: add tests
The value must be valid against all schemas given in allOf list
up |
hey, someone here willing to merge this pr ? |
@igormq It's difficult to review and merge this PR with so many commits and changes. |
|
||
# Merge 2 maps considering as equal keys that are atom or string representation | ||
# of that atom. Atom keys takes precedence over string ones. | ||
def merge_maps(map1, map2) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've not implemented this and am not sure what the functions achieves. @albertored can you take a look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Can this be merged? I've been running this in production for a few months as it fixes a few issues with the existing code where Discriminator is not working. I guess improvements can be done in subsequent PRs. |
end | ||
defp find_discriminator_schema(discriminator, _mappings, schemas) | ||
when is_atom(discriminator) and not is_nil(discriminator), | ||
do: Enum.find(schemas, &Kernel.==(&1."x-struct", discriminator)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Kernel.==
necessary here? can it be:
do: Enum.find(schemas, &Kernel.==(&1."x-struct", discriminator)) | |
do: Enum.find(schemas, & &1."x-struct" == discriminator) |
?
@@ -40,7 +40,7 @@ defmodule OpenApiSpex.Cast.Discriminator do | |||
defp cast_discriminator(%_{value: value, schema: schema} = ctx) do | |||
{discriminator_property, mappings} = discriminator_details(schema) | |||
|
|||
case value["#{discriminator_property}"] || value[discriminator_property] do | |||
case value["#{discriminator_property}"] do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mbuhot I don't remember if I was the one that originally added this line but I think this was needed to support discriminators where the property is an atom, it is indirectly tested in the test you removed in this same commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a scenario where the discriminator property is an atom?
The test was casting a map where all keys were already atoms, I'm not sure when that would be required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are use cases but I don't have a particular one in mind.
My reasoning was that since it is possible to cast an object with atom keys it should be possible also when the discriminator property is an atom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heho, The example from the tests still renders a wrong json. defmodule AppointmentType do
require OpenApiSpex
OpenApiSpex.schema(%{
title: "AppointmentType",
type: :object,
properties: %{
appointment_type: %Schema{
type: :string
}
},
required: [:appointment_type]
})
end
defmodule TrainingAppointment do
OpenApiSpex.schema(%{
title: "TrainingAppointment",
description: "Request for a training appointment",
type: :object,
allOf: [
AppointmentType,
%Schema{
type: :object,
properties: %{
level: %Schema{
description: "The level of training",
type: :integer
}
},
required: [:level]
}
]
})
end
defmodule GroomingAppointment do
OpenApiSpex.schema(%{
title: "GroomingAppointment",
description: "Request for a training appointment",
type: :object,
allOf: [
AppointmentType,
%Schema{
type: :object,
properties: %{
hair_trim: %Schema{
description: "Whether or not to include a hair trim",
type: :boolean
},
nail_clip: %Schema{
description: "Whether or not to include nail clip",
type: :boolean
}
},
required: [:hair_trim, :nail_clip]
}
]
})
end
defmodule PetAppointmentRequest do
OpenApiSpex.schema(%{
title: "PetAppointmentRequest",
description: "POST body for making a pet appointment",
type: :object,
oneOf: [
TrainingAppointment,
GroomingAppointment
],
discriminator: %OpenApiSpex.Discriminator{
propertyName: "appointment_type",
mapping: %{
"training" => "TrainingAppointment",
"grooming" => "GroomingAppointment"
}
}
})
end |
@mbuhot It works great from my point of view: Thansk for the quick fix! :) |
@Aduril Great I'll tag a release 👍 |
This is the same as #440, with master merged and a fix to allow Schema modules to be used in Discriminator mappings instead of relying on the title:
Without this casting does not currently work proprerly for schemas with oneOf and Discriminator. It also removes the discriminator propertyName from the path, avoiding it to be added to the JSON pointers in validation errors.