UNPKG

4.53 kBJavaScriptView Raw
1const qs = require('qs')
2const _ = require('lodash')
3
4/**
5 * @function
6 * @private
7 *
8 * @description
9 * Get parameter value based on the passed condition
10 *
11 * @param {*} param The parameter to be minimized
12 * @param {*} condition The condition to be checked for
13 * @returns {* | undefined} The minimized parameter value
14 */
15function minimizeQueryParameter (param, condition) {
16 return param === condition ? undefined : param
17}
18
19/**
20 * @function
21 * @private
22 *
23 * @description
24 * Halify links by converting them to objects
25 *
26 * @param {Object} links The links to be halified
27 * @returns {Object} The halified links object
28 */
29function halifyLinks (links) {
30 _.forOwn(links, (href, entity) => {
31 links[entity] = { href }
32 })
33}
34
35/**
36 * @function
37 * @private
38 *
39 * @description
40 * Get absolute/relative request url
41 *
42 * @param {Object} request The related request object
43 * @param {Object} pluginOptions The plugin related options
44 * @returns {string} The request url
45 */
46function getRequestUrl (request, pluginOptions) {
47 const proxyProtocol = request.headers && request.headers['x-forwarded-proto']
48 const protocol = proxyProtocol || request.server.info.protocol || 'http'
49 let requestUrl = request.url.pathname
50
51 if (pluginOptions.absolute) {
52 requestUrl = `${protocol}://${request.info.host}${requestUrl}`
53 }
54
55 return requestUrl
56}
57
58/**
59 * @function
60 * @private
61 *
62 * @description
63 * Get link of the requested resource itself
64 *
65 * @param {number} page The requested page
66 * @param {number} perPage The requested items per page
67 * @param {Object} request The related request object
68 * @param {Object} options The request related options
69 * @param {Object} pluginOptions The plugin related options
70 * @returns {string} The generated resource link
71 */
72function getSelfLink (page, perPage, request, options, pluginOptions) {
73 const requestPath = getRequestUrl(request, pluginOptions)
74
75 const paramNames = pluginOptions.paramNames
76 const query = qs.stringify(Object.assign({}, request.query, {
77 [paramNames.perPage]: minimizeQueryParameter(perPage, options.perPage),
78 [paramNames.page]: minimizeQueryParameter(page, 1)
79 }))
80
81 return query ? `${requestPath}?${query}` : requestPath
82}
83
84/**
85 * @function
86 * @private
87 *
88 * @description
89 * Get pagination link generator with predefined values
90 *
91 * @param {string} id The endpoint ID
92 * @param {number} perPage The number of entries per page
93 * @param {Object} options The related options
94 * @param {Object} requestObj The related query parameters
95 * @param {Function} aka The request bound akaya function for link building
96 * @param {boolean} absolute If the link should be an absolute one
97 * @param {Object} paramNames The names of the query params
98 * @returns {Function} The predefined pagination link generator
99 */
100function getPaginationLink (id, perPage, options, requestObj, aka, absolute, paramNames) {
101 perPage = minimizeQueryParameter(perPage, options.perPage)
102
103 return (page) => {
104 page = minimizeQueryParameter(page, 1)
105
106 return aka(id, {
107 query: Object.assign({}, requestObj.query, {
108 [paramNames.page]: page,
109 [paramNames.perPage]: perPage
110 }),
111 params: requestObj.params
112 }, { rel: !absolute })
113 }
114}
115
116/**
117 * @function
118 * @public
119 *
120 * @description
121 * Get entity/href mapping of necessary pagination links
122 *
123 * @param {string} id The endpoint ID
124 * @param {number} page The requested page
125 * @param {number} perPage The number of entries per page
126 * @param {number} total The total number of entries
127 * @param {Object} requestObj The related query parameters
128 * @param {Function} aka The request bound akaya function for link building
129 * @param {Object} options The related options
130 * @param {Object} pluginOptions The plugin related options
131 * @returns {Object.<?string>} The mapping of pagination links
132 */
133function getPaginationLinks (id, page, perPage, total, requestObj, aka, options, pluginOptions) {
134 const getLink = getPaginationLink(
135 id, perPage, options, requestObj, aka, pluginOptions.absolute, pluginOptions.paramNames
136 )
137 const lastPage = Math.ceil(total / perPage)
138 const links = {}
139
140 links.self = getSelfLink(page, perPage, requestObj, options, pluginOptions)
141 links.first = getLink(undefined)
142
143 if (page > 1 && page <= lastPage) {
144 links.prev = getLink(page - 1)
145 }
146
147 if (page < lastPage && page >= 1) {
148 links.next = getLink(page + 1)
149 }
150
151 links.last = getLink(lastPage)
152
153 halifyLinks(links)
154
155 return links
156}
157
158module.exports = {
159 getLinks: getPaginationLinks
160}