monastery 3.0.20 → 3.0.22
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/changelog.md +4 -0
- package/lib/model-crud.js +45 -17
- package/lib/model-validate.js +1 -2
- package/lib/util.js +35 -31
- package/package.json +1 -1
- package/test/crud.js +123 -6
- package/test/util.js +3 -2
package/changelog.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.0.22](https://github.com/boycce/monastery/compare/3.0.21...3.0.22) (2024-05-08)
|
|
6
|
+
|
|
7
|
+
### [3.0.21](https://github.com/boycce/monastery/compare/3.0.20...3.0.21) (2024-05-07)
|
|
8
|
+
|
|
5
9
|
### [3.0.20](https://github.com/boycce/monastery/compare/3.0.19...3.0.20) (2024-05-05)
|
|
6
10
|
|
|
7
11
|
### [3.0.19](https://github.com/boycce/monastery/compare/3.0.18...3.0.19) (2024-05-05)
|
package/lib/model-crud.js
CHANGED
|
@@ -48,9 +48,9 @@ Model.prototype.insert = async function (opts) {
|
|
|
48
48
|
let data = await this.validate(opts.data || {}, opts) // was { ...opts }
|
|
49
49
|
|
|
50
50
|
// Insert
|
|
51
|
-
await util.runSeries.call(this, this.beforeInsert.map(f => f.bind(opts
|
|
51
|
+
data = await util.runSeries.call(this, this.beforeInsert.map(f => f.bind(opts)), 'beforeInsert', data)
|
|
52
52
|
let response = await this._insert(data, util.omit(opts, this._queryOptions))
|
|
53
|
-
await util.runSeries.call(this, this.afterInsert.map(f => f.bind(opts
|
|
53
|
+
response = await util.runSeries.call(this, this.afterInsert.map(f => f.bind(opts)), 'afterInsert', response)
|
|
54
54
|
|
|
55
55
|
// Success/error
|
|
56
56
|
if (opts.req && opts.respond) opts.req.res.json(response)
|
|
@@ -283,7 +283,8 @@ Model.prototype.update = async function (opts, type='update') {
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// Hook: beforeUpdate (has access to original, non-validated opts.data)
|
|
286
|
-
|
|
286
|
+
data = data || {}
|
|
287
|
+
data = await util.runSeries.call(this, this.beforeUpdate.map(f => f.bind(opts)), 'beforeUpdate', data)
|
|
287
288
|
|
|
288
289
|
if (data && operators['$set']) {
|
|
289
290
|
this.info(`'$set' fields take precedence over the data fields for \`${this.name}.${type}()\``)
|
|
@@ -314,7 +315,7 @@ Model.prototype.update = async function (opts, type='update') {
|
|
|
314
315
|
|
|
315
316
|
// Hook: afterUpdate (doesn't have access to validated data)
|
|
316
317
|
if (response) {
|
|
317
|
-
await util.runSeries.call(this, this.afterUpdate.map(f => f.bind(opts
|
|
318
|
+
response = await util.runSeries.call(this, this.afterUpdate.map(f => f.bind(opts)), 'afterUpdate', response)
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
// Hook: afterFind if findOneAndUpdate
|
|
@@ -561,7 +562,7 @@ Model.prototype._pathBlacklisted = function (path, projection, matchDeepWhitelis
|
|
|
561
562
|
return inclusion? true : false
|
|
562
563
|
}
|
|
563
564
|
|
|
564
|
-
Model.prototype._processAfterFind = function (data, projection={}, afterFindContext={}) {
|
|
565
|
+
Model.prototype._processAfterFind = async function (data, projection={}, afterFindContext={}) {
|
|
565
566
|
/**
|
|
566
567
|
* Todo: Maybe make this method public?
|
|
567
568
|
* Recurses through fields that are models and populates missing default-fields and calls model.afterFind([fn,..])
|
|
@@ -576,16 +577,26 @@ Model.prototype._processAfterFind = function (data, projection={}, afterFindCont
|
|
|
576
577
|
*/
|
|
577
578
|
// Recurse down from the parent model, ending with the parent model as the parent afterFind hook may
|
|
578
579
|
// want to manipulate any populated models
|
|
579
|
-
let
|
|
580
|
+
let seriesGroups = []
|
|
580
581
|
let models = this.manager.models
|
|
581
|
-
let
|
|
582
|
-
|
|
582
|
+
let isArray = util.isArray(data)
|
|
583
|
+
if (!isArray) data = [data]
|
|
584
|
+
let modelFields = this
|
|
585
|
+
._recurseAndFindModels(data)
|
|
586
|
+
.concat(data.map((o, i) => ({
|
|
587
|
+
dataRefParent: data,
|
|
588
|
+
dataRefKey: i,
|
|
589
|
+
dataPath: '',
|
|
590
|
+
dataFieldName: '',
|
|
591
|
+
modelName: this.name,
|
|
592
|
+
})))
|
|
583
593
|
|
|
584
594
|
// Loop found model/deep-model data objects, and populate missing default-fields and call afterFind on each
|
|
585
595
|
for (let item of modelFields) {
|
|
596
|
+
const dataRef = item.dataRefParent[item.dataRefKey]
|
|
586
597
|
// Populate missing default fields if data !== null
|
|
587
598
|
// NOTE: maybe only call functions if default is being set.. fine for now
|
|
588
|
-
if (
|
|
599
|
+
if (dataRef) {
|
|
589
600
|
for (const localSchemaFieldPath in models[item.modelName].fieldsFlattened) {
|
|
590
601
|
const schema = models[item.modelName].fieldsFlattened[localSchemaFieldPath]
|
|
591
602
|
if (!util.isDefined(schema.default) || localSchemaFieldPath.match(/^\.?(createdAt|updatedAt)$/)) continue
|
|
@@ -601,25 +612,37 @@ Model.prototype._processAfterFind = function (data, projection={}, afterFindCont
|
|
|
601
612
|
|
|
602
613
|
// Set default value
|
|
603
614
|
const value = util.isFunction(schema.default) ? schema.default(this.manager) : schema.default
|
|
604
|
-
util.setDeepValue(
|
|
615
|
+
util.setDeepValue(dataRef, localSchemaFieldPath.replace(/\.0(\.|$)/g, '.$$$1'), value, true, false, true)
|
|
605
616
|
}
|
|
606
617
|
}
|
|
607
618
|
// Collect all of the model's afterFind hooks
|
|
608
|
-
|
|
609
|
-
|
|
619
|
+
if (models[item.modelName].afterFind.length) {
|
|
620
|
+
seriesGroups.push(
|
|
621
|
+
(async (_item) => {
|
|
622
|
+
const _modelName = _item.modelName
|
|
623
|
+
const _model = models[_modelName]
|
|
624
|
+
const _opts = { ...afterFindContext, afterFindName: _modelName }
|
|
625
|
+
const _dataRef = _item.dataRefParent[_item.dataRefKey]
|
|
626
|
+
_item.dataRefParent[_item.dataRefKey] = (
|
|
627
|
+
await util.runSeries.call(_model, _model.afterFind.map(f => f.bind(_opts)), 'afterFind', _dataRef)
|
|
628
|
+
)
|
|
629
|
+
}).bind(null, item)
|
|
630
|
+
)
|
|
610
631
|
}
|
|
611
632
|
}
|
|
612
|
-
|
|
633
|
+
for (let item of seriesGroups) await item()
|
|
634
|
+
return isArray ? data : data[0]
|
|
613
635
|
}
|
|
614
636
|
|
|
615
637
|
Model.prototype._recurseAndFindModels = function (dataArr, dataParentPath='', modelPaths) {
|
|
616
638
|
/**
|
|
617
|
-
* Returns a flattened list of models fields
|
|
639
|
+
* Returns a flattened list of models fields, sorted by depth
|
|
618
640
|
* @param {object|array} dataArr
|
|
619
641
|
* @param {string} <dataParentPath>
|
|
620
642
|
* @this Model
|
|
621
643
|
* @return [{
|
|
622
|
-
*
|
|
644
|
+
* dataRefParent: { *fields here* },
|
|
645
|
+
* dataRefKey: 'fieldName',
|
|
623
646
|
* dataPath: 'usersNewCompany',
|
|
624
647
|
* dataFieldName: usersNewCompany,
|
|
625
648
|
* modelName: company
|
|
@@ -667,7 +690,8 @@ Model.prototype._recurseAndFindModels = function (dataArr, dataParentPath='', mo
|
|
|
667
690
|
// Array of data models (schema field can be either a single or array of models, due to custom $lookup's)
|
|
668
691
|
} else if (pathMatch && util.isObject(data[key])) {
|
|
669
692
|
out.push({
|
|
670
|
-
|
|
693
|
+
dataRefParent: data,
|
|
694
|
+
dataRefKey: key,
|
|
671
695
|
dataPath: dataPath,
|
|
672
696
|
dataFieldName: key,
|
|
673
697
|
modelName: this.fieldsFlattened[modelPath.k].model,
|
|
@@ -677,7 +701,8 @@ Model.prototype._recurseAndFindModels = function (dataArr, dataParentPath='', mo
|
|
|
677
701
|
} else if (pathMatch && util.isObject(data[key][0])) {
|
|
678
702
|
for (let i=0, l=data[key].length; i<l; i++) {
|
|
679
703
|
out.push({
|
|
680
|
-
|
|
704
|
+
dataRefParent: data[key],
|
|
705
|
+
dataRefKey: i,
|
|
681
706
|
dataPath: dataPath + '.' + i,
|
|
682
707
|
dataFieldName: key,
|
|
683
708
|
modelName: this.fieldsFlattened[modelPath.k].model,
|
|
@@ -687,6 +712,9 @@ Model.prototype._recurseAndFindModels = function (dataArr, dataParentPath='', mo
|
|
|
687
712
|
}
|
|
688
713
|
}
|
|
689
714
|
|
|
715
|
+
// Sort by dataPath length so that nested models are processed first
|
|
716
|
+
// note: this shouldn't matter anyway since we can't currently have nested populated models
|
|
717
|
+
out = out.sort((a, b) => b.dataPath.split('.').length - a.dataPath.split('.').length)
|
|
690
718
|
return out
|
|
691
719
|
}
|
|
692
720
|
|
package/lib/model-validate.js
CHANGED
|
@@ -29,8 +29,7 @@ Model.prototype.validate = async function (data, opts) {
|
|
|
29
29
|
else opts.projectionValidate = this._getProjectionFromBlacklist(opts.update ? 'update' : 'insert', opts.blacklist)
|
|
30
30
|
|
|
31
31
|
// Hook: beforeValidate
|
|
32
|
-
|
|
33
|
-
await util.runSeries.call(this, this.beforeValidate.map(f => f.bind(opts, data)), 'beforeValidate')
|
|
32
|
+
data = await util.runSeries.call(this, this.beforeValidate.map(f => f.bind(opts)), 'beforeValidate', data)
|
|
34
33
|
|
|
35
34
|
// Recurse and validate fields
|
|
36
35
|
let response = util.toArray(data).map(item => {
|
package/lib/util.js
CHANGED
|
@@ -193,7 +193,8 @@ module.exports = {
|
|
|
193
193
|
* @param {object}
|
|
194
194
|
* @return promise(data)
|
|
195
195
|
*/
|
|
196
|
-
|
|
196
|
+
let data = this.parseDotNotation(obj)
|
|
197
|
+
return this.parseFormData(data)
|
|
197
198
|
},
|
|
198
199
|
|
|
199
200
|
parseDotNotation: function(obj) {
|
|
@@ -201,18 +202,20 @@ module.exports = {
|
|
|
201
202
|
* Mutates dot notation objects into a deep object
|
|
202
203
|
* @param {object}
|
|
203
204
|
*/
|
|
204
|
-
|
|
205
|
+
if (!Object.keys(obj).find(o => o.indexOf('.') !== -1)) return obj
|
|
206
|
+
let objCopy = this.deepCopy(obj) // maybe convert to JSON.parse(JSON.stringify(obj))
|
|
207
|
+
|
|
205
208
|
for (let key in obj) {
|
|
206
209
|
if (key.indexOf('.') !== -1) {
|
|
207
|
-
|
|
210
|
+
setup(key, obj[key], obj)
|
|
208
211
|
} else {
|
|
209
212
|
// Ordinary values may of been updated by the bracket notation values, we are
|
|
210
213
|
// reassigning, trying to preserve the order of keys (not always guaranteed in for loops)
|
|
211
|
-
obj[key] =
|
|
214
|
+
obj[key] = objCopy[key]
|
|
212
215
|
}
|
|
213
216
|
}
|
|
214
217
|
return obj
|
|
215
|
-
function
|
|
218
|
+
function setup(str, val, obj) {
|
|
216
219
|
let parentObj = obj
|
|
217
220
|
let grandparentObj = obj
|
|
218
221
|
let keys = str.split(/\./)
|
|
@@ -233,7 +236,6 @@ module.exports = {
|
|
|
233
236
|
},
|
|
234
237
|
|
|
235
238
|
parseFormData: function(obj) {
|
|
236
|
-
let original = this.deepCopy(obj)
|
|
237
239
|
/**
|
|
238
240
|
* Mutates FormData (bracket notation) objects into a deep object
|
|
239
241
|
* @param {object}
|
|
@@ -242,21 +244,22 @@ module.exports = {
|
|
|
242
244
|
* E.g. ['user']['petnames'][0]
|
|
243
245
|
* E.g. ['users'][0]['name']
|
|
244
246
|
*/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
setup(key)
|
|
252
|
-
} else {
|
|
253
|
-
// Ordinary values may of been updated by the bracket notation values, we are
|
|
254
|
-
// reassigning, trying to preserve the order of keys (not always guaranteed in for loops)
|
|
255
|
-
obj[key] = original[key]
|
|
256
|
-
}
|
|
247
|
+
if (!Object.keys(obj).find(o => o.indexOf('[') !== -1)) return obj
|
|
248
|
+
let objCopy = this.deepCopy(obj) // maybe convert to JSON.parse(JSON.stringify(obj))
|
|
249
|
+
|
|
250
|
+
for (let key in obj) {
|
|
251
|
+
if (key.match(/\[\]\[/i)) {
|
|
252
|
+
throw new Error(`Monastery: Array items in bracket notation need array indexes "${key}", e.g. users[0][name]`)
|
|
257
253
|
}
|
|
258
|
-
|
|
259
|
-
|
|
254
|
+
if (key.indexOf('[') !== -1) {
|
|
255
|
+
setup(key)
|
|
256
|
+
} else {
|
|
257
|
+
// Ordinary values may of been updated by the bracket notation values, we are
|
|
258
|
+
// reassigning, trying to preserve the order of keys (not always guaranteed in for loops)
|
|
259
|
+
obj[key] = objCopy[key]
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return obj
|
|
260
263
|
function setup(path) {
|
|
261
264
|
let parent = obj
|
|
262
265
|
let grandparent = obj
|
|
@@ -308,20 +311,21 @@ module.exports = {
|
|
|
308
311
|
return variable
|
|
309
312
|
},
|
|
310
313
|
|
|
311
|
-
runSeries: function(tasks, hookName,
|
|
314
|
+
runSeries: function(tasks, hookName, data) {
|
|
312
315
|
/*
|
|
313
|
-
* Runs functions in series
|
|
316
|
+
* Runs functions in series
|
|
314
317
|
* @param {function(err, result)[]} tasks - array of functions
|
|
315
318
|
* @param {string} <hookName> - e.g. 'afterFind'
|
|
319
|
+
* @param {any} data - data to pass to the first function
|
|
316
320
|
* @param {function(err, results[])} <cb>
|
|
317
321
|
* @return promise
|
|
318
322
|
* @this Model
|
|
319
323
|
* @source https://github.com/feross/run-series
|
|
320
324
|
*/
|
|
321
325
|
let current = 0
|
|
322
|
-
let results = []
|
|
323
326
|
let isSync = true
|
|
324
|
-
let caller =
|
|
327
|
+
let caller = (this.afterFindName || this.name) + '.' + hookName
|
|
328
|
+
let lastDefinedResult = data
|
|
325
329
|
|
|
326
330
|
return new Promise((res, rej) => {
|
|
327
331
|
const next = (i, err, result) => { // aka next(err, data)
|
|
@@ -330,8 +334,8 @@ module.exports = {
|
|
|
330
334
|
return
|
|
331
335
|
}
|
|
332
336
|
current++
|
|
333
|
-
|
|
334
|
-
if (!err && current < tasks.length) callTask(current)
|
|
337
|
+
if (!err && typeof result !== 'undefined') lastDefinedResult = result
|
|
338
|
+
if (!err && current < tasks.length) callTask(current, lastDefinedResult)
|
|
335
339
|
else done(err)
|
|
336
340
|
}
|
|
337
341
|
const done = (err) => {
|
|
@@ -339,13 +343,13 @@ module.exports = {
|
|
|
339
343
|
else end(err)
|
|
340
344
|
}
|
|
341
345
|
const end = (err) => {
|
|
342
|
-
if (cb) cb(err, results)
|
|
343
346
|
if (err) rej(err)
|
|
344
|
-
else res(
|
|
347
|
+
else res(lastDefinedResult)
|
|
345
348
|
}
|
|
346
|
-
const callTask = (i) => {
|
|
349
|
+
const callTask = (i, data) => {
|
|
347
350
|
const next2 = next.bind(null, i)
|
|
348
|
-
const
|
|
351
|
+
const args = hookName.match(/remove/i)? [next2] : [data, next2]
|
|
352
|
+
const res = tasks[i](...args)
|
|
349
353
|
if (res instanceof Promise) {
|
|
350
354
|
res.then((result) => next2(null, result)).catch((e) => next2(e))
|
|
351
355
|
}
|
|
@@ -353,7 +357,7 @@ module.exports = {
|
|
|
353
357
|
|
|
354
358
|
// Start
|
|
355
359
|
if (!tasks.length) done(null)
|
|
356
|
-
else callTask(current)
|
|
360
|
+
else callTask(current, lastDefinedResult)
|
|
357
361
|
|
|
358
362
|
isSync = false
|
|
359
363
|
})
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "monastery",
|
|
3
3
|
"description": "⛪ A simple, straightforward MongoDB ODM",
|
|
4
4
|
"author": "Ricky Boyce",
|
|
5
|
-
"version": "3.0.
|
|
5
|
+
"version": "3.0.22",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:boycce/monastery",
|
|
8
8
|
"homepage": "https://boycce.github.io/monastery/",
|
package/test/crud.js
CHANGED
|
@@ -687,7 +687,7 @@ test('count defaults', async () => {
|
|
|
687
687
|
.resolves.toEqual(2)
|
|
688
688
|
})
|
|
689
689
|
|
|
690
|
-
test('hooks', async () => {
|
|
690
|
+
test('hooks > basic', async () => {
|
|
691
691
|
let user = db.model('user', {
|
|
692
692
|
fields: {
|
|
693
693
|
first: { type: 'string'},
|
|
@@ -774,6 +774,123 @@ test('hooks', async () => {
|
|
|
774
774
|
await expect(user2.update({ query: userDoc2._id, data: { first: 'M', bad: true } })).rejects.toThrow('error2')
|
|
775
775
|
})
|
|
776
776
|
|
|
777
|
+
test('hooks > chained values', async () => {
|
|
778
|
+
let bookCount = 0
|
|
779
|
+
const afterInsertAsync = [
|
|
780
|
+
async (data) => {
|
|
781
|
+
return // ignored
|
|
782
|
+
},
|
|
783
|
+
async (data) => {
|
|
784
|
+
data.first = 'Martin11'
|
|
785
|
+
},
|
|
786
|
+
async (data) => {
|
|
787
|
+
expect(data.first).toEqual('Martin11')
|
|
788
|
+
return { ...data, first: 'Martin' }
|
|
789
|
+
},
|
|
790
|
+
async (data) => {
|
|
791
|
+
expect(data.first).toEqual('Martin')
|
|
792
|
+
return // ignored
|
|
793
|
+
},
|
|
794
|
+
]
|
|
795
|
+
const afterFindAsync = [
|
|
796
|
+
async (data) => {
|
|
797
|
+
return // ignored
|
|
798
|
+
},
|
|
799
|
+
async (data) => {
|
|
800
|
+
bookCount++
|
|
801
|
+
if (data.bookNumber) data.bookNumber += (1 + bookCount)
|
|
802
|
+
else data.first = 'Martin2'
|
|
803
|
+
},
|
|
804
|
+
async (data) => {
|
|
805
|
+
if (data.bookNumber) {
|
|
806
|
+
expect(data).toEqual({ _id: expect.any(Object), bookNumber: 11 + bookCount })
|
|
807
|
+
return { _id: 1, bookNumber: 11 + bookCount }
|
|
808
|
+
} else {
|
|
809
|
+
expect(data).toEqual({ _id: expect.any(Object), first: 'Martin2', books: data.books })
|
|
810
|
+
return { _id: 2, books: data.books }
|
|
811
|
+
}
|
|
812
|
+
},
|
|
813
|
+
async (data) => {
|
|
814
|
+
if (data._id == 1) expect(data).toEqual({ _id: 1, bookNumber: 11 + bookCount })
|
|
815
|
+
else expect(data).toEqual({ _id: 2, books: data.books })
|
|
816
|
+
return // ignored
|
|
817
|
+
},
|
|
818
|
+
]
|
|
819
|
+
const afterFindCallback = [
|
|
820
|
+
(data, next) => {
|
|
821
|
+
next() // ignored
|
|
822
|
+
},
|
|
823
|
+
(data, next) => {
|
|
824
|
+
bookCount++
|
|
825
|
+
if (data.bookNumber) data.bookNumber += (1 + bookCount)
|
|
826
|
+
else data.first = 'Martin2'
|
|
827
|
+
next()
|
|
828
|
+
},
|
|
829
|
+
(data, next) => {
|
|
830
|
+
if (data.bookNumber) {
|
|
831
|
+
expect(data).toEqual({ _id: expect.any(Object), bookNumber: 11 + bookCount })
|
|
832
|
+
next(null, { _id: 1, bookNumber: 11 + bookCount })
|
|
833
|
+
} else {
|
|
834
|
+
expect(data).toEqual({ _id: expect.any(Object), first: 'Martin2', books: data.books })
|
|
835
|
+
next(null, { _id: 2, books: data.books })
|
|
836
|
+
}
|
|
837
|
+
},
|
|
838
|
+
(data, next) => {
|
|
839
|
+
if (data._id == 1) expect(data).toEqual({ _id: 1, bookNumber: 11 + bookCount })
|
|
840
|
+
else expect(data).toEqual({ _id: 2, books: data.books })
|
|
841
|
+
next() // ignored
|
|
842
|
+
},
|
|
843
|
+
]
|
|
844
|
+
|
|
845
|
+
// Async
|
|
846
|
+
db.model('book', {
|
|
847
|
+
fields: { bookNumber: { type: 'number'} },
|
|
848
|
+
afterFind: afterFindAsync,
|
|
849
|
+
})
|
|
850
|
+
db.model('user', {
|
|
851
|
+
fields: { first: { type: 'string'}, books: [{ model: 'book' }] },
|
|
852
|
+
afterInsert: afterInsertAsync,
|
|
853
|
+
afterFind: afterFindAsync,
|
|
854
|
+
})
|
|
855
|
+
let bookDoc = await db.book.insert({ data: { bookNumber: 10 }})
|
|
856
|
+
let bookDoc2 = await db.book.insert({ data: { bookNumber: 10 }})
|
|
857
|
+
let userDoc = await db.user.insert({ data: { first: 'Martin0', books: [bookDoc._id, bookDoc2._id]}})
|
|
858
|
+
|
|
859
|
+
// AfterInsert async
|
|
860
|
+
expect(userDoc).toEqual({
|
|
861
|
+
_id: expect.any(Object),
|
|
862
|
+
first: 'Martin',
|
|
863
|
+
books: [bookDoc._id, bookDoc2._id],
|
|
864
|
+
})
|
|
865
|
+
|
|
866
|
+
// AfterFind async
|
|
867
|
+
await expect(db.user.find({ query: userDoc._id, populate: ['books'] })).resolves.toEqual({
|
|
868
|
+
_id: 2,
|
|
869
|
+
books: [
|
|
870
|
+
{ _id: 1, bookNumber: 12 },
|
|
871
|
+
{ _id: 1, bookNumber: 13 },
|
|
872
|
+
],
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
// AfterFind callback/next
|
|
876
|
+
db.model('book', {
|
|
877
|
+
fields: { bookNumber: { type: 'number'} },
|
|
878
|
+
afterFind: afterFindCallback,
|
|
879
|
+
})
|
|
880
|
+
db.model('user', {
|
|
881
|
+
fields: { first: { type: 'string'}, books: [{ model: 'book' }] },
|
|
882
|
+
afterFind: afterFindCallback,
|
|
883
|
+
})
|
|
884
|
+
await expect(db.user.find({ query: userDoc._id, populate: ['books'] })).resolves.toEqual({
|
|
885
|
+
_id: 2,
|
|
886
|
+
books: [
|
|
887
|
+
{ _id: 1, bookNumber: 15 },
|
|
888
|
+
{ _id: 1, bookNumber: 16 },
|
|
889
|
+
],
|
|
890
|
+
})
|
|
891
|
+
|
|
892
|
+
})
|
|
893
|
+
|
|
777
894
|
test('hooks > async', async () => {
|
|
778
895
|
let user = db.model('user', {
|
|
779
896
|
fields: {
|
|
@@ -954,19 +1071,19 @@ test('hooks > async and next conflict', async () => {
|
|
|
954
1071
|
|
|
955
1072
|
// Only increment twice
|
|
956
1073
|
await expect(user1.find({ query: user1Doc._id })).resolves.toEqual({ _id: expect.any(Object), age: 2 })
|
|
957
|
-
expect(logSpy).toHaveBeenCalledWith('Monastery afterFind error: you cannot return a promise AND call next()')
|
|
1074
|
+
expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
|
|
958
1075
|
|
|
959
1076
|
await expect(user2.find({ query: user2Doc._id })).resolves.toEqual({ _id: expect.any(Object), age: 2 })
|
|
960
|
-
expect(logSpy).toHaveBeenCalledWith('Monastery afterFind error: you cannot return a promise AND call next()')
|
|
1077
|
+
expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
|
|
961
1078
|
|
|
962
1079
|
await expect(user3.find({ query: user3Doc._id })).resolves.toEqual({ _id: expect.any(Object), age: 2 })
|
|
963
|
-
expect(logSpy).toHaveBeenCalledWith('Monastery afterFind error: you cannot return a promise AND call next()')
|
|
1080
|
+
expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
|
|
964
1081
|
|
|
965
1082
|
await expect(user4.find({ query: user4Doc._id })).resolves.toEqual({ _id: expect.any(Object), age: 2 })
|
|
966
|
-
expect(logSpy).toHaveBeenCalledWith('Monastery afterFind error: you cannot return a promise AND call next()')
|
|
1083
|
+
expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
|
|
967
1084
|
|
|
968
1085
|
await expect(user5.find({ query: user5Doc._id })).rejects.toThrow('An async error occurred with Martin3')
|
|
969
|
-
expect(logSpy).toHaveBeenCalledWith('Monastery afterFind error: you cannot return a promise AND call next()')
|
|
1086
|
+
expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
|
|
970
1087
|
|
|
971
1088
|
db2.close()
|
|
972
1089
|
})
|
package/test/util.js
CHANGED
|
@@ -26,8 +26,9 @@ test('util > formdata', async () => {
|
|
|
26
26
|
{ 'first': 'Bruce', 'last': 'Lee' },
|
|
27
27
|
],
|
|
28
28
|
})
|
|
29
|
-
expect(util.parseFormData({ 'users[][\'name\']': 'Martin' })).
|
|
30
|
-
|
|
29
|
+
expect(() => util.parseFormData({ 'users[][\'name\']': 'Martin' })).toThrow(
|
|
30
|
+
'Monastery: Array items in bracket notation need array indexes "users[][\'name\']", e.g. users[0][name]'
|
|
31
|
+
)
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
test('util > isId', async () => {
|