GraphQL: Apply resolver to nested relationship

Hey!

Say I have many Users, and each User has many Posts.

The schema is as follows:

type User {
  name: String!
  posts: [Post!] @relation
  ...
}

input UserFilterInput {
  name: String
}

enum PostType {
  TEXT
  IMAGE
}

type Post {
  type: PostType!
  author: User! @relation
  ...
}

input PostFilterInput {
  type: PostType
}

type Query {
  findUsersCustom(filter: UserFilterInput!): [User!] @resolver(name: "findUsersCustom", paginated: true)
  findPostsCustom(filter: PostFilterInput!): [Post!] @resolver(name: "findPostsCustom", paginated: true)
}

Now, with my custom UDF findPostsCustom, I can query posts filtered by type like so:

query FindPostsCustom($filters: PostFilterInput!, $size: Int!, $cursor: String) {
  findPostsCustom(filters: $filters, _size: $size, _cursor: $cursor) {
    ...
  }
}

This is great, however, what I would really like to do, is apply the same UDF as a resolver for posts in the findUsersCustom query – which would allow me to do something like so:

query FindUsersCustom($userFilters: UserFilterInput!, $userSize: Int!, $userCursor: String, $postFilters: PostFilterInput!, $postSize: Int!, $postCursor: String) {
  findUsersCustom(filters: $userFilters, _size: $userSize, _cursor: $userCursor) {
    after
    data {
      posts (filters: $postFilters, _size: $postSize, _cursor: $postCursor) {
        ...
      }
    }
  }
}

Is this possible at all?

If this isn’t possible, what’s the best way to achieve this?

Is the only option to simply seperate the queries like so?
(1) Fetch filtered users
(2) Then, for each user, fetch filtered posts

Thanks!

** Update **
After reading this post, looks as though the feature I’m after is being considered, but not yet implemented :frowning:

Hi @ryanpwaldon! We have an open feature request to allow custom resolvers on user-defined types: Allow @resolver directive in user-defined types’ fields

That’s what would allow you to specify your custom arguments for posts in your second query.

We recognize that the feature request here in the forums is a couple of years old now. While we have prioritized other work, and I cannot promise when we can get to this, I know it is still very much on our radar.

To continue forward now, what you do may depend on what data your application actually needs from these queries.

For example, if you need to fetch the user data at the same time, then I think it makes sense to make two queries:

  1. Fetch filtered user
  2. For each user, fetch filtered posts

If, however, you don’t need user details as part of this query, then you could create a custom resolver that filters users and uses Join to return only the related posts.

type Query {
  findUserPostsCustom(userFilters: UserFilterInput!, postFilters: PostFilterInput!): [Post]!
      @resolver(name: "findUserPostsCustom", paginated: true)
}
query FindUserPostsCustom($userFilters: UserFilterInput!, $postFilters: PostFilterInput!, $size: Int!, $cursor: String) {
  findUserPostsCustom(userFilters: $userFilters, postFilters: $postFilters, _size: $size, _cursor: $cursor) {
    after
    data {
      _id

      # include Author ID so that you can link back to it.
      # but don't get other fields, because that would potentially be a lot of redundant data
      author: { _id } 

      # ... more Post fields
    }
  }
}

Side note about paginated types

the type [User!] won’t do what you think it does – this type is a nullable List of NonNull User. However, Fauna will replace it with type UserPage { data: [User]! } in order to reflect the actual data type. Note that data is now a NonNull List of nullable User. You cannot enforce a different nullability scheme on paginated types

You can specify the arrangement of NonNull that you want for other types like scalars and Lists of @embedded types, e.g. [Thing], [Thing!], [Thing]!, or [Thing!]!]