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

Custom query is not called on Union type using relation field type. #900

Open
edgarsn opened this issue Feb 21, 2022 · 6 comments
Open

Custom query is not called on Union type using relation field type. #900

edgarsn opened this issue Feb 21, 2022 · 6 comments

Comments

@edgarsn
Copy link
Contributor

edgarsn commented Feb 21, 2022

Versions:

  • graphql-laravel Version: 7.2.0
  • Laravel Version: 8.42.1
  • PHP Version: 8.0.5

Description:

Custom query in relation field is not being triggered while using Union type.

Steps To Reproduce:

1. Union query
<?php

namespace App\GraphQL\Queries\Guide;

use App\Models\Channel;
use App\Models\LiveStream;
use Closure;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Str;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;

class LiveItemQuery extends Query
{
    /** @var array Query Attributes */
    protected $attributes = [
        'name' => 'LiveItem',
    ];

    /**
     * Result of query.
     */
    public function type(): Type
    {
        return GraphQL::type('LiveItemUnion');
    }

    /**
     * Arguments to filter query.
     *
     * @return array
     */
    public function args(): array
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::string()),
            ],
        ];
    }

    /**
     * Query data.
     *
     * @param mixed $root
     * @param array $args
     * @param mixed $context
     * @param ResolveInfo $info
     * @param Closure $getSelectFields
     * @return Channel|LiveStream|null
     */
    public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields)
    {
        if (Str::startsWith($args['id'], 'channel:')) {
            return Channel::find((int)Str::after($args['id'], 'channel:'));
        } else {
            return Livestream::find((int)$args['id']);
        }
    }
}
2. Union Type
<?php

declare(strict_types=1);

namespace App\GraphQL\Types\Guide;

use App\Models\Model;
use App\Models\Channel;
use App\Models\LiveStream;
use GraphQL;
use Rebing\GraphQL\Support\UnionType;

class LiveItemUnionType extends UnionType
{
    /**
     * @var string[]
     */
    protected $attributes = [
        'name' => 'LiveItemUnion',
    ];

    public function types(): array
    {
        return [
            GraphQL::type('LiveItem'),
            GraphQL::type('Channel'),
        ];
    }

    public function resolveType(Model $value): ?GraphQL\Type\Definition\Type
    {
        if ($value instanceof LiveStream) {
            return GraphQL::type('LiveItem');
        } elseif ($value instanceof Channel) {
            return GraphQL::type('Channel');
        } else {
            return null;
        }
    }
}
3. Model type (Where problem appers)
<?php

namespace App\GraphQL\Types\Guide;

use App\\Models\Channel;
use Carbon\Carbon;
use GraphQL\Type\Definition\Type;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Rebing\GraphQL\Support\Type as GraphQLType;

class ChannelType extends GraphQLType
{
    /** @var array Type attributes */
    protected $attributes = [
        'name' => 'Channel',
        'model' => Channel::class,
    ];

    /**
     * Field definition of type.
     *
     * @return array
     */
    public function fields(): array
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
            ],
            'guideItems' => [
                'type' => Type::listOf(\GraphQL::type('GuideItem')),
                'query' => function (array $args, $query, $ctx) {
			// this is never being called through UnionType!
                },
            ],
        ];
    }
}

My client query:

query {
    liveItem(id: "channel:1") {
        ... on LiveItem {
             id
        }
       ... on Channel {
             id
             guideItems {
                 title
             }
        }
    }
}

I Hope it helps. I don't know, if this is only related to version 7 or it's reproducible in version 8 as well.

@edgarsn edgarsn added the bug label Feb 21, 2022
@mfn
Copy link
Collaborator

mfn commented May 3, 2022

Seems SelectFields related.

To you want to attempt a PR to fix this?

If not, I would also only accepts tests showing the problem.

@edgarsn
Copy link
Contributor Author

edgarsn commented May 3, 2022

I'm on vacation in an hour, so no PR from me for now.

But here are tests - edgarsn@471a949

test_customQueryDoesntWorkWhenQueryUsingUnionType - failing example. It should return only 1 comment to post, but returns 2.
test_customQueryWorksWhenQueryTypeIsNotUnionType - this example shows custom query is working when query is returning simply PostType

@mfn
Copy link
Collaborator

mfn commented Jan 13, 2023

@edgarsn can you make a PR with the tests?

@edgarsn
Copy link
Contributor Author

edgarsn commented Jan 13, 2023

I don't think I'm capable of making fix for this. I can only make a draft PR with tests showing the bug, but it wouldn't help you a lot I guess.

From my observations SelectFields receives a list of all requested union fields without ability to detect on which Type that field belongs to since in UnionType there can be many types defined with the same field name.

For example,

query ($id: String!) {
  searchQuery(id: $id) {
    ... on Post {
        id
        title
        comments {
            id
        }
    }
    ... on Comment {
        id
        title
        body
    }
  }
}

SelectFields constructor $fieldsAndArguments would return:

array:4 [ // /app/src/Support/SelectFields.php:52
  "id" => array:3 [
    "type" => GraphQL\Type\Definition\NonNull^ {#3664
      ...
    }
    "fields" => []
    "args" => []
  ]
  "body" => array:3 [
    "type" => GraphQL\Type\Definition\StringType^ {#3305
      ...
    }
    "fields" => []
    "args" => []
  ]
  "title" => array:3 [
    "type" => GraphQL\Type\Definition\NonNull^ {#3665
      ...
    }
    "fields" => []
    "args" => []
  ]
  "comments" => array:3 [
    "type" => GraphQL\Type\Definition\NonNull^ {#3662
		...
    }
    "fields" => array:1 [
		...
    ]
    "args" => []
  ]
]

And here I'm confused how this could be solved. ID and Title is requested in two different fragments, but here they appear only once in this case.

I hope you understood the problem I'm saying and dealing with in my mind.

@mfn
Copy link
Collaborator

mfn commented Jan 14, 2023

I can only make a draft PR with tests showing the bug, but it wouldn't help you a lot I guess.

Au contraire! It would still be helpful! If you could contribute the tests showing the problem, that's already useful on its own!

@edgarsn
Copy link
Contributor Author

edgarsn commented Jan 14, 2023

I can only make a draft PR with tests showing the bug, but it wouldn't help you a lot I guess.

Au contraire! It would still be helpful! If you could contribute the tests showing the problem, that's already useful on its own!

Thank you! Will do on monday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants