UNPKG

next-sql

Version:

Next-gen SQL connector, easy way to query SQL and create relationship linked object.

223 lines (208 loc) 5.5 kB
/** @typedef {import('./')} xsql */ /** @typedef {import('./').State} State */ /** @typedef {import('./array').ReadResult} ReadResult */ /** * @typedef {Object} PaginationOptions * @property {number} currPage [Default: 1] The current page * @property {number} rowStep [Default: 10] How many rows pre each page * @property {number} navStep [Default: 4] How many pages will shown on the navigation bar * @property {number} aLimit Database start index * @property {number} bLimit Database end index * @property {number} aPage Page start index * @property {number} bPage Page end index */ /** * @typedef {Object} PaginationNavButton * @property {number} page * @property {boolean} enable * @property {string} className */ /** * @typedef {Object} PaginationResult * @property {boolean} isOutOfRange * @property {number} currPage * @property {number} rowStep * @property {number} navStep * @property {Object} row * @property {number} row.from * @property {number} row.to * @property {Object} page * @property {number} page.from * @property {number} page.current * @property {number} page.to * @property {boolean} page.hasPrev * @property {boolean} page.hasNext * @property {Object} nav * @property {boolean} nav.hasPrev * @property {boolean} nav.hasNext * @property {PaginationNavButton[]} nav.buttons */ const classNames = require('classnames') const is = require('./is') /** * @memberof xsql * @this xsql * @param {PaginationOptions} options * @returns {xsql} */ function pagination(options) { if (is.plainObject(options)) { let { currPage, rowStep, navStep } = { currPage: 1, rowStep: 10, navStep: 4, ...options, } currPage = Number(currPage) rowStep = Number(rowStep) navStep = Number(navStep) let aLimit = 0 // Database start index let bLimit = 0 // Database end index let aPage = 0 // Page start index let bPage = 0 // Page end index if (currPage <= navStep) { aLimit = 0 bLimit = rowStep * (navStep + 1) aPage = 1 bPage = navStep } else { // p=13: 13/8=1.625 => floor=1 // p=25: 25/8=3.125 => floor=3 // floor=1: 1*8*10+10=90 // floor=3: 3*8*10+10=250 aLimit = (Math.floor((currPage - 1) / navStep) * navStep * rowStep) // 8*10+10*1=90 bLimit = navStep * rowStep + rowStep * 1 // p=13: 13/8=1.625 => floor=1 // p=25: 25/8=3.125 => floor=3 // floor=1: 1*8+1=9 // floor=3: 3*8+1=25 aPage = (Math.floor((currPage - 1) / navStep) * navStep) + 1 // 9: 9+8-1=16 // 25: 25+8-1=32 bPage = aPage + navStep - 1 } this._state.pagination = { currPage, rowStep, navStep, aLimit, bLimit, aPage, bPage, } } else { this._state.pagination = null } return this } /** @this xsql */ function paginationBefore() { const { aLimit, bLimit } = this._state.pagination this.offset(aLimit) this.limit(bLimit) } /** * @this xsql * @param {ReadResult} rows * @param {State} state */ function paginationAfter(rows, state) { const { pagination: { currPage, rowStep, navStep, aPage, }, } = state const totalPages = Math.ceil(rows.length / rowStep) const pageStartIndex = aPage const pageEndIndex = aPage + totalPages - 1 const rowStartIndex = ((currPage - 1) * rowStep) - navStep * rowStep * Math.floor((currPage - 1) / navStep) let rowEndIndex = rowStartIndex + rowStep - 1 if (rowEndIndex >= rows.length) { rowEndIndex = rows.length - 1 } const paginationRows = [] for (let i = rowStartIndex; i <= rowEndIndex; i++) { paginationRows.push(rows[i]) } const navCurrent = (Math.floor((currPage - 1) / navStep) + 1) const pageRealEnd = Math.min(...[navCurrent * navStep, pageEndIndex]) const paginationResult = { isOutOfRange: !paginationRows.length, currPage, rowStep, navStep, row: { record: { from: ((currPage - 1) * rowStep) + 1, to: currPage * rowStep, }, index: { from: ((currPage - 1) * rowStep), to: (currPage * rowStep) - 1, }, }, page: { from: pageStartIndex, current: currPage, to: pageRealEnd, hasPrev: currPage > 1, hasNext: currPage < pageEndIndex, }, nav: { current: navCurrent, hasPrev: navCurrent > 1, hasNext: pageEndIndex - pageStartIndex >= navStep, }, } const buttons = [] buttons.push({ value: currPage - 1, label: '«', className: classNames('page-prev', { disabled: !paginationResult.page.hasPrev, }), }) if (paginationResult.nav.hasPrev) { buttons.push({ value: pageStartIndex - 1, label: '...', className: 'nav-prev', }) } for (let i = pageStartIndex; i <= pageRealEnd; i++) { buttons.push({ value: i, label: `${i}`, className: classNames({ current: currPage === i, active: currPage === i, }), }) } if (paginationResult.nav.hasNext) { buttons.push({ value: pageEndIndex, label: '...', className: 'nav-next', }) } buttons.push({ value: currPage + 1, label: '»', className: classNames('page-next', { disabled: !paginationResult.page.hasNext, }), }) paginationResult.nav.buttons = buttons return { paginationRows, paginationResult, } } module.exports = { pagination, paginationBefore, paginationAfter, }