Hotchocolate: [Hydration] Is there any helper that collects the requested root fields and returns them as an array?

Created on 20 Aug 2019  ยท  7Comments  ยท  Source: ChilliCream/hotchocolate

I have a resolver that fetch a list of authors. Author's entity have many columns in database such as id, name, role, isActive, createdAt, updatedAt etc. However my GraphQL API exposes only three fields: id, name, role.

descriptor.Field(t => t.Authors)
    .Type<NonNullType<ListType<AuthorType>>>()
    .Resolver(ctx =>
    {
        <repository fetching stuff>
    }
}

To optimize the speed of the resolver, I want to request from the repository only the necessary columns, and not all in a row. Actually, the question arose: How can I get a list of requested fields from the ctx?

I know that in context there is a property ctx.FieldSelection.SelectionSet, and I can just select each item's name with Linq. But fragments can also act as fields. And then you need to read the whole scheme in search of this fragment and get a list of fields there.

Does the HotChocolate have any helper to solve this problem?

โ“ question

All 7 comments

Yes there is ... will post you some code later today

So the easiest way to do that is with our IResolverContext.CollectFields fields. This will pull in the fields that have to be resolved in the next level. There are two overloads that allow you to walk the graph and look at all the levels in all possible combinations. This will let you focus on what fields to fetch. CollectFields will compute @skip and @include and also resolve all fragments.

Did this answer help you? Can we close this issue or do you need more help on this one?

public class ArticleType : ObjectType<Article>
{
    protected override void Configure(IObjectTypeDescriptor<Article> descriptor)
    {
        <...>

        descriptor.Field(t => t.Authors)
            .Type<NonNullType<ListType<AuthorType>>>()
            .Resolver(ctx =>
            {
                var fields = ctx.CollectFields((ObjectType)ctx.Field.Type.NamedType());
                <...>
            });

        <...>
    }
}

Am I doing the right thing?

@acelot your example will work when ctx.Field.Type is an object type. If you have a union or an interface you can ask for all possible types ctx.Schema.GetPossibleTypes(cox.Field.Type.NamedType()).

With that you can ask for the fields of each case.

If you want to walk the graph further you can pass in any selectionSet to CollectFields and the type context for that selection set.

If you want to generalize your solution you can put that in a middleware and use it on multiple fields....

public class ArticleType : ObjectType<Article>
{
    protected override void Configure(IObjectTypeDescriptor<Article> descriptor)
    {
        <...>

        descriptor.Field(t => t.Authors)
            .Type<NonNullType<ListType<AuthorType>>>()
            .UseDynamicSQL();

        <...>
    }
}

https://hotchocolate.io/docs/middleware#field-middleware

With a middleware you could collect the fields and apply them onto IQueryable. If you need help with that we can guide you along.

Thanks for the detailed answer! :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

acelot picture acelot  ยท  4Comments

hognevevle picture hognevevle  ยท  3Comments

louisjrdev picture louisjrdev  ยท  3Comments

benmccallum picture benmccallum  ยท  5Comments

jbray1982 picture jbray1982  ยท  5Comments