Polymorphic Absinthe

I want to add an orderBy argument to one of my resolvers, e.g.

users(orderBy: {name: DESC}) {...}

I do this by adding an input object,

input_object :user_sort do
  field :name, :asc_or_desc
 …

which is pretty much the same as my user object, e.g.

object :user do
      field :name, :string
     …

etc.

The question is, is there a way to map my many objects / types to ‘input objects’ for sorting?

Hey @mmport80,

This is a good question. Some of it comes down to how you want to model in the input. I think for situations like this, you probably don’t want to do an input object the way you are now.

The reason is that it implies you could do orderBy: {name: DESC, age: ASC}. The issue is, which column will be used to sort the collection first? Age or name? GraphQL input objects are unordered just like Elixir maps, name is not “before” age.

This points us in a direction of looking at a list, although then the next question of course is what do we want a list of? Doing a list of the current thing won’t help much cause you could still do orderBy: [{name: DESC, age: ASC}]. So instead let’s look at another approach:

orderBy: [{direction: DESC, value: NAME}, {direction: ASC, value: AGE}]

This lets you be a lot stricter about the types:

# on the field
arg :order_by, list_of(:user_order)

input_object :user_sort_order do
  field :direction, non_null(:sort_order_direction)
  field :column, non_null(:sortable_user_column)
end

enum :sort_order_direction, values: [:asc, :desc]

enum :sortable_user_column do
  value :name, as: :name
  value :age, as: :age
end

Now, for sure there’s some degree of duplication here in that you’ve got a variety of fields defined on your user type that you’ll also need to add to your :sortable_user_column enum. At the present moment there isn’t much of a good way around this without doing some pretty hacky stuff.

I’m not entirely convinced though that you want it to be dynamic. I think there’s value to having the explicit list of what can be sorted by, because pretty quickly in a lot of apps this won’t be everything.

6 Likes

V nicely explained, and big thanks for the tips and putting me on the right track!

Tbh, with a moderately sized API (and much more to come) I am feeling the weight of explicitness and also testing.

But I suppose this is something that can be tackled as more experience of GraphQL & Absinthe accumulates, might find new and sensible ways of approaching things…

Thanks again!

Yeah, I agree. Right now the mechanics of how we build schemas has certain limitations, but it’s the goal of Absinthe 1.5 to tackle these limitations. Once we’re done I think we could envision helpers like:

sortable_fields :user

# exclude some fields
sortable_fields :user, except: [:foo]

That sort of thing.

1 Like