3

I am using SearchObject with GraphQL in Ruby on Rails and created an option called :order_by

option :order_by, type: LinksOrderBy, with: :apply_order_by

The type LinksOrderBy is defined by this:

class LinksOrderBy < ::Types::BaseInputObject
  argument :created_at, AscDescEnum, required: false
  argument :description, AscDescEnum, required: false
  argument :id, AscDescEnum, required: false
  argument :updated_at, AscDescEnum, required: false
  argument :url, AscDescEnum, required: false
end

But when I try something like this in GraphQL query:

{allLinks(order_by:{id: asc, description: desc}) {
    id
    description
}}

I don't get it in the right order:

def apply_order_by(scope, value)
  scope.order(value.arguments.to_h.map{|k, v| k + ' ' + v}.join(', ')) # "description desc, id asc"
end

As you can see the right order should be "id, description", not "description, id".

Arthur Felipe
  • 1,404
  • 1
  • 13
  • 20

1 Answers1

3

The ruby Hash instances are not ordered (see Is order of a Ruby hash literal guaranteed?)


To leverage the optional multi sorting options in GraphQL input types, I usually use the following structure:

  • 1 enum to contain all filterable/sortable/searchable field of a resource (ex: UserField)
  • 1 enum to contain the 2 sort directions (asc and desc)
  • 1 field accepting an optional list of { field: UserField!, sortDir: SortDir! } inputs.

This then enables the API consumers to simply do queries like:

allUsers(sort_by: [{field: username, sortDir: desc}, {field: id, sortDir: asc}]) {
  # ...
}

And this pattern can be easily re-used for searching and filtering:

allUsers(search: [{field: username, comparator: like, value: 'bob'}]) {}
allUsers(search: [{field: age, comparator: greater_than, value: '22'}]) {} # type casting is done server-side
allUsers(search: [{field: username, comparator: equal, value: 'bob'}]) {} # equivalent of filtering

Eventually, with further deeper work you can allow complex and/or for the input:

allUsers(
  search: [
    {
      left: {field: username, comparator: like, value: 'bob'}
      operator: and
      right: {field: dateOfBirth, comparator: geater_than, value: '2001-01-01'}
    }
  ]
)

Disclaimer: the last example above is one of the many things I want to implement in my GQL API but I haven't had the time to think it through yet, it's just a draft

MrYoshiji
  • 54,334
  • 13
  • 124
  • 117