Feat ordering by associated models now works

It's now possible to order by associated models. This technically might
have worked before b/c we were parsing JSON sent to `order`, but I'm
pretty sure it wouldn't actually work b/c we never grabbed the actual
model to associate by. Regardless, this actually enables things and adds
tests to prove it.

Note: there's a sequelize bug that's poorly reported but definitely
known where `order` with associated models can fail because the sql
generated doesn't include a join. So, I added docs noting that and a
`test.failing` so that we'll be notified when that bug is fixed and can
remove the note.
This commit is contained in:
Joey Baker
2016-10-31 12:48:34 -07:00
parent e1b851f932
commit c289fb2ed4
4 changed files with 112 additions and 22 deletions

View File

@ -3,21 +3,27 @@ import { notImplemented } from 'boom';
const sequelizeKeys = ['include', 'order', 'limit', 'offset'];
const getModels = (request) => {
const noGetDb = typeof request.getDb !== 'function';
const noRequestModels = !request.models;
if (noGetDb && noRequestModels) {
return notImplemented('`request.getDb` or `request.models` are not defined.'
+ 'Be sure to load hapi-sequelize before hapi-sequelize-crud.');
}
const { models } = noGetDb ? request : request.getDb();
return models;
};
export const parseInclude = request => {
const include = Array.isArray(request.query.include)
? request.query.include
: [request.query.include]
;
const noGetDb = typeof request.getDb !== 'function';
const noRequestModels = !request.models;
if (noGetDb && noRequestModels) {
return notImplemented('`request.getDb` or `request.models` are not defined.'
+ 'Be sure to load hapi-sequelize before hapi-sequelize-crud.');
}
const { models } = noGetDb ? request : request.getDb();
const models = getModels(request);
if (models.isBoom) return models;
return include.map(a => {
const singluarOrPluralMatch = Object.keys(models).find((modelName) => {
@ -63,24 +69,40 @@ export const parseLimitAndOffset = (request) => {
return out;
};
const parseOrderArray = (order, models) => {
return order.map((requestColumn) => {
if (Array.isArray(requestColumn)) {
return parseOrderArray(requestColumn, models);
}
let column;
try {
column = JSON.parse(requestColumn);
} catch (e) {
column = requestColumn;
}
if (column.model) column.model = models[column.model];
return column;
});
};
export const parseOrder = (request) => {
const { order } = request.query;
if (!order) return null;
const models = getModels(request);
if (models.isBoom) return models;
// transform to an array so sequelize will escape the input for us and
// maintain security. See http://docs.sequelizejs.com/en/latest/docs/querying/#ordering
if (isString(order)) return [order.split(' ')];
const requestOrderColumns = isString(order) ? [order.split(' ')] : order;
for (const key of Object.keys(order)) {
try {
order[key] = JSON.parse(order[key]);
} catch (e) {
//
}
}
const parsedOrder = parseOrderArray(requestOrderColumns, models);
return [order];
return parsedOrder;
};
export const getMethod = (model, association, plural = true, method = 'get') => {