1 | const Joi = require('joi')
|
2 | const Boom = require('boom')
|
3 | const errors = require('./errors')
|
4 | const validate = require('./validate')
|
5 | const header = require('./header')
|
6 | const pagination = require('./pagination')
|
7 | const pkg = require('../package.json')
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const internals = {
|
17 | defaults: {
|
18 | total: null,
|
19 | perPage: 100,
|
20 | key: 'result'
|
21 | },
|
22 | scheme: {
|
23 | pluginOptions: Joi.object({
|
24 | absolute: Joi.boolean().default(false),
|
25 | paramNames: Joi
|
26 | .object({
|
27 | perPage: Joi.string().default('per_page'),
|
28 | page: Joi.string().default('page'),
|
29 | total: Joi.string().default('total')
|
30 | })
|
31 | .default({
|
32 | perPage: 'per_page',
|
33 | page: 'page',
|
34 | total: 'total'
|
35 | })
|
36 | })
|
37 | }
|
38 | }
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | function setParamScheme (paramNames) {
|
50 | internals.scheme = {
|
51 | pluginOptions: internals.scheme.pluginOptions,
|
52 | [paramNames.perPage]: Joi.number()
|
53 | .integer()
|
54 | .min(1)
|
55 | .max(500)
|
56 | .default(100),
|
57 | [paramNames.page]: Joi.number()
|
58 | .integer()
|
59 | .min(1)
|
60 | .default(1)
|
61 | }
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | function bissle (server, pluginOptions) {
|
75 | pluginOptions = Joi.attempt(pluginOptions, internals.scheme.pluginOptions)
|
76 |
|
77 | const paramNames = pluginOptions.paramNames
|
78 | setParamScheme(paramNames)
|
79 |
|
80 | server.expose('scheme', internals.scheme)
|
81 | server.dependency('akaya')
|
82 |
|
83 | server.decorate('toolkit', 'bissle', function decorator (res, options) {
|
84 | let result
|
85 | let total
|
86 |
|
87 | options = Object.assign({}, internals.defaults, options)
|
88 |
|
89 | if (!validate.options(options)) {
|
90 | throw Boom.badRequest(errors.invalidOptions)
|
91 | }
|
92 |
|
93 | if (!validate.query(this.request.query, options, pluginOptions.paramNames)) {
|
94 | throw Boom.badRequest(errors.invalidQuery)
|
95 | }
|
96 | const page = this.request.query[paramNames.page]
|
97 | const perPage = this.request.query[paramNames.perPage]
|
98 | const offset = (page - 1) * perPage
|
99 |
|
100 | if (options.total !== null) {
|
101 | total = options.total
|
102 | result = res[options.key]
|
103 | } else {
|
104 | total = res[options.key].length
|
105 | result = res[options.key].splice(offset, perPage)
|
106 | }
|
107 |
|
108 | const id = this.request.route.settings.id
|
109 |
|
110 | if (!id) {
|
111 | throw Boom.badRequest(errors.missingId)
|
112 | }
|
113 |
|
114 | const links = pagination.getLinks(
|
115 | id, page, perPage, total, this.request,
|
116 | this.request.aka.bind(this.request), options, pluginOptions
|
117 | )
|
118 |
|
119 | const linkHeader = header.getLink(links)
|
120 |
|
121 | return this.response(Object.assign(res, {
|
122 | [options.key]: result,
|
123 | _links: links,
|
124 | [paramNames.perPage]: perPage,
|
125 | [paramNames.page]: page,
|
126 | [paramNames.total]: total
|
127 | })).header('link', linkHeader)
|
128 | })
|
129 | }
|
130 |
|
131 | module.exports = {
|
132 | register: bissle,
|
133 | pkg
|
134 | }
|