express-toolkit 0.7.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,7 @@ Tiny little utilities for reducing expressjs boilerplate code when building simp
19
19
  - [Default endpoints](#default-endpoints)
20
20
  - [Disable endpoints](#disable-endpoints)
21
21
  - [Sorting](#sorting)
22
+ - [Pagination](#pagination)
22
23
  - [Projection](#projection)
23
24
  - [Custom primary key](#custom-primary-key)
24
25
  - [Hooks](#hooks)
@@ -237,6 +238,12 @@ For example, the following request would sort dinosaurs by age, oldest to younge
237
238
  ```http
238
239
  GET /dinosaurs?sortby=age&sortorder=DESC
239
240
  ```
241
+ ## Pagination
242
+ GET endpoints support result pagination through `skip` and `limit` parameters:
243
+ - `skip <Number>` tells the endpoint how many results to skip
244
+ - `limit <Number` tells the endpoint how many results to include in the response
245
+
246
+ To implement a pagination scheme, you can leverage these two parameters in the following way: Suppose you want to return `R` results per page and you want to return page number `P`, you just need to set limit to `R` and skip to `(P-1)*R`
240
247
 
241
248
  ## Projection
242
249
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-toolkit",
3
- "version": "0.7.1",
3
+ "version": "0.8.2",
4
4
  "files": [
5
5
  "index.js",
6
6
  "src/"
@@ -16,7 +16,8 @@
16
16
  "test": "nyc --reporter=text ava test/*.spec.js --verbose",
17
17
  "test-ci": "npx nyc --reporter=lcov ava test/*.spec.js --verbose",
18
18
  "commit": "npx git-cz",
19
- "pre-commit": "npm run lint && depcheck && npm run test",
19
+ "documentation": "docsify init ./docs",
20
+ "pre-commit": "npm run lint && npm run test",
20
21
  "changelog": "npx easy-changelog --out=./CHANGELOG.md",
21
22
  "release": "sh scripts/release.sh"
22
23
  },
@@ -34,24 +35,25 @@
34
35
  "express"
35
36
  ],
36
37
  "dependencies": {
37
- "express": "^4.17.1",
38
+ "express": "^4.17.3",
38
39
  "json8-patch": "^1.0.4",
39
40
  "mongoose": "^5.12.3",
40
41
  "throwable-http-errors": "^2.1.0"
41
42
  },
42
43
  "devDependencies": {
43
- "ava": "^3.8.1",
44
+ "ava": "^4.3.1",
44
45
  "body-parser": "^1.19.0",
45
- "eslint": "^5.16.0",
46
- "eslint-config-standard": "^12.0.0",
47
- "eslint-plugin-import": "^2.18.2",
48
- "eslint-plugin-node": "^8.0.1",
49
- "eslint-plugin-promise": "^4.2.1",
46
+ "eslint": "^7.32.0",
47
+ "eslint-config-standard": "^16.0.3",
48
+ "eslint-plugin-import": "^2.25.4",
49
+ "eslint-plugin-node": "^11.1.0",
50
+ "eslint-plugin-promise": "^5.2.0",
50
51
  "eslint-plugin-standard": "^4.0.1",
51
52
  "husky": "^1.3.1",
52
- "mongodb-memory-server": "^5.2.11",
53
- "nyc": "^14.1.1",
53
+ "mongodb-memory-server": "^8.4.0",
54
+ "nyc": "^15.1.0",
54
55
  "sinon": "^7.5.0",
55
- "supertest": "^4.0.2"
56
+ "supertest": "^4.0.2",
57
+ "uuid": "^8.3.2"
56
58
  }
57
59
  }
package/src/controller.js CHANGED
@@ -20,11 +20,13 @@ class Controller {
20
20
  * @param {String} [config.id] The attribute to use as primary key for findById, updateById and deleteById. Defaults to _id.
21
21
  * @param {Number} [config.defaultSkipValue] The default skip value to be used in find() queries
22
22
  * @param {Number} [config.defaultLimitValue] The default skip value to be used in find() queries
23
+ * @param {Number} [config.useUpdateOne] If set to true, updateById method will use mongoose's Model.updateOne() instead of Document.save()
23
24
  */
24
25
  constructor (config) {
25
26
  this.Model = config.model
26
27
  this.id = config.id || '_id'
27
28
  this.name = config.name
29
+ this.useUpdateOne = Boolean(config.useUpdateOne) || false
28
30
  this.defaultSkipValue = config.defaultSkipValue || DEFAULT_SKIP_VALUE
29
31
  this.defaultLimitValue = config.defaultLimitValue || DEFAULT_LIMIT_VALUE
30
32
  this.__hooks = {}
@@ -37,10 +39,10 @@ class Controller {
37
39
  async find (query) {
38
40
  let skip = this.defaultSkipValue
39
41
  let limit = this.defaultLimitValue
40
- if (query.hasOwnProperty('limit')) {
42
+ if (Object.prototype.hasOwnProperty.call(query, 'limit')) {
41
43
  limit = Number(query.limit)
42
44
  }
43
- if (query.hasOwnProperty('skip')) {
45
+ if (Object.prototype.hasOwnProperty.call(query, 'skip')) {
44
46
  skip = Number(query.skip)
45
47
  }
46
48
 
@@ -180,7 +182,7 @@ class Controller {
180
182
  const instances = await this.Model.find(query)
181
183
 
182
184
  for (const instance of instances) {
183
- for (var k in update) {
185
+ for (const k in update) {
184
186
  instance.set(k, update[k])
185
187
  }
186
188
 
@@ -207,7 +209,7 @@ class Controller {
207
209
  throw new Errors.NotFound()
208
210
  }
209
211
 
210
- for (var k in update) {
212
+ for (const k in update) {
211
213
  instance.set(k, update[k])
212
214
  }
213
215
 
@@ -216,7 +218,13 @@ class Controller {
216
218
  throw new Errors.BadRequest(validationError.message)
217
219
  }
218
220
 
219
- return instance.save()
221
+ if (this.useUpdateOne) {
222
+ await this.Model.updateOne({ [this.id]: id }, update)
223
+
224
+ return instance.toJSON()
225
+ } else {
226
+ return instance.save()
227
+ }
220
228
  }
221
229
 
222
230
  /**
@@ -233,7 +241,7 @@ class Controller {
233
241
  throw new Errors.NotFound()
234
242
  }
235
243
  // Primary identifiers cannot be replaced
236
- replacement['_id'] = instance._id
244
+ replacement._id = instance._id
237
245
  replacement[this.id] = instance[this.id]
238
246
  instance.overwrite(replacement)
239
247
 
package/src/router.js CHANGED
@@ -48,10 +48,12 @@ const defaultEndpoints = {
48
48
  * @param {Object} config
49
49
  * @param {Object} config.controller
50
50
  * @param {Object} [config.endpoints] Map<String,Boolean>
51
+ * @param {String} [config.id] The named route parameter to use as id. Defaults to "id"
51
52
  * @param {Object} [config.options] Express router options. As described in https://expressjs.com/en/api.html#express.router
52
53
  */
53
54
  function buildRouter (config) {
54
55
  config.options = config.options || {}
56
+ config.id = config.id || 'id'
55
57
  const router = express.Router(config.options)
56
58
  if (!(config.controller instanceof Controller)) {
57
59
  throw new Error('config.controller must be an instance of Controller')
@@ -64,7 +66,7 @@ function buildRouter (config) {
64
66
  const endpointsMap = Object.assign({}, defaultEndpoints, config.endpoints)
65
67
 
66
68
  const findByIdMiddleware = asyncMiddleware(async (req, res, next) => {
67
- const resource = await config.controller.findById(req.params.id, req.query)
69
+ const resource = await config.controller.findById(req.params[config.id], req.query)
68
70
  req.toSend = resource
69
71
  return next()
70
72
  })
@@ -76,7 +78,7 @@ function buildRouter (config) {
76
78
  })
77
79
 
78
80
  const updateByIdMiddleware = asyncMiddleware(async (req, res, next) => {
79
- const resource = await config.controller.updateById(req.params.id, req.body, req.query)
81
+ const resource = await config.controller.updateById(req.params[config.id], req.body, req.query)
80
82
  req.toSend = resource
81
83
  return next()
82
84
  })
@@ -88,7 +90,7 @@ function buildRouter (config) {
88
90
  })
89
91
 
90
92
  const deleteByIdMiddleware = asyncMiddleware(async (req, res, next) => {
91
- await config.controller.deleteById(req.params.id)
93
+ await config.controller.deleteById(req.params[config.id])
92
94
  req.toSend = null
93
95
  return next()
94
96
  })
@@ -114,13 +116,13 @@ function buildRouter (config) {
114
116
  })
115
117
 
116
118
  const patchByIdMiddleware = asyncMiddleware(async (req, res, next) => {
117
- const resource = await config.controller.patchById(req.params.id, req.body)
119
+ const resource = await config.controller.patchById(req.params[config.id], req.body)
118
120
  req.toSend = resource
119
121
  return next()
120
122
  })
121
123
 
122
124
  const replaceByIdMiddleware = asyncMiddleware(async (req, res, next) => {
123
- const resource = await config.controller.replaceById(req.params.id, req.body)
125
+ const resource = await config.controller.replaceById(req.params[config.id], req.body)
124
126
  req.toSend = resource
125
127
  return next()
126
128
  })
@@ -138,7 +140,7 @@ function buildRouter (config) {
138
140
  },
139
141
  findById: {
140
142
  method: 'get',
141
- path: '/:id',
143
+ path: `/:${config.id}`,
142
144
  middleware: findByIdMiddleware
143
145
  },
144
146
  create: {
@@ -148,7 +150,7 @@ function buildRouter (config) {
148
150
  },
149
151
  updateById: {
150
152
  method: 'put',
151
- path: '/:id',
153
+ path: `/:${config.id}`,
152
154
  middleware: updateByIdMiddleware
153
155
  },
154
156
  updateByQuery: {
@@ -158,7 +160,7 @@ function buildRouter (config) {
158
160
  },
159
161
  deleteById: {
160
162
  method: 'delete',
161
- path: '/:id',
163
+ path: `/:${config.id}`,
162
164
  middleware: deleteByIdMiddleware
163
165
  },
164
166
  deleteByQuery: {
@@ -168,12 +170,12 @@ function buildRouter (config) {
168
170
  },
169
171
  patchById: {
170
172
  method: 'patch',
171
- path: '/:id',
173
+ path: `/:${config.id}`,
172
174
  middleware: patchByIdMiddleware
173
175
  },
174
176
  replaceById: {
175
177
  method: 'put',
176
- path: '/:id/replace',
178
+ path: `/:${config.id}/replace`,
177
179
  middleware: replaceByIdMiddleware
178
180
  }
179
181