join-monster / join-monster

A GraphQL to SQL query execution layer for query planning and batch data fetching.

Home Page:http://join-monster.readthedocs.io/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for more complex orderBy statements

bradzacher opened this issue · comments

I'd love to be able to do something similar to where functions, where I can construct my own complex orderBy.

The problem is that right now if I want to do something as simple as:
ORDER BY -`table`.`field` DESC
I can't see a way to do this with JM without explicitly defining the field on the schema, and using alwaysFetch.

In the app I'm working on (we're converting an old code base to GraphQL), we default to natural ordering, but also allow users to explicitly order items, which means the sort field is usually null, unless it's explicitly set to a number (with 0 being the highest sort priority).

In MySQL, null comes before values in an ASC sort, and goes after values in a DESC sort.

So to achieve the desired functionality I need a DESC sort on the field, but this will sort with higher numbers being a higher sort priority.
This can be fixed by the above order by, with a - in front of it. But as stated this is unsupported in JM.

commented

Ah yes just as sqlExpr enables arbitrary SQL expressions in the selections, there should probably be an analogous orderExpr. There are nuisances like this one with the treatment of NULL and every SQL vendor handles it a little differently, e.g. MySQL with - and Postgres with NULLS FIRST/LAST. The only sane way to handle this is to allow arbitrary ORDER BY clauses.

This would be wonderful if you could implement such a thing! Support custom SQL functions like length, sum, ascii or what ever function databases support etc...

orderBy: {
LENGTH(${table}.field: 'ASC',
field: 'ASC'
}

Any progress on this? This would be a great feature.

I was able to resolve the same problem in a pretty 'hacky' way.

Join Monster actually accepts any string as a "field name" in the OrderBy array and does not check whether it is an actual field or not, so this means we can craft a long order by list in one single field.

The one caveat is that the string must START and END with a real field name. This is because Join Monster prepends the first part of the string with table. and then appends ASC (or whatever direction is set) at the end. Usually there is at least 1 or 2 fields that you can order by first/last which don't really affect the outcome - like say a status field, so we can do something like this (this was my exact example and it works great):

orderBy: {
    "TaskStatus` ASC, isnull(nullif(TaskDue, '0000-00-00 00:00:00')) ASC, `TaskDue": 'asc',
},

Notice where the back-ticks are to complete the full order-by string. Think of it like SQL injection 😄

The resulting query:

SELECT ...
ORDER BY `task`.`TaskStatus` ASC, isnull(nullif(TaskDue, '0000-00-00 00:00:00')) ASC, `TaskDue` ASC

Hopefully a more functional OrderBy feature will come soon anyway but this for now works fine.

That would be indeed great, I have the same issue currently with jsonb support, basically it should be possible to pass fields that are expressions, like "table"."field"->'jsonfield'
currently that is not possible as joinmonster add the extra quotes around which render then an invalid sql.