objection-paginator
Version:
Paginated queries for Objection.js
106 lines • 3.54 kB
JavaScript
import _ from "lodash";
import { Cursor } from "./cursor.js";
import { InvalidCursorError } from "./invalid-cursor-error.js";
import { UnknownSortError } from "./unknown-sort-error.js";
import { createSortNode } from "./create-sort-node.js";
export class Paginator {
constructor(options = {}, ...rest) {
const { limit, sort } = options;
Object.defineProperties(this, {
limit: { value: limit || 1000, enumerable: true },
sort: { value: sort || "default", enumerable: true },
args: { value: rest[0], enumerable: true, writable: true },
});
}
static async getPage(options, ...rest) {
return new this(options, ...rest).execute(options && options.cursor);
}
static _getQueryName() {
return this.queryName || this.name;
}
static _createSortNodes() {
return this.sorts ? _.mapValues(this.sorts, createSortNode) : {};
}
static _getSortNodes() {
let nodes = this._sortNodes;
if (!nodes)
nodes = this._sortNodes = this._createSortNodes();
return nodes;
}
get _cls() {
return this.constructor;
}
async execute(cursor) {
const qry = this._getQuery(cursor);
const items = await qry;
const lastItem = _.last(items);
let remaining = 0;
if (lastItem) {
remaining = await this._getRemainingCount(qry, items.length);
cursor = this._createCursorString(lastItem);
}
else if (!cursor) {
cursor = this._createCursorString();
}
return { items, remaining, cursor };
}
_getSortNode() {
const node = this._cls._getSortNodes()[this.sort];
if (node)
return node;
throw new UnknownSortError({ info: { sort: this.sort } });
}
_createCursor(item) {
return new Cursor(this._cls._getQueryName(), this.sort, item && this._getSortNode().getCursorValues(item));
}
_createCursorString(item) {
return this._createCursor(item).serialize();
}
_validateCursor(cursor) {
const queryName = this._cls._getQueryName();
if (cursor.query !== queryName) {
throw new InvalidCursorError({
shortMessage: "Cursor is for a different query",
info: {
cursorQuery: cursor.query,
expectedQuery: queryName,
},
});
}
if (cursor.sort !== this.sort) {
throw new InvalidCursorError({
shortMessage: "Cursor is for a different sort",
info: {
cursorSort: cursor.sort,
expectedSort: this.sort,
},
});
}
return cursor;
}
_parseCursor(str) {
return this._validateCursor(Cursor.parse(str));
}
_getCursorValues(str) {
if (!_.isNil(str))
return this._parseCursor(str).values;
}
_applySortNode(qry, cursor) {
this._getSortNode().apply(qry, this._getCursorValues(cursor));
}
_applyLimit(qry) {
qry.limit(this.limit);
}
_getQuery(cursor) {
const qry = this.getBaseQuery();
this._applySortNode(qry, cursor);
this._applyLimit(qry);
return qry;
}
async _getRemainingCount(qry, itemCount) {
if (itemCount < this.limit)
return 0;
return await qry.resultSize() - itemCount;
}
}
//# sourceMappingURL=paginator.js.map