UNPKG

drf-paginator

Version:

Module for consuming paginated Django REST framework endpoints.

113 lines (85 loc) 2.45 kB
import _ from 'lodash'; import * as actions from '../actions'; import PaginatorError from '../paginator-error'; export const errors = Object.freeze({ calculateOffsetNoLimit: 'Can\'t calculate offsets without a limit', calculatePageNoLimit: 'Can\'t calculate pages without a limit' }); const defaultOptions = { limitQueryParam: 'limit', offsetQueryParam: 'offset' }; export class LimitOffsetQueryHandler { constructor(options) { this._excessParams = null; this._limit = null; this.setOptions(options); } makeParams(page) { const opts = this._options; const queryParams = _.assign({}, this._excessParams); queryParams[opts.limitQueryParam] = this._limit; queryParams[opts.offsetQueryParam] = this._calculateOffset(page); return queryParams; } resolvePage(queryParams) { const {offset, limit} = this._parse(queryParams); if (offset === 0) { return 1; } if (!limit) { throw new PaginatorError(errors.calculatePageNoLimit); } return (offset + limit) / limit; } setParams(queryParams) { const result = this._parse(queryParams); this._excessParams = result.excess; this._limit = result.limit; return this; } onResponse(response, page) { if (page === 1 && !this._limit) { this._limit = actions.inferLimit(response); } } setOptions(options) { this._options = _.assign({}, defaultOptions, options); return this; } _parse(queryParams) { const {limitQueryParam, offsetQueryParam} = this._options; const defaults = { limit: null, offset: 0 }; const result = _.assign({}, defaults); if (queryParams.hasOwnProperty(limitQueryParam)) { result.limit = queryParams[limitQueryParam]; } if (queryParams.hasOwnProperty(offsetQueryParam)) { result.offset = queryParams[offsetQueryParam]; } result.excess = this._getExcess(queryParams); return result; } _getExcess(queryParams) { const opts = this._options; const paginationProperties = [ opts.limitQueryParam, opts.offsetQueryParam ]; return _.omit(queryParams, paginationProperties); } _calculateOffset(page) { const limit = this._limit; if (page === 1) { return 0; } if (!limit) { throw new PaginatorError(errors.calculateOffsetNoLimit); } return limit * page - limit; } } export default LimitOffsetQueryHandler;