0

我的问题涉及如何构建复杂的自定义解析器,以及为什么它们不能很好地与内置解析器配合使用。我找不到任何关于复杂解析器的好例子,而我的真实案例比这个例子还要复杂。

我有以下架构

type Query {
    users: [User!]! @field(resolver: "App\\Library\\UserController@fetchAll")
    posts: [Post!]! @field(resolver: "App\\Library\\PostController@fetchAll")
    post(id: Int! @eq): Post @find
}

type User {
    id: ID!
    name: String
    posts: [Post!]!  @field(resolver: "App\\Library\\PostController@fetchAll")
}

type Post {
    id: ID!
    content: String!
    comments: [Comment] @field(resolver: "App\\Library\\CommentController@fetchAll")
}

type Comment {
    id: ID!
    reply: String!
commentRating: [CommentRating] @field(resolver: “App\\Library\\CommentRatingController@fetchSum")
}

type CommentRating {
    id: ID!
    rating: String
}

例如我有这个查询

{
  users {
    id,
    name
    posts {
      title
      comments {
        id,
        reply
        
      }
    }
  }
}

由于业务逻辑,我需要自定义解析器,但不是全部。以上工作(我故意为所有这些使用自定义解析器,我会稍微解释一下)但前提是我在第一个被正确调用的解析器中构建我的雄辩查询。像这样

// Function in custom resolver. All other custom resolver which are accessed can just pass the $rootValue on, or operate on it.
public function fetchAll($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
// We have some more sophisticated logic to dynamically build the array parameter on the line below, because the query may not always request comments, which means 'posts.comments' wont be needed. As this is the entrypoint, $rootValue is empty
    $t = User::with['posts', 'posts.comments', 'posts.comments.ratings'])->get();

    // Business logic modules called here
        return $t;
}

如果我从自定义解析器开始,但查询中的某些内容使用了内置解析器,例如,如果更改

type User {
    id: ID!
    name: String
    posts: [Post!]!  @field(resolver: "App\\Library\\PostController@fetchAll")
}

type User {
    id: ID!
    name: String
    posts: [Post!]!  @all
}

然后它仍然可以正常运行,但引入了 N+1 问题。因此,我可以在我的 mysql 日志中看到突然运行多个查询,如果我只有自定义或仅内置解析器,则不会发生这种情况。让自定义解析器调用内置解析器是不好的做法吗?

最好只为我的所有类型坚持自定义解析器吗?我构建自定义解析器的方法是否正确?(参考公共函数fetchAll代码片段)

4

3 回答 3

1

您可以在您的架构中映射您的解析器类,例如

type Query {
    users: [User] @field(resolver: "App\\GraphQL\\Queries\\User@FooFunction")
}

并使用此命令生成此查询解析器类:

php artisan lighthouse:query User

并将您喜欢的每个查询放在这个名为 FooFunction 的函数上:

<?php

namespace App\GraphQL\Queries;

use Carbon\Carbon;
use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Support\Facades\DB;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;

class User
{
    /**
     * Return a value for the field.
     *
     * @param  null  $rootValue Usually contains the result returned from the parent field. In this case, it is always `null`.
     * @param  mixed[]  $args The arguments that were passed into the field.
     * @param  \Nuwave\Lighthouse\Support\Contracts\GraphQLContext  $context Arbitrary data that is shared between all fields of a single query.
     * @param  \GraphQL\Type\Definition\ResolveInfo  $resolveInfo Information about the query itself, such as the execution state, the field name, path to the field from the root, and more.
     * @return mixed
     */
    public function FooFunction($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
    {
        return
            DB::table('...')
              ->where(...)
              ->get();
    }
}

于 2020-06-24T15:03:53.027 回答
0

Lighthouse 提供了诸如@hasOne、@hasMany、@belongsTo 之类的指令来防止 N+1 问题。您需要做的就是使用它们。

https://lighthouse-php.com/master/eloquent/relationships.html#avoiding-the-n-1-performance-problem

于 2020-06-24T14:31:55.717 回答
0

答案有点晚,但问题是我没有完全理解 graphql 模型。自定义解析器纯粹需要发回正确类型的模型,以便架构可以理解它。我的解析器没有返回正确的类型。

于 2020-12-14T09:00:07.933 回答