2020-09-08 07:15:47 +03:00
|
|
|
const _ = require('lodash');
|
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
const orderPlugin = function orderPlugin(Bookshelf) {
|
2020-09-08 07:15:47 +03:00
|
|
|
Bookshelf.Model = Bookshelf.Model.extend({
|
|
|
|
orderAttributes() {},
|
2020-12-03 23:13:37 +03:00
|
|
|
orderRawQuery() {},
|
2020-09-08 07:15:47 +03:00
|
|
|
|
|
|
|
parseOrderOption: function (orderQueryString, withRelated) {
|
2020-12-03 23:13:37 +03:00
|
|
|
const order = {};
|
|
|
|
const orderRaw = [];
|
|
|
|
const eagerLoadArray = [];
|
2020-09-08 07:15:47 +03:00
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
const orderAttributes = this.orderAttributes();
|
2020-09-08 07:15:47 +03:00
|
|
|
if (withRelated && withRelated.indexOf('count.posts') > -1) {
|
|
|
|
orderAttributes.push('count.posts');
|
|
|
|
}
|
2020-11-02 14:15:24 +03:00
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
let rules = [];
|
2020-11-02 14:15:24 +03:00
|
|
|
// CASE: repeat order query parameter keys are present
|
|
|
|
if (_.isArray(orderQueryString)) {
|
|
|
|
orderQueryString.forEach((qs) => {
|
|
|
|
rules.push(...qs.split(','));
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
rules = orderQueryString.split(',');
|
|
|
|
}
|
2020-09-08 07:15:47 +03:00
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
_.each(rules, (rule) => {
|
2020-09-08 07:15:47 +03:00
|
|
|
let match;
|
|
|
|
let field;
|
|
|
|
let direction;
|
|
|
|
|
|
|
|
match = /^([a-z0-9_.]+)\s+(asc|desc)$/i.exec(rule.trim());
|
|
|
|
|
|
|
|
// invalid order syntax
|
|
|
|
if (!match) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
field = match[1].toLowerCase();
|
|
|
|
direction = match[2].toUpperCase();
|
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
const orderRawQuery = this.orderRawQuery(field, direction, withRelated);
|
|
|
|
|
|
|
|
if (orderRawQuery) {
|
|
|
|
orderRaw.push(orderRawQuery.orderByRaw);
|
|
|
|
if (orderRawQuery.eagerLoad) {
|
|
|
|
eagerLoadArray.push(orderRawQuery.eagerLoad);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-24 04:32:40 +03:00
|
|
|
const matchingOrderAttribute = orderAttributes.find((orderAttribute) => {
|
|
|
|
// NOTE: this logic assumes we use different field names for "parent" and "child" relations.
|
|
|
|
// E.g.: ['parent.title', 'child.title'] and ['child.title', 'parent.title'] - would not
|
|
|
|
// distinguish on which relation to sort neither which order to pick the fields on.
|
|
|
|
// For more context see: https://github.com/TryGhost/Ghost/pull/12226#discussion_r493085098
|
|
|
|
return orderAttribute.endsWith(field);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!matchingOrderAttribute) {
|
2020-09-08 07:15:47 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
order[matchingOrderAttribute] = direction;
|
2020-09-08 07:15:47 +03:00
|
|
|
});
|
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
return {
|
|
|
|
order,
|
|
|
|
orderRaw: orderRaw.join(', '),
|
|
|
|
eagerLoad: _.uniq(eagerLoadArray)
|
|
|
|
};
|
2020-09-08 07:15:47 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-12-03 23:13:37 +03:00
|
|
|
module.exports = orderPlugin;
|