@hosoft/restful-api-framework
Version:
Base framework of the headless cms HoServer provided by http://helloreact.cn
140 lines (118 loc) • 4.22 kB
JavaScript
/* eslint-disable no-prototype-builtins */
const Promise = require('bluebird')
/**
* @param {Object} [query={}]
* @param {Object} [options={}]
* @param {Object|String} [options.select]
* @param {Object|String} [options.sort]
* @param {Object|String} [options.customLabels]
* @param {Object|} [options.collation]
* @param {Array|Object|String} [options.populate]
* @param {Boolean} [options.lean=false]
* @param {Boolean} [options.leanWithId=true]
* @param {Number} [options.offset=0] - Use offset or page to set skip position
* @param {Number} [options.page=1]
* @param {Number} [options.limit=10]
* @param {Function} [callback]
*
* @returns {Promise}
*/
function paginate(query, options, callback) {
query = query || {}
options = Object.assign({}, paginate.options, options)
options.customLabels = options.customLabels ? options.customLabels : {}
const select = options.select
const sort = options.sort
const collation = options.collation
const populate = options.populate
const lean = options.lean || false
const leanWithId = options.hasOwnProperty('leanWithId') ? options.leanWithId : false
const limit = options.hasOwnProperty('limit') ? options.limit : 10
let skip
let offset
let page
// Custom Labels
const labelTotal = 'total'
const labelLimit = 'pageSize'
const labelPage = 'current'
const labelPagination = 'pagination'
const labelTotalPages = 'pages'
const labelDocs = 'list'
const labelNextPage = 'next'
const labelPrevPage = 'prev'
if (options.hasOwnProperty('offset')) {
offset = options.offset
skip = offset
} else if (options.hasOwnProperty('page')) {
page = options.page
skip = (page - 1) * limit
} else {
offset = 0
page = 1
skip = offset
}
const promises = {
docs: Promise.resolve([]),
count: this.countDocuments(query).exec()
}
if (limit) {
query = this.find(query).select(select).sort(sort).collation(collation).skip(skip).limit(limit).lean(lean)
if (populate) {
;[].concat(populate).forEach(function (item) {
query.populate(item)
})
}
promises.docs = query.exec()
if (lean && leanWithId) {
promises.docs = promises.docs.then(function (docs) {
docs.forEach(function (doc) {
doc.id = String(doc._id)
})
return docs
})
}
}
return Promise.props(promises)
.then(function (data) {
const result = {
[labelDocs]: data.docs,
[labelPagination]: {
[labelTotal]: data.count,
[labelLimit]: limit
}
}
if (offset !== undefined) {
result[labelPagination].offset = offset
}
if (page !== undefined) {
const pages = Math.ceil(data.count / limit) || 1
result.has_prev = false
result.has_next = false
result[labelPagination][labelPage] = page
result[labelPagination][labelTotalPages] = pages
// Set prev page
if (page > 1) {
result.has_prev = true
result[labelPagination][labelPrevPage] = page - 1
} else {
result[labelPagination][labelPrevPage] = undefined
}
// Set next page
if (page < pages) {
result.has_next = true
result[labelPagination][labelNextPage] = page + 1
} else {
result[labelPagination][labelNextPage] = undefined
}
}
return result
})
.asCallback(callback)
}
/**
* @param {Schema} schema
*/
module.exports = function (schema) {
schema.statics.paginate = paginate
}
module.exports.paginate = paginate