@dakohhh/mongoose-paginator
Version:
Mongoose-Class-Paginator is a lightweight, flexible, and TypeScript-friendly pagination utility for Mongoose models. It provides a class-based approach to handling database pagination with support for filtering, sorting, population, projection, and metada
190 lines • 6.69 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Paginator = exports.MongoosePaginatorError = exports.CursorPaginator = exports.OffsetPaginator = exports.PageNumberPaginator = exports.BasePaginator = void 0;
const mongoose_1 = require("mongoose");
class BasePaginator {
constructor(model, args = { filter: {}, sort: { createdAt: -1 }, lean: true }) {
this.model = model;
this.args = args;
}
setArgs(args) {
this.args = args;
return this;
}
paginate() {
return __awaiter(this, void 0, void 0, function* () {
throw new MongoosePaginatorError('Method not implemented');
});
}
}
exports.BasePaginator = BasePaginator;
class PageNumberPaginator extends BasePaginator {
constructor(model, page = 1, limit = 10, args = { filter: {}, sort: { createdAt: -1 }, lean: true }) {
super(model, args);
this.page = page;
this.limit = limit;
}
getSkip() {
return (this.page - 1) * this.limit;
}
paginate() {
return __awaiter(this, void 0, void 0, function* () {
const skip = this.getSkip();
const query = this.model
.find(this.args.filter || {})
.sort(this.args.sort || { createdAt: -1 })
.skip(skip)
.limit(this.limit)
.populate(this.args.populate || [])
.select(this.args.projection || {});
// If the `lean` option is true, apply it to the query
if (this.args.lean) {
query.lean();
}
const [items, total] = yield Promise.all([
query,
this.model.countDocuments(this.args.filter || {}),
]);
const lastPage = Math.ceil(total / this.limit);
const currentPage = this.page;
return {
data: items,
meta: {
total,
lastPage,
currentPage,
perPage: this.limit,
prev: currentPage > 1 ? currentPage - 1 : null,
next: currentPage < lastPage ? currentPage + 1 : null,
},
};
});
}
setPage(page) {
this.page = page;
return this;
}
setLimit(limit) {
this.limit = limit;
return this;
}
setArgs(args) {
this.args = args;
return this;
}
}
exports.PageNumberPaginator = PageNumberPaginator;
class OffsetPaginator extends BasePaginator {
constructor(model, offset, limit, args = { filter: {}, sort: {}, lean: true }) {
if (offset % limit !== 0) {
throw new MongoosePaginatorError(`Offset must be a multiple of limit)`);
}
super(model, args);
this.offset = offset;
this.limit = limit;
}
setOffset(offset) {
this.offset = offset;
return this;
}
setLimit(limit) {
this.limit = limit;
return this;
}
paginate() {
return __awaiter(this, void 0, void 0, function* () {
const query = this.model
.find(this.args.filter || {})
.sort(this.args.sort)
.skip(this.offset)
.limit(this.limit)
.populate(this.args.populate || [])
.select(this.args.projection || {});
if (this.args.lean) {
query.lean();
}
const [items, total] = yield Promise.all([
query,
this.model.countDocuments(this.args.filter || {}),
]);
const lastPage = Math.ceil(total / this.limit);
const currentPage = Math.floor(this.offset / this.limit) + 1;
return {
data: items,
meta: {
total,
lastPage,
currentPage,
perPage: this.limit,
prev: currentPage > 1 ? currentPage - 1 : null,
next: currentPage < lastPage ? currentPage + 1 : null,
},
};
});
}
}
exports.OffsetPaginator = OffsetPaginator;
class CursorPaginator extends BasePaginator {
constructor(model, cursor, limit, args = { filter: {}, lean: true }) {
super(model, args);
this.cursor = cursor;
this.limit = limit;
}
setCursor(cursor) {
this.cursor = cursor;
return this;
}
setLimit(limit) {
this.limit = limit;
return this;
}
paginate() {
return __awaiter(this, void 0, void 0, function* () {
const filter = Object.assign({}, this.args.filter);
if (this.cursor) {
filter._id = { $gt: new mongoose_1.Types.ObjectId(this.cursor) };
}
const query = this.model
.find(filter)
.sort({ _id: 1 })
.limit(this.limit)
.populate(this.args.populate || [])
.select(this.args.projection || {});
if (this.args.lean) {
query.lean();
}
const items = yield query;
const lastItem = items[items.length - 1];
return {
data: items,
meta: {
nextCursor: lastItem ? (String(lastItem._id)) : null,
},
};
});
}
}
exports.CursorPaginator = CursorPaginator;
class MongoosePaginatorError extends Error {
constructor(message) {
super(message);
this.name = 'MongoosePaginatorError';
}
}
exports.MongoosePaginatorError = MongoosePaginatorError;
/**
* @deprecated Please use `PageNumberPaginator` instead.
* This will be removed in version 1.1.
*/
const PaginatorDeprecationNotice = PageNumberPaginator;
exports.Paginator = PaginatorDeprecationNotice;
//# sourceMappingURL=index.js.map