Lighthouse: Implement orderBy [DESC, ASC] that can be controlled through an argument

Created on 21 Jan 2019  路  15Comments  路  Source: nuwave/lighthouse

How to implement ordeBy functionality using GraphQL with the nuwave / lighthouse dependency?
I searched in several forums, without example events

enhancement

Most helpful comment

I'd vote for a flexible solution with supports sorting by multiple fields. e.g:

query {
  users(orderBy: ["firstName:desc", "lastName:desc"]) {
    firstName,
    lastName
  }
}

Which would be untyped though.

Typed version could look like:

type Query {
  users(orderBy: [SortOption!]! @orderBy): [User!]!
}

input SortOption {
  field: String
  order: SortOrder
}

enum SortOrder {
  ASC
  DESC
}
query {
  users(orderBy: [{field: "firstName", order: DESC}, {field: "lastName", order: DESC]) {
    firstName,
    lastName
  }
}

All 15 comments

You can do that easily with any custom resolver, using a defined argument to control the query.

If you want a reusable way that works with the built-in resolvers that Lighthouse offers, you can go for a custom ArgFilterDirective, similar to https://github.com/nuwave/lighthouse/blob/master/src/Schema/Directives/Args/EqDirective.php

It should be pretty simple to implement an @orderBy directive, accepting PRs.

@spawnia Considering paginate/ filters / order is a common stuff, do you think is useful to provide it from Lighthouse core? Would be hard to implement it with one shot (all in one) ?

Usually paginate / filter / order lives together.

I think we should have it in the core.

It should be fairly simple to implement orderBy, considering @paginate and the ArgumentFilterDirective class already exist.

How about this syntax:

type Query {
  posts(orderByTimePosted: SortOrder @orderBy): [Post!]!
}

enum SortOrder {
  ASC
  DESC
}

So, SortOrder would be a builtin scalar?

Any update on this?

How about this: https://gist.github.com/Arkitecht/6ec3a9e850273214d7803093271ef625

Can be used by:

users(
        order_by: String @orderBy
    ): [User!]! @all

and called with:

query {
  users(order_by:"last_name") {
    first_name,
    last_name
  }
}

OR

query {
  users(order_by:"last_name,desc") {
    first_name,
    last_name
  }
}

I'd vote for a flexible solution with supports sorting by multiple fields. e.g:

query {
  users(orderBy: ["firstName:desc", "lastName:desc"]) {
    firstName,
    lastName
  }
}

Which would be untyped though.

Typed version could look like:

type Query {
  users(orderBy: [SortOption!]! @orderBy): [User!]!
}

input SortOption {
  field: String
  order: SortOrder
}

enum SortOrder {
  ASC
  DESC
}
query {
  users(orderBy: [{field: "firstName", order: DESC}, {field: "lastName", order: DESC]) {
    firstName,
    lastName
  }
}

@jbbr's approach seems pretty clean.

Could SortOrder and SortOption be built in?

I've been trying to build my own implementation for this, but i'm stuck. I've added the Directive in the Directives folder but it does not apply its logic.

<?php


namespace App\Http\Graphql\Directives;


use Illuminate\Database\Eloquent\Builder;
use Nuwave\Lighthouse\Support\Contracts\ArgFilterDirective;

/**
 * Class OrderBy
 *
 * @package App\Http\Graphql\Directives
 */
class OrderByDirective implements ArgFilterDirective
{

    /**
     * @param  \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder
     * @param  string                                                                   $columnName
     * @param  mixed                                                                    $value
     *
     * @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
     */
    public function applyFilter($builder, string $columnName, $value)
    {
        return $builder->orderBy($columnName, $value);
    }

    /**
     * Does this filter combine the values of multiple input arguments into one query?
     *
     * This is true for filter directives such as "whereBetween" that expects two
     * different input values, given as separate arguments.
     *
     * @return bool
     */
    public function combinesMultipleArguments(): bool
    {
        return false;
    }

    /**
     * Name of the directive.
     *
     * @return string
     */
    public function name()
    {
        return 'orderBy';
    }
}
input SortOption {
    field: String!
    order: SortOrder!
}

enum SortOrder {
    ASC
    DESC
}

type Query{
    suppliers(sortOptions: [SortOption!]! @orderBy): [Supplier!]  @paginate
}

When I test it with xdebug, it never hits the applyFilter function. Do I need to register it somewhere? When I add a constructor and place a breakpoint inside of it, it breaks multiple times. So the directive is found. Also, the schema is valid according to artisan lighthouse:validate-schema

@megawubs can you try without @paginate using something like @all instead?

@spawnia When I remove @paginate and add @all the @orderBy Directive is still not applied

Using dev-master?

Yes, because the project is uses Laravel 5.8

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexwhb picture alexwhb  路  4Comments

m1guelpf picture m1guelpf  路  3Comments

Leuloch picture Leuloch  路  3Comments

vine1993 picture vine1993  路  3Comments

spawnia picture spawnia  路  4Comments