Blog Post Image
20 August, 2021

Lighthouse upgrade - 'Order by' issue

Icon

Luigi Laezza

Continuing our experience with the use of GraphQL + Laravel Nova and Lighthouse, the time has come to update Lighthouse (from version 4 to version 5) since upgrading to Nova 3.0 required at least version five for Lighthouse. In this sense, some changes in this framework would make us have some problems with the queries sent by the client.

As soon as we performed the update, the application started to behave in a typical way, and when we accessed Lighthouse's Upgrade Guide, it became clear what our problem was. As of version 5, the argument that determined which column would be used to perform the ordering (orderBy) had changed:

{
    posts (
        orderBy: [
            {
-               field: POSTED_AT
+               column: POSTED_AT
                order: ASC
            }
        ]
    ) {
        title
    }
}

Where we used the 'column' argument before, it should now be modified by 'field'. At this point, the project that was already implemented and in operation did not allow us, due to contractual obligations, to modify the structure or even the arguments of these queries that arrived in our application, we had to find a way around this. As the update guide itself indicates, we then use an ArgManipulator directive.

Following the documentation, what we've done is create a new directive using the OrderBy directive as the basis, and we've applied the following modification to the handleBuilder method:

/**
     * @param  array<array{field: string, order: string}>  $value
     */
    public function handleBuilder($builder, $value): object
    {
        foreach ($value as $orderByClause) {
            $builder->orderBy(
                $orderByClause['field'],
                $orderByClause['order']
            );
        }

        return $builder;
    }

Next, you should update your "schema.graphql" file by declaring the new directive we created and including the inputs we will use from now on:

directive @orderByOld on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION

input OrderByOldClause{
field: String!    
order: SortOrder!
}
enum SortOrder {
    ASC
    DESC
}

Now, just modify your query declaring now the new directive that we created (@orderByOld):

extend type Query  {
    notifications(
        count: Int!
        business_id: ID @where(operator: "=")
        orderBy: [OrderByOldClause!] @orderByOld
    ): [Notification!]! @paginate(defaultCount: 30, type: "paginator" model: "App\\Models\\Notification")

Done! Now your application will work perfectly even if the query sent by the client does not have the 'field' argument, the response will be ordered as requested.

This technique can be used to modify any argument you need in the same direction.