loopback-graphql-relay
Version:
Add Relay based Apollo Server or GraphQL queries on your Loopback server
87 lines (69 loc) • 1.98 kB
JavaScript
const _ = require('lodash');
const utils = require('./utils');
/**
* Inspired by https://www.reindex.io/blog/relay-graphql-pagination-with-mongodb/
*/
function sortFilter(filter, order, before, idName) {
const end = utils.getId(before);
const idSort = idName + (end ? ' DESC' : ' ASC');
if (!order) {
filter.order = idSort;
} else {
filter.order = _.concat(order, idSort);
}
}
function limitFilter(model, filter, before, after, order, idName) {
let begin = after;
let end = before;
if (model.definition.settings['loopback-graphql-relay'] && model.definition.settings['loopback-graphql-relay'].idField) {
idName = model.definition.settings['loopback-graphql-relay'].idField;
} else {
begin = utils.getId(after);
end = utils.getId(before);
}
if (begin) {
filter.where[idName] = filter[idName] || {};
filter.where[idName].gt = begin;
}
if (end) {
filter.where[idName] = filter[idName] || {};
filter.where[idName].lt = end;
}
}
function applyPagination(filter, first, last, count) {
if (first || last) {
let limit;
let skip;
if (first && count > first) {
limit = first;
}
if (last) {
if (limit && limit > last) {
skip = limit - last;
limit -= skip;
} else if (!limit && count > last) {
skip = count - last;
}
}
if (skip) {
filter.skip = skip;
}
if (limit) {
filter.limit = limit;
}
}
return {
hasNextPage: Boolean(first && count > first),
hasPreviousPage: Boolean(last && count > last),
};
}
module.exports = function buildFilter(model, args) {
const idName = (model.getIdName && model.getIdName()) ? model.getIdName() : 'id';
const filter = {
where: args.where || {},
};
sortFilter(filter, args.order, args.before, idName);
limitFilter(model, filter, args.before, args.after, null, idName);
applyPagination(filter, args.first, args.last, args.count);
return filter;
};