Issues with $sort and createQuery/._find
0This may be more of a breadcrumb for others having this issue than an actual bug report, though perhaps documentation can be improved.
I was trying to modify the incoming query in a service hook, and noticed that the $sort param was not being respected properly when passed into context.service.createQuery. I had similar results using context.service.find. Note that i am using postgres via the feathers-knex provider.
When sending (from the REST client) a query like
$select: [
"record_id",
"title",
],
$limit: PAGE_SIZE,
$skip: offset,
$sort: { title: 1 },
};
and then in my hook, creating a query using context.service.createQuery(context.params) (or with context.service._find(context.params), I noticed that the sort on title was always desc regardless of what I specified in the $sort parameter. After digging around, I found https://github.com/feathersjs/feathers/blob/dove/packages/knex/src/adapter.ts#L153
if (filters.$sort) {
return Object.keys(filters.$sort).reduce(
(currentQuery, key) => currentQuery.orderBy(key, filters.$sort[key] === 1 ? 'asc' : 'desc'),
builder
)
}
in the knex provider code. It seems that integers are converted into strings when passed into the API, so I was ending up with $sort: { title: "1" } which of course was failing the === 1 test.
Upon further digging, I found a pretty acceptable workaround by passing params into the (undocumented) context.service.sanitizeQuery method like so:
const params = {
...context.params,
query: await context.service.sanitizeQuery(context.params)
};
context.service.createQuery(params);
this results in the $sort param (and perhaps others) being properly interpreted.
I can definitely see why you might not want to pass the query arg to ._find or createQuery through sanitizeQuery by default, but maybe a note could be added to the docs pointing this behavior out?
Are you using the REST adapter? This smells like the aged old problem of URL query parameters not being validated. Something as simple as ?order=1 will parse the query parameter as "1", similar for other natives like "true". The REST protocol doesn't specify how to handle various types in the URL. You should use a Feathers schema to validate the query, which will also cast it to its proper types.
Yes,, I am using the REST adapter. Isn't passing the context.params through context.service.sanitizeQuery essentially running the params through the standard schema validator? Is there a better way to run the params through a schema?
https://feathersjs.com/api/schema/validators.html#validatequery