Skip to content
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

Check if input object CLR property type does not match the scalar's CLR type declared in GraphQL object definition #490

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

xperiandri
Copy link
Collaborator

No description provided.

Comment on lines 159 to 189
if result then result
else
if from.FullName.StartsWith OptionTypeName || from.FullName.StartsWith ValueOptionTypeName then
from.GetGenericArguments().[0].IsAssignableTo ``to``
else result
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we declare scalar with a validator like this

type AddressLine1 = ValidString<Phantom.Address.Line1>

module Address =
    open ValidString
    open Validus.Operators

    let createLine1 : Validator<string, AddressLine1 voption> =
        (allowEmpty ?=> (Check.String.lessThanLen 1000 <+> validateStringCharacters)) *|* ValueOption.map ValidString

let Line1Type : ScalarDefinition<string, AddressLine1 voption> = Define.ValidStringScalar<AddressLine1>("AddressLine1", createLine1, "Address line 1")

it appears that the type of scalar becomes voption<AddressLine1>
and then if we declare it Nullable

Define.Input("line1", Nullable Address.Line1Type)

it is double wrapped like option<voption<AddressLine1>>
The unwrapping itself happes on execution well but in order to perform check here I need to try unwrapping it 2 times

@xperiandri
Copy link
Collaborator Author

@valbers what do you think?

Copy link
Collaborator

@valbers valbers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@valbers what do you think?

It looks overall good. Please just take a look at my comments.

@@ -36,7 +36,8 @@ let private normalizeOptional (outputType : Type) value =
| value ->
let inputType = value.GetType ()
if inputType.Name <> outputType.Name then
let expectedOutputType = outputType.GenericTypeArguments[0]
// Use only when option or voption so must not be null
let expectedOutputType = outputType.GenericTypeArguments.FirstOrDefault()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're sure it will never be null, then:

Suggested change
let expectedOutputType = outputType.GenericTypeArguments.FirstOrDefault()
let expectedOutputType = outputType.GenericTypeArguments.First()

Otherwise, I think it's a better idea to actively throw an exception in case of Default:

if expectedOutputType = null
then
   failwith "Expected output type was null. This is a bug in FSharp.Data.GraphQL."

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, my point was that the expectedOutputType value is used only in if clauses that a relevant for Option and ValueOption types

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Just keep in mind that by doing this you create a logical dependency in the lines of code and someday someone might introduce a bug by not considering your initial intention with Option and ValueOption.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no quick idea how to improve that 🙂

src/FSharp.Data.GraphQL.Server/ReflectionHelper.fs Outdated Show resolved Hide resolved
Comment on lines 183 to 189
let result = from.IsAssignableTo ``to`` || checkCollections from ``to``
if result then result
else
if from.FullName.StartsWith OptionTypeName || from.FullName.StartsWith ValueOptionTypeName then
let from = from.GetGenericArguments()[0]
from.IsAssignableTo ``to`` || checkCollections from ``to``
else result
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let result = from.IsAssignableTo ``to`` || checkCollections from ``to``
if result then result
else
if from.FullName.StartsWith OptionTypeName || from.FullName.StartsWith ValueOptionTypeName then
let from = from.GetGenericArguments()[0]
from.IsAssignableTo ``to`` || checkCollections from ``to``
else result
from.IsAssignableTo ``to`` || checkCollections from ``to`` ||
((from.FullName.StartsWith OptionTypeName || from.FullName.StartsWith ValueOptionTypeName) && ((from.GetGenericArguments()[0]).IsAssignableTo ``to`` || checkCollections from ``to``))

also notice how the else result in your code is superfluous, since result is always false at that point.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is hard to read

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but did you also read the part:

also notice how the else result in your code is superfluous, since result is always false at that point.

?

Copy link
Collaborator Author

@xperiandri xperiandri Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep but do you see wrong in that?

@xperiandri xperiandri force-pushed the input_object_deserialization_fix branch 3 times, most recently from 079c192 to ef24b61 Compare September 11, 2024 20:47
@xperiandri xperiandri force-pushed the input_object_deserialization_fix branch from ef24b61 to 821acdc Compare October 4, 2024 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants