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

add multiple types of parameter resolution #419

Merged
merged 22 commits into from
Aug 16, 2019
Merged

add multiple types of parameter resolution #419

merged 22 commits into from
Aug 16, 2019

Conversation

sowork
Copy link
Contributor

@sowork sowork commented Jul 23, 2019

$args is parsed incorrectly when the parameter passed in is an object or listObject

{
    "query": "{users{id, name blogs(filter:{id:1, desc:\"hello\", ReviewInput:{id: 4}}, field5:[{id:2,desc:\"world\"},{id:3,desc:\"world\", ReviewInput:{id: 4}}]){id text comments{id desc} }}}"
}

$args:   result:
Array
(
    [filter] => Array
        (
            [id] => 1
            [desc] => hello
            [ReviewInput] => Array
                (
                    [id] => 4
                )

        )

    [field5] => Array
        (
            [0] => Array
                (
                    [id] => 2
                    [desc] => world
                )

            [1] => Array
                (
                    [id] => 3
                    [desc] => world
                    [ReviewInput] => Array
                        (
                            [id] => 4
                        )

                )

        )

)

@sowork
Copy link
Contributor Author

sowork commented Jul 23, 2019

Moved into PR description for clarity

@sowork
Copy link
Contributor Author

sowork commented Jul 23, 2019

looks like something went wrong

Ignored error pattern /Access to an undefined property GraphQL\\Language\\AST\\ValueNode::\$value/ was not matched in reported errors.

what do I need to do?

@mfn
Copy link
Collaborator

mfn commented Jul 23, 2019

Please:

  • don't format / change existing / unrelated code
  • add tests!

Thank you!

@sowork
Copy link
Contributor Author

sowork commented Jul 23, 2019

don't format / change existing / unrelated code

I don't understand what you mean, can you say something specific?

if ($value instanceof VariableNode) {
$variableName = $value->name->value;

return $this->info->variableValues[$variableName] ?? null;
}
// Scalar Types
if ($value instanceof IntValueNode || $value instanceof FloatValueNode || $value instanceof StringValueNode || $value instanceof BooleanValueNode || $value instanceof EnumValueNode) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be shorten to:

if ($value instanceof ValueNode)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Valuenode contains the following types

/**
export type ValueNode = VariableNode
| NullValueNode
| IntValueNode
| FloatValueNode
| StringValueNode
| BooleanValueNode
| EnumValueNode
| ListValueNode
| ObjectValueNode
*/

The parameter is ListValueNode or ObjectValueNode is not applicable.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@sowork @crissi should we change the order of conditions?

  1. check for ListValueNode and ObjectVakueNode
  2. Check for ValueNode

This way we would not be concerned anymore about all the details as they effectively work the same.

Another approach for 2.: we effectively treat the "fallthrough" in this method as always being ValueNode and return $argumentNode->value as it currently is?

Would that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Theoretically feasible, but there is also a nullValueNode

Copy link
Contributor

Choose a reason for hiding this comment

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

not sure

but checking for the ListValueNode and ObjectVakueNode and nullValueNode first

and then fallthough to just get the value might work. So custom scalar types is also considered, not sure the current implementation take this in account.

Copy link
Collaborator

Choose a reason for hiding this comment

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

but there is also a nullValueNode

Right! Forgot to list it, but that would apply for it too.

So custom scalar types

Oh, interesting. Didn't think about it and currently don't know what kind of node it exactly is.

We need a test for this too. 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

custom scalar types

for custom scalar types will still be converted to a ValueNode

@mfn
Copy link
Collaborator

mfn commented Jul 23, 2019

I don't understand what you mean, can you say something specific?

Please don't just remove the empty lines:
image

Also this change seems unrelated to any functionality in this PR:
image

But most importantly would be tests first.

@sowork
Copy link
Contributor Author

sowork commented Jul 24, 2019

I don't understand what you mean, can you say something specific?

Please don't just remove the empty lines:
image

Also this change seems unrelated to any functionality in this PR:
image

But most importantly would be tests first.

This may be caused by my editor, I will fix it later and append a test

thank

Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

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

Thanks for for, now just waiting for the test(s) :-)

@sowork
Copy link
Contributor Author

sowork commented Jul 31, 2019

I added a unit test and it should be fine now.

Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

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

Many thanks for the PR, I did my first in-depth review today.

I'm in favour of this change and looking forward to include it 👍 but have some feedback regarding style and clarity as well as the tests 🔍

My issue with the test:

  • it's slapped on top of an existing but absolutely unrelated test
  • all types supported in \Rebing\GraphQL\Support\ResolveInfoFieldsAndArguments::getValue should be tested for (currently it misses at least the null type and the variable node; the latter was already there but I think it's the right time to add this)
  • there are no real assertions on the new code: rather it implicitly observes the output of the GraphQL result. That's great and useful for many applications, but I think in this particular one it should be more explicit

My suggestion is:

  • it should be a standalone test, i.e. create a new directory/namespace in tests/Database/SelectFields
  • the (new) FilterInput should cover all types supported in getValue
  • the assertions should be done when the 'query' receives the arguments, i.e. with the types the full $args could be compared to a expected array using \PHPUnit\Framework\Assert::assertSame => see \Rebing\GraphQL\Tests\Database\SelectFields\ValidateFieldTests\PostType::fields for an example. Having to add fixtures / results for a test just bloats for not obvious reasons. A assertion directly where we receive the data ASAP we transformed it seems most appropriate for me.
    • As such I would suggest to remove all the newly added models, types, etc. and only concentrate on the essential as outlined above

What do you think?

return $this->getInputListObjectValue($value);
}

throw new \Exception('Failed to resolve unknown ValueNode type');
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 don't add a specific exception, please use at least RuntimeException (and import it)

Copy link
Collaborator

Choose a reason for hiding this comment

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

How can this be triggered with the current code?

Would like to see a test for this.

@@ -76,6 +85,7 @@ public function __construct(ResolveInfo $info)
* @param int $depth How many levels to include in output
* @return array
* @see \GraphQL\Type\Definition\ResolveInfo::getFieldSelection
* @throws \Exception
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please remove all the @throws you added in this PR

They are deliberately not added because it's a PITA to maintain them. Code changes, exception changes and before you notice it, it's out of date.

if ($value instanceof IntValueNode || $value instanceof FloatValueNode || $value instanceof StringValueNode || $value instanceof BooleanValueNode || $value instanceof EnumValueNode) {
return $value->value;
}
// null Type
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the code speaks for itself, remove the comment (but leave a blank line)

if ($value instanceof NullValueNode) {
return;
}
// object Type
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the code speaks for itself, remove the comment (but leave a blank line)

if ($value instanceof ObjectValueNode) {
return $this->getInputObjectValue($value);
}
// list object Type
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the code speaks for itself, remove the comment (but leave a blank line)

* @return array
* @throws \Exception
*/
private function getInputListObjectValue(ListValueNode $listValueNode)
Copy link
Collaborator

Choose a reason for hiding this comment

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

add return type decl :array

}
// null Type
if ($value instanceof NullValueNode) {
return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be more explicit and actually return null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Originally I returned null, but styleci changed to this way by default.

Copy link
Collaborator

Choose a reason for hiding this comment

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

How strange, thanks!

{
$value = [];
foreach ($objectValueNode->fields->getIterator() as $item) {
if ($item instanceof ObjectFieldNode) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure about this.

The code makes it look like $item could be something else. But reading \GraphQL\Language\AST\ObjectValueNode::$fields it's clear this is not intended.

How can we improve this? Should we remove the check? Or add an } else { and throw an exception?

Because as it is right now, if that case ever would happen, we silently would carry on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. Currently, item only handles objects of type ObjectFieldNode
  2. If the current item object contains other scalar types or listNode and so on, the resolution continues recursively

@@ -42,8 +42,6 @@ parameters:
- '/Cannot call method set\(\) on Illuminate\\Config\\Repository\|null/'
- '/Parameter #4 \$currentPage of class Illuminate\\Pagination\\LengthAwarePaginator constructor expects int\|null, float\|int given/'
- '/Parameter #1 \$offset of method Illuminate\\Support\\Collection::slice\(\) expects int, float\|int given/'
# \Rebing\GraphQL\Support\ResolveInfoFieldsAndArguments::getValue
- '/Access to an undefined property GraphQL\\Language\\AST\\ValueNode::\$value/'
Copy link
Collaborator

Choose a reason for hiding this comment

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

This pretty cool and a very clear indicator that the current code was broken :/ Great 👍

if ($value instanceof VariableNode) {
$variableName = $value->name->value;

return $this->info->variableValues[$variableName] ?? null;
}
// Scalar Types
if ($value instanceof IntValueNode || $value instanceof FloatValueNode || $value instanceof StringValueNode || $value instanceof BooleanValueNode || $value instanceof EnumValueNode) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please break the lines: there are so many ORs, they really need to be better readable.

For simplicity, I suggest each one gets its own line:

        if ($value instanceof IntValueNode ||
            $value instanceof FloatValueNode ||
…

@crissi crissi mentioned this pull request Aug 9, 2019
Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

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

Thanks, looking very good 👍

}
// null Type
if ($value instanceof NullValueNode) {
return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

How strange, thanks!

* @param ValueNode $value
* @return mixed
* @throws \Exception
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Removed it

* @param ObjectValueNode $objectValueNode
* @return array
* @throws \Exception
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Removed it

* @param ListValueNode $listValueNode
* @return array
* @throws \Exception
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Removed it

use SqlAssertionTrait;

/**
* Fixed with https://github.com/rebing/graphql-laravel/pull/419.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I removed this reference; it would only have made sense for code which existing prior to this PR.

@mfn mfn merged commit edc0bd2 into rebing:master Aug 16, 2019
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