@conpago/mongo-cursor-pagination
Version:
Make it easy to return cursor-paginated results from a Mongo collection
79 lines • 3.69 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const underscore_1 = __importDefault(require("underscore"));
const resolveFields_1 = __importDefault(require("./resolveFields"));
/**
* Normalize the given query parameter to an array, so we support both param=a,b and
* param[]=a¶m[]=b.
*
* @param {Object} query The parsed query object containing the given parameter.
* @param {String} param The parameter to normalize.
* @returns {String[]} The normalized array from the given query parameter.
* @throws {TypeError} When the query parameter isn't a string, an empty value, or an array of
* strings.
*/
function normalizeQueryArray(query, param) {
const value = query[param];
if (Array.isArray(value)) {
for (let i = 0; i < value.length; ++i) {
if (!underscore_1.default.isString(value[i])) {
throw new TypeError("expected string array or comma-separated string for " + param);
}
}
return value;
}
// This goes before _.isString so we don't split an empty string into ['']. The array option just
// uses whatever the user provides.
if (underscore_1.default.isEmpty(value)) {
return [];
}
if (underscore_1.default.isString(value)) {
return value.split(",");
}
throw new TypeError("expected string array or comma-separated string for " + param);
}
/**
* Sanitizes a `query` object received and merges it's changes to an optional `params` object
*
* @param {Object} query An object with the following properties:
* -limit: If a numeric string, use it as the limit. If limit also passed in params
* then this value cannot exceed it.
* -next: If a non-empty string, use it as the next cursor.
* -previous: If a non-empty string, use it as the previous cursor.
* -fields: If a non-empty string, used to limit fields that are returned. Multiple fields
* can be specified as a comma-delimited list. If field name used is not in params.fields,
* it will be ignored.
* @param {Object} params See documentation for `find()`, plus these options:
* -overrideFields: an object containing fields that should override fields from the querystring, e.g.
* {_id: 0} or {internalField: 1}. We only support field exclusion for _id, as we expect whitelists
* for fields from both params.fields and params.overrideFields.
*/
exports.default = (query, params) => {
params = params || {};
if (!underscore_1.default.isEmpty(query.limit)) {
const limit = parseInt(query.limit, 10);
// Don't let the user specify a higher limit than params.limit, if defined.
if (!isNaN(limit) && (!params.limit || params.limit > limit)) {
params.limit = limit;
}
}
if (!underscore_1.default.isEmpty(query.next)) {
params.next = query.next;
}
if (!underscore_1.default.isEmpty(query.previous)) {
params.previous = query.previous;
}
// Don't trust fields passed in the querystring, so whitelist them against the fields defined in
// parameters.
const fields = (0, resolveFields_1.default)(normalizeQueryArray(query, "fields"), params.fields, params.overrideFields);
if (fields === null) {
throw new TypeError("no valid fields provided");
}
// Set fields to undefined if it's empty to avoid adding _id: 0 in find.
params.fields = underscore_1.default.isEmpty(fields) ? undefined : fields;
return params;
};
//# sourceMappingURL=sanitizeQuery.js.map