adapt-authoring-api 3.2.3 → 3.4.0
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/lib/AbstractApiModule.js +5 -1
- package/lib/typedefs.js +2 -0
- package/package.json +1 -1
- package/tests/AbstractApiModule.spec.js +115 -0
package/lib/AbstractApiModule.js
CHANGED
|
@@ -538,6 +538,10 @@ class AbstractApiModule extends AbstractModule {
|
|
|
538
538
|
* @param {Object} mongoOpts The MongoDB options
|
|
539
539
|
*/
|
|
540
540
|
async setUpPagination (req, res, mongoOpts) {
|
|
541
|
+
if (mongoOpts.limit === 0) {
|
|
542
|
+
delete mongoOpts.limit
|
|
543
|
+
return
|
|
544
|
+
}
|
|
541
545
|
const maxPageSize = this.getConfig('maxPageSize') ?? this.app.config.get('adapt-authoring-api.maxPageSize')
|
|
542
546
|
let pageSize = mongoOpts.limit ?? this.getConfig('defaultPageSize') ?? this.app.config.get('adapt-authoring-api.defaultPageSize')
|
|
543
547
|
|
|
@@ -658,7 +662,7 @@ class AbstractApiModule extends AbstractModule {
|
|
|
658
662
|
if (results.length > 1) {
|
|
659
663
|
throw this.app.errors.TOO_MANY_RESULTS.setData({ actual: results.length, expected: 1, query })
|
|
660
664
|
}
|
|
661
|
-
if (options.strict !== false && !results.length) {
|
|
665
|
+
if ((options.throwOnMissing ?? options.strict) !== false && !results.length) {
|
|
662
666
|
throw this.app.errors.NOT_FOUND.setData({ id: query, type: options.schemaName })
|
|
663
667
|
}
|
|
664
668
|
return results[0] ?? null
|
package/lib/typedefs.js
CHANGED
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
* @typedef {Object} FindOptions
|
|
50
50
|
* @property {String} schemaName Name of the schema to validate against
|
|
51
51
|
* @property {String} collectionName DB collection to insert document into
|
|
52
|
+
* @property {Boolean} throwOnMissing Whether to throw a NOT_FOUND error when no results are found (default: true)
|
|
53
|
+
* @property {Boolean} [strict] @deprecated Use throwOnMissing instead
|
|
52
54
|
*/
|
|
53
55
|
/**
|
|
54
56
|
* @memberof api
|
package/package.json
CHANGED
|
@@ -142,6 +142,56 @@ describe('AbstractApiModule', () => {
|
|
|
142
142
|
})
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
+
describe('#findOne()', () => {
|
|
146
|
+
function createFindOneInstance (findResults) {
|
|
147
|
+
const notFoundError = { setData: () => { const e = new Error('NOT_FOUND'); e.code = 'NOT_FOUND'; return e } }
|
|
148
|
+
const tooManyResultsError = { setData: () => { const e = new Error('TOO_MANY_RESULTS'); e.code = 'TOO_MANY_RESULTS'; return e } }
|
|
149
|
+
const instance = Object.create(AbstractApiModule.prototype)
|
|
150
|
+
instance.find = async () => findResults
|
|
151
|
+
instance.app = { errors: { NOT_FOUND: notFoundError, TOO_MANY_RESULTS: tooManyResultsError } }
|
|
152
|
+
return instance
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
it('should throw NOT_FOUND when no results and throwOnMissing is not set', async () => {
|
|
156
|
+
const instance = createFindOneInstance([])
|
|
157
|
+
await assert.rejects(() => instance.findOne({}), /NOT_FOUND/)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('should throw NOT_FOUND when no results and throwOnMissing is true', async () => {
|
|
161
|
+
const instance = createFindOneInstance([])
|
|
162
|
+
await assert.rejects(() => instance.findOne({}, { throwOnMissing: true }), /NOT_FOUND/)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('should return null when no results and throwOnMissing is false', async () => {
|
|
166
|
+
const instance = createFindOneInstance([])
|
|
167
|
+
const result = await instance.findOne({}, { throwOnMissing: false })
|
|
168
|
+
assert.equal(result, null)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should return null when no results and strict is false (backward compat)', async () => {
|
|
172
|
+
const instance = createFindOneInstance([])
|
|
173
|
+
const result = await instance.findOne({}, { strict: false })
|
|
174
|
+
assert.equal(result, null)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('should prefer throwOnMissing over strict when both are set', async () => {
|
|
178
|
+
const instance = createFindOneInstance([])
|
|
179
|
+
await assert.rejects(() => instance.findOne({}, { throwOnMissing: true, strict: false }), /NOT_FOUND/)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('should return the single result when found', async () => {
|
|
183
|
+
const doc = { _id: '1', name: 'test' }
|
|
184
|
+
const instance = createFindOneInstance([doc])
|
|
185
|
+
const result = await instance.findOne({})
|
|
186
|
+
assert.deepEqual(result, doc)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('should throw TOO_MANY_RESULTS when more than one result is returned', async () => {
|
|
190
|
+
const instance = createFindOneInstance([{ _id: '1' }, { _id: '2' }])
|
|
191
|
+
await assert.rejects(() => instance.findOne({}), /TOO_MANY_RESULTS/)
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
145
195
|
describe('default-routes.json', () => {
|
|
146
196
|
it('should define an array of route objects', () => {
|
|
147
197
|
assert.ok(Array.isArray(defaultRoutes.routes))
|
|
@@ -180,4 +230,69 @@ describe('AbstractApiModule', () => {
|
|
|
180
230
|
assert.equal(queryRoute.modifying, false)
|
|
181
231
|
})
|
|
182
232
|
})
|
|
233
|
+
|
|
234
|
+
describe('#setUpPagination()', () => {
|
|
235
|
+
function createPaginationInstance (docCount = 0, config = {}) {
|
|
236
|
+
const headers = {}
|
|
237
|
+
const instance = createInstance({
|
|
238
|
+
getConfig: (key) => config[key],
|
|
239
|
+
app: {
|
|
240
|
+
config: {
|
|
241
|
+
get: (key) => {
|
|
242
|
+
const defaults = { 'adapt-authoring-api.defaultPageSize': 100, 'adapt-authoring-api.maxPageSize': 250 }
|
|
243
|
+
return defaults[key]
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
waitForModule: async () => ({
|
|
247
|
+
getCollection: () => ({
|
|
248
|
+
countDocuments: async () => docCount
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
const req = { originalUrl: '/api/content/query', query: {}, apiData: { collectionName: 'content', query: {} } }
|
|
254
|
+
const res = { set: (k, v) => { headers[k] = v } }
|
|
255
|
+
return { instance, req, res, headers }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
it('should skip pagination when limit is 0', async () => {
|
|
259
|
+
const { instance, req, res, headers } = createPaginationInstance(500)
|
|
260
|
+
const mongoOpts = { limit: 0 }
|
|
261
|
+
await instance.setUpPagination(req, res, mongoOpts)
|
|
262
|
+
assert.equal(mongoOpts.limit, undefined)
|
|
263
|
+
assert.equal(headers['X-Adapt-Page'], undefined)
|
|
264
|
+
assert.equal(headers['X-Adapt-PageSize'], undefined)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('should apply default pagination when limit is not 0', async () => {
|
|
268
|
+
const { instance, req, res, headers } = createPaginationInstance(50)
|
|
269
|
+
const mongoOpts = {}
|
|
270
|
+
await instance.setUpPagination(req, res, mongoOpts)
|
|
271
|
+
assert.equal(mongoOpts.limit, 100)
|
|
272
|
+
assert.equal(headers['X-Adapt-Page'], 1)
|
|
273
|
+
assert.equal(headers['X-Adapt-PageSize'], 100)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('should set Link header when results span multiple pages', async () => {
|
|
277
|
+
const { instance, req, res, headers } = createPaginationInstance(250)
|
|
278
|
+
const mongoOpts = {}
|
|
279
|
+
await instance.setUpPagination(req, res, mongoOpts)
|
|
280
|
+
assert.ok(headers.Link)
|
|
281
|
+
assert.ok(headers.Link.includes('rel="next"'))
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('should not set Link header for single-page results', async () => {
|
|
285
|
+
const { instance, req, res, headers } = createPaginationInstance(50)
|
|
286
|
+
const mongoOpts = {}
|
|
287
|
+
await instance.setUpPagination(req, res, mongoOpts)
|
|
288
|
+
assert.equal(headers.Link, undefined)
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('should cap pageSize at maxPageSize', async () => {
|
|
292
|
+
const { instance, req, res, headers } = createPaginationInstance(500)
|
|
293
|
+
const mongoOpts = { limit: 999 }
|
|
294
|
+
await instance.setUpPagination(req, res, mongoOpts)
|
|
295
|
+
assert.equal(headers['X-Adapt-PageSize'], 250)
|
|
296
|
+
})
|
|
297
|
+
})
|
|
183
298
|
})
|