monastery 1.28.4 → 1.28.5
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/.eslintrc.json +30 -4
- package/lib/index.js +0 -1
- package/lib/model-crud.js +32 -16
- package/lib/model-validate.js +10 -8
- package/lib/model.js +12 -4
- package/lib/rules.js +9 -12
- package/lib/util.js +13 -7
- package/package.json +16 -15
- package/plugins/images/index.js +4 -4
- package/test/blacklisting.js +4 -8
- package/test/crud.js +28 -31
- package/test/model.js +22 -25
- package/test/monk.js +4 -4
- package/test/plugin-images.js +400 -390
- package/test/populate.js +15 -18
- package/test/util.js +8 -8
- package/test/validate.js +50 -43
- package/test/virtuals.js +2 -4
package/.eslintrc.json
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true,
|
|
5
|
+
"node": true
|
|
6
|
+
},
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended"
|
|
9
|
+
],
|
|
10
|
+
"globals": {
|
|
11
|
+
"test": true,
|
|
12
|
+
"expect": true
|
|
13
|
+
},
|
|
2
14
|
"parserOptions": {
|
|
3
|
-
"ecmaVersion": 2018,
|
|
4
|
-
"sourceType": "module",
|
|
5
15
|
"ecmaFeatures": {
|
|
6
16
|
"jsx": true
|
|
7
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"ecmaVersion": "latest",
|
|
19
|
+
"sourceType": "module"
|
|
8
20
|
},
|
|
21
|
+
"plugins": [],
|
|
9
22
|
"rules": {
|
|
10
|
-
|
|
23
|
+
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
|
24
|
+
"max-len": ["error", { "code": 120, "ignorePattern": "^\\s*<(rect|path|line)\\s" }],
|
|
25
|
+
"no-prototype-builtins": "off",
|
|
26
|
+
"no-unused-vars": ["error", { "args": "none" }],
|
|
27
|
+
"object-shorthand": ["error", "consistent"],
|
|
28
|
+
// "no-restricted-syntax": [
|
|
29
|
+
// "error",
|
|
30
|
+
// {
|
|
31
|
+
// "selector": "ObjectPattern > Property[shorthand=false]",
|
|
32
|
+
// "message": "Renaming properties within object deconstructions is not allowed."
|
|
33
|
+
// }
|
|
34
|
+
// ],
|
|
35
|
+
"quotes": ["error", "single"],
|
|
36
|
+
"semi": ["error", "never"]
|
|
11
37
|
}
|
|
12
38
|
}
|
package/lib/index.js
CHANGED
package/lib/model-crud.js
CHANGED
|
@@ -9,7 +9,8 @@ module.exports = {
|
|
|
9
9
|
* @param {object|array} <opts.data> - documents to insert
|
|
10
10
|
* @param {array|string|false} <opts.blacklist> - augment schema.insertBL, `false` will remove all blacklisting
|
|
11
11
|
* @param {boolean} <opts.respond> - automatically call res.json/error (requires opts.req)
|
|
12
|
-
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or
|
|
12
|
+
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or
|
|
13
|
+
* undefined subdocument required fields that have a defined parent/grandparent during update
|
|
13
14
|
* @param {array|string|true} <opts.skipValidation> - skip validation for this field name(s)
|
|
14
15
|
* @param {boolean} <opts.timestamps> - whether `createdAt` and `updatedAt` are automatically inserted
|
|
15
16
|
* @param {any} <opts.any> - any mongodb option
|
|
@@ -21,7 +22,9 @@ module.exports = {
|
|
|
21
22
|
opts.insert = true
|
|
22
23
|
opts.model = this
|
|
23
24
|
let data = opts.data = opts.data || (opts.req? opts.req.body : {})
|
|
24
|
-
let options = util.omit(opts, [
|
|
25
|
+
let options = util.omit(opts, [
|
|
26
|
+
'data', 'insert', 'model', 'respond', 'ignoreUndefined', 'skipValidation', 'blacklist'
|
|
27
|
+
])
|
|
25
28
|
if (cb && !util.isFunction(cb)) {
|
|
26
29
|
throw new Error(`The callback passed to ${this.name}.insert() is not a function`)
|
|
27
30
|
}
|
|
@@ -75,7 +78,7 @@ module.exports = {
|
|
|
75
78
|
opts.one = one || opts.one
|
|
76
79
|
// Operation options
|
|
77
80
|
options = util.omit(opts, ['blacklist', 'one', 'populate', 'project', 'query', 'respond'])
|
|
78
|
-
options.sort = options.sort || {
|
|
81
|
+
options.sort = options.sort || { 'createdAt': -1 }
|
|
79
82
|
options.skip = Math.max(0, options.skip || 0)
|
|
80
83
|
options.limit = opts.one? 1 : parseInt(options.limit || this.manager.limit || 0)
|
|
81
84
|
options.addFields = options.addFields || {}
|
|
@@ -99,8 +102,8 @@ module.exports = {
|
|
|
99
102
|
}
|
|
100
103
|
// Has text search?
|
|
101
104
|
// if (opts.query.$text) {
|
|
102
|
-
// options.projection.score = { $meta:
|
|
103
|
-
// options.sort = { score: { $meta:
|
|
105
|
+
// options.projection.score = { $meta: 'textScore' }
|
|
106
|
+
// options.sort = { score: { $meta: 'textScore' }}
|
|
104
107
|
// }
|
|
105
108
|
// Sort string passed
|
|
106
109
|
if (util.isString(options.sort)) {
|
|
@@ -130,7 +133,7 @@ module.exports = {
|
|
|
130
133
|
continue
|
|
131
134
|
}
|
|
132
135
|
// Populate model (convert array into document & create lookup)
|
|
133
|
-
options.addFields[path] = {
|
|
136
|
+
options.addFields[path] = { '$arrayElemAt': [ '$' + path, 0 ] }
|
|
134
137
|
lookups.push({ $lookup: {
|
|
135
138
|
from: modelName,
|
|
136
139
|
localField: path,
|
|
@@ -191,7 +194,8 @@ module.exports = {
|
|
|
191
194
|
* @param {object} <opts.query> - mongodb query object
|
|
192
195
|
* @param {object|array} <opts.data> - mongodb document update object(s)
|
|
193
196
|
* @param {boolean} <opts.respond> - automatically call res.json/error (requires opts.req)
|
|
194
|
-
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or
|
|
197
|
+
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or
|
|
198
|
+
* undefined subdocument required fields that have a defined parent/grandparent during update
|
|
195
199
|
* @param {array|string|true} <opts.skipValidation> - skip validation for this field name(s)
|
|
196
200
|
* @param {boolean} <opts.timestamps> - whether `updatedAt` is automatically updated
|
|
197
201
|
* @param {array|string|false} <opts.blacklist> - augment schema.updateBL, `false` will remove all blacklisting
|
|
@@ -212,7 +216,7 @@ module.exports = {
|
|
|
212
216
|
operators = util.pluck(opts, [/^\$/])
|
|
213
217
|
// Operation options
|
|
214
218
|
options = util.omit(opts, ['data', 'query', 'respond', 'ignoreUndefined', 'skipValidation', 'blacklist'])
|
|
215
|
-
options.sort = options.sort || {
|
|
219
|
+
options.sort = options.sort || { 'createdAt': -1 }
|
|
216
220
|
options.limit = parseInt(options.limit || 0)
|
|
217
221
|
// Sort string passed
|
|
218
222
|
if (util.isString(options.sort)) {
|
|
@@ -283,7 +287,7 @@ module.exports = {
|
|
|
283
287
|
if (util.isEmpty(opts.query)) throw new Error('Please specify opts.query')
|
|
284
288
|
// Operation options
|
|
285
289
|
options = util.omit(opts, ['query', 'respond'])
|
|
286
|
-
options.sort = options.sort || {
|
|
290
|
+
options.sort = options.sort || { 'createdAt': -1 }
|
|
287
291
|
options.limit = parseInt(options.limit || 1)
|
|
288
292
|
// Sort string passed
|
|
289
293
|
if (util.isString(options.sort)) {
|
|
@@ -397,7 +401,7 @@ module.exports = {
|
|
|
397
401
|
let paths = (populate||[]).map(o => o && o.as? o.as : o)
|
|
398
402
|
|
|
399
403
|
if (!paths.length) return blacklistProjection
|
|
400
|
-
this._recurseFields(model.fields,
|
|
404
|
+
this._recurseFields(model.fields, '', function(path, field) {
|
|
401
405
|
// Remove array indexes from the path e.g. '0.'
|
|
402
406
|
path = path.replace(/(\.[0-9]+)(\.|$)/, '$2')
|
|
403
407
|
if (!field.model || !paths.includes(path)) return
|
|
@@ -420,7 +424,8 @@ module.exports = {
|
|
|
420
424
|
/**
|
|
421
425
|
* Merge blacklist in
|
|
422
426
|
* @param {object} blacklistProjection
|
|
423
|
-
* @param {array} paths - e.g. ['password', '-email'] - email will be whitelisted / removed from
|
|
427
|
+
* @param {array} paths - e.g. ['password', '-email'] - email will be whitelisted / removed from
|
|
428
|
+
* exlcusion projection
|
|
424
429
|
* @return {object} exclusion blacklist
|
|
425
430
|
* @this model
|
|
426
431
|
*/
|
|
@@ -461,7 +466,7 @@ module.exports = {
|
|
|
461
466
|
let findWL = [ '_id', ...this.findWL ]
|
|
462
467
|
let model = this.manager.model
|
|
463
468
|
|
|
464
|
-
this._recurseFields(this.fields,
|
|
469
|
+
this._recurseFields(this.fields, '', function(path, field) {
|
|
465
470
|
// Remove array indexes from the path e.g. '0.'
|
|
466
471
|
path = path.replace(/(\.[0-9]+)(\.|$)/, '$2')
|
|
467
472
|
//if (field.type == 'any') findWL.push(path) //exclude.push(path)
|
|
@@ -529,7 +534,7 @@ module.exports = {
|
|
|
529
534
|
}
|
|
530
535
|
|
|
531
536
|
for (let doc of util.toArray(data)) {
|
|
532
|
-
recurseAndDeleteData(doc,
|
|
537
|
+
recurseAndDeleteData(doc, '')
|
|
533
538
|
}
|
|
534
539
|
return data
|
|
535
540
|
},
|
|
@@ -586,7 +591,11 @@ module.exports = {
|
|
|
586
591
|
if (!data) return
|
|
587
592
|
|
|
588
593
|
// Valid model object field.
|
|
589
|
-
if (
|
|
594
|
+
if (
|
|
595
|
+
((util.isArray(field) && field[0].model) || field.model) &&
|
|
596
|
+
data[fieldName] &&
|
|
597
|
+
util.isObjectAndNotID(data[fieldName])
|
|
598
|
+
) {
|
|
590
599
|
// Note that sometimes a single model is passed instead of an array of models via a custom populate $lookup
|
|
591
600
|
out.push({
|
|
592
601
|
dataRef: data[fieldName],
|
|
@@ -595,11 +604,18 @@ module.exports = {
|
|
|
595
604
|
})
|
|
596
605
|
|
|
597
606
|
// Recurse through fields that are sub-documents
|
|
598
|
-
} else if (
|
|
607
|
+
} else if (
|
|
608
|
+
util.isSubdocument(field) &&
|
|
609
|
+
util.isObjectAndNotID(data[fieldName])
|
|
610
|
+
) {
|
|
599
611
|
out = [...out, ...this._recurseAndFindModels(field, data[fieldName])]
|
|
600
612
|
|
|
601
613
|
// Array of sub-documents or models
|
|
602
|
-
} else if (
|
|
614
|
+
} else if (
|
|
615
|
+
(util.isArray(field) || field.model) &&
|
|
616
|
+
data[fieldName] &&
|
|
617
|
+
util.isObjectAndNotID(data[fieldName][0])
|
|
618
|
+
) {
|
|
603
619
|
// Valid model object found in array
|
|
604
620
|
// Note that sometimes an array of models are passed instead of single object via a custom populate $lookup
|
|
605
621
|
if (field.model || field[0].model) {
|
package/lib/model-validate.js
CHANGED
|
@@ -12,9 +12,11 @@ module.exports = {
|
|
|
12
12
|
* @param {boolean(false)} update - are we validating for insert or update?
|
|
13
13
|
* @param {array|string|false} blacklist - augment schema blacklist, `false` will remove all blacklisting
|
|
14
14
|
* @param {array|string} projection - only return these fields, ignores blacklist
|
|
15
|
-
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or undefined
|
|
15
|
+
* @param {array|string|true} ignoreUndefined - ignore all required fields during insert, or undefined
|
|
16
|
+
* subdocument required fields that have a defined parent/grandparent during update
|
|
16
17
|
* @param {array|string|true} skipValidation - skip validation on these fields
|
|
17
|
-
* @param {boolean} timestamps - whether `createdAt` and `updatedAt` are inserted, or `updatedAt` is
|
|
18
|
+
* @param {boolean} timestamps - whether `createdAt` and `updatedAt` are inserted, or `updatedAt` is
|
|
19
|
+
* updated, depending on the `options.update` value
|
|
18
20
|
* @param {function} <cb> - instead of returning a promise
|
|
19
21
|
* @this model
|
|
20
22
|
|
|
@@ -56,7 +58,7 @@ module.exports = {
|
|
|
56
58
|
else continue
|
|
57
59
|
if (whitelist.includes(split.join())) {
|
|
58
60
|
blacklist.splice(i, 1)
|
|
59
|
-
break
|
|
61
|
+
break
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
}
|
|
@@ -189,11 +191,11 @@ module.exports = {
|
|
|
189
191
|
errors.push(...(verrors = this._validateRules(dataRoot, schema, value, opts, path2)))
|
|
190
192
|
// Data value is array too
|
|
191
193
|
if (util.isArray(value)) {
|
|
192
|
-
var
|
|
193
|
-
errors.push(...
|
|
194
|
+
var res2 = this._validateFields(dataRoot, field, value, opts, path2)
|
|
195
|
+
errors.push(...res2[0])
|
|
194
196
|
}
|
|
195
197
|
if (util.isDefined(value) && !verrors.length) {
|
|
196
|
-
data2[indexOrFieldName] =
|
|
198
|
+
data2[indexOrFieldName] = res2? res2[1] : value
|
|
197
199
|
}
|
|
198
200
|
}
|
|
199
201
|
}, this)
|
|
@@ -234,7 +236,7 @@ module.exports = {
|
|
|
234
236
|
for (let i=0, l=skippedFieldChunks.length; i<l; i++) {
|
|
235
237
|
if (skippedFieldChunks[i] == '$') skippedFieldChunks[i] = '[0-9]+'
|
|
236
238
|
}
|
|
237
|
-
if (path.match(new RegExp('^' + skippedFieldChunks.join('.') + '(
|
|
239
|
+
if (path.match(new RegExp('^' + skippedFieldChunks.join('.') + '(.|$)'))) return []
|
|
238
240
|
}
|
|
239
241
|
}
|
|
240
242
|
|
|
@@ -254,7 +256,7 @@ module.exports = {
|
|
|
254
256
|
// Remove [] from the message path, and simply ignore non-numeric children to test for all array items
|
|
255
257
|
ruleArg = ruleArg === true? undefined : ruleArg
|
|
256
258
|
let rule = this.rules[ruleName] || rules[ruleName]
|
|
257
|
-
let fieldName = path.match(/[
|
|
259
|
+
let fieldName = path.match(/[^.]+$/)[0]
|
|
258
260
|
let ruleMessageKey = this._getMostSpecificKeyMatchingPath(this.messages, path)
|
|
259
261
|
let ruleMessage = ruleMessageKey && this.messages[ruleMessageKey][ruleName]
|
|
260
262
|
if (!ruleMessage) ruleMessage = rule.message
|
package/lib/model.js
CHANGED
|
@@ -203,7 +203,12 @@ Model.prototype._setupFields = function(fields) {
|
|
|
203
203
|
let nullObject = this.manager.nullObjects
|
|
204
204
|
let virtual = field.length == 1 && (field[0]||{}).virtual ? true : undefined
|
|
205
205
|
field.schema = {
|
|
206
|
-
type: 'array',
|
|
206
|
+
type: 'array',
|
|
207
|
+
isArray: true,
|
|
208
|
+
default: arrayDefault,
|
|
209
|
+
nullObject: nullObject,
|
|
210
|
+
virtual: virtual,
|
|
211
|
+
...(field.schema || {})
|
|
207
212
|
}
|
|
208
213
|
this._setupFields(field)
|
|
209
214
|
|
|
@@ -262,7 +267,10 @@ Model.prototype._setupIndexes = function(fields) {
|
|
|
262
267
|
|
|
263
268
|
// No db defined
|
|
264
269
|
if (!(model.manager._state || '').match(/^open/)) {
|
|
265
|
-
let error = {
|
|
270
|
+
let error = {
|
|
271
|
+
type: 'info',
|
|
272
|
+
detail: `Skipping createIndex on the '${model.name}' model, no mongodb connection found.`
|
|
273
|
+
}
|
|
266
274
|
return Promise.reject(error)
|
|
267
275
|
}
|
|
268
276
|
|
|
@@ -361,10 +369,10 @@ Model.prototype._timestampFields = {
|
|
|
361
369
|
}
|
|
362
370
|
}
|
|
363
371
|
|
|
364
|
-
for (
|
|
372
|
+
for (let key in crud) {
|
|
365
373
|
Model.prototype[key] = crud[key]
|
|
366
374
|
}
|
|
367
375
|
|
|
368
|
-
for (
|
|
376
|
+
for (let key in validate) {
|
|
369
377
|
Model.prototype[key] = validate[key]
|
|
370
378
|
}
|
package/lib/rules.js
CHANGED
|
@@ -36,8 +36,7 @@ module.exports = {
|
|
|
36
36
|
tryParse: function(x) {
|
|
37
37
|
if (x === '') return null
|
|
38
38
|
if (!util.isString(x)) return x
|
|
39
|
-
try { var parsed = JSON.parse(x) }
|
|
40
|
-
catch (e) { return x }
|
|
39
|
+
try { var parsed = JSON.parse(x) } catch (e) { return x }
|
|
41
40
|
return Array.isArray(parsed)? parsed : x
|
|
42
41
|
},
|
|
43
42
|
fn: function(x) {
|
|
@@ -47,11 +46,11 @@ module.exports = {
|
|
|
47
46
|
'isDate': {
|
|
48
47
|
message: 'Value was not a unix timestamp.',
|
|
49
48
|
tryParse: function(x) {
|
|
50
|
-
if (util.isString(x) && x.match(/^[
|
|
49
|
+
if (util.isString(x) && x.match(/^[+-]?[0-9]+$/)) return x // keep string nums intact
|
|
51
50
|
return isNaN(parseInt(x))? x : parseInt(x)
|
|
52
51
|
},
|
|
53
52
|
fn: function(x) {
|
|
54
|
-
if (util.isString(x) && x.match(/^[
|
|
53
|
+
if (util.isString(x) && x.match(/^[+-]?[0-9]+$/)) return true
|
|
55
54
|
return typeof x === 'number' && (parseInt(x) === x)
|
|
56
55
|
}
|
|
57
56
|
},
|
|
@@ -62,8 +61,7 @@ module.exports = {
|
|
|
62
61
|
tryParse: function(x) {
|
|
63
62
|
if (x === '') return null
|
|
64
63
|
if (!util.isString(x)) return x
|
|
65
|
-
try { var parsed = JSON.parse(x) }
|
|
66
|
-
catch (e) { return x }
|
|
64
|
+
try { var parsed = JSON.parse(x) } catch (e) { return x }
|
|
67
65
|
return parsed !== null && typeof parsed === 'object' && !(parsed instanceof Array)? parsed : x
|
|
68
66
|
},
|
|
69
67
|
fn: function(x) {
|
|
@@ -74,22 +72,22 @@ module.exports = {
|
|
|
74
72
|
'isInteger': {
|
|
75
73
|
message: 'Value was not an integer.',
|
|
76
74
|
tryParse: function(x) {
|
|
77
|
-
if (util.isString(x) && x.match(/^[
|
|
75
|
+
if (util.isString(x) && x.match(/^[+-][0-9]+$/)) return x // keep string nums intact
|
|
78
76
|
return isNaN(parseInt(x)) || (!x && x!==0) || x===true? x : parseInt(x)
|
|
79
77
|
},
|
|
80
78
|
fn: function(x) {
|
|
81
|
-
if (util.isString(x) && x.match(/^[
|
|
79
|
+
if (util.isString(x) && x.match(/^[+-]?[0-9]+$/)) return true
|
|
82
80
|
return typeof x === 'number' && (parseInt(x) === x)
|
|
83
81
|
}
|
|
84
82
|
},
|
|
85
83
|
'isNumber': {
|
|
86
84
|
message: 'Value was not a number.',
|
|
87
85
|
tryParse: function(x) {
|
|
88
|
-
if (util.isString(x) && x.match(/^[
|
|
86
|
+
if (util.isString(x) && x.match(/^[+-][0-9]+$/)) return x // keep string nums intact
|
|
89
87
|
return isNaN(Number(x)) || (!x && x!==0) || x===true? x : Number(x)
|
|
90
88
|
},
|
|
91
89
|
fn: function(x) {
|
|
92
|
-
if (util.isString(x) && x.match(/^[
|
|
90
|
+
if (util.isString(x) && x.match(/^[+-][0-9]+$/)) return true
|
|
93
91
|
return typeof x === 'number'
|
|
94
92
|
}
|
|
95
93
|
},
|
|
@@ -98,8 +96,7 @@ module.exports = {
|
|
|
98
96
|
tryParse: function(x) {
|
|
99
97
|
if (x === '') return null
|
|
100
98
|
if (!util.isString(x)) return x
|
|
101
|
-
try { var parsed = JSON.parse(x) }
|
|
102
|
-
catch (e) { return x }
|
|
99
|
+
try { var parsed = JSON.parse(x) } catch (e) { return x }
|
|
103
100
|
return parsed !== null && typeof parsed === 'object' && !(parsed instanceof Array)? parsed : x
|
|
104
101
|
},
|
|
105
102
|
fn: function(x) {
|
package/lib/util.js
CHANGED
|
@@ -9,7 +9,7 @@ module.exports = {
|
|
|
9
9
|
for (let key in obj) {
|
|
10
10
|
let v = obj[key]
|
|
11
11
|
if (this.isId(v)) obj2[key] = v.toString()
|
|
12
|
-
else obj2[key] = (typeof v ===
|
|
12
|
+
else obj2[key] = (typeof v === 'object')? this.deepCopy(v) : v
|
|
13
13
|
}
|
|
14
14
|
return obj2
|
|
15
15
|
},
|
|
@@ -165,7 +165,7 @@ module.exports = {
|
|
|
165
165
|
* @param {object}
|
|
166
166
|
*/
|
|
167
167
|
for (let key in obj) {
|
|
168
|
-
if (key.indexOf(
|
|
168
|
+
if (key.indexOf('.') !== -1) recurse(key, obj[key], obj)
|
|
169
169
|
}
|
|
170
170
|
return obj
|
|
171
171
|
function recurse(str, val, obj) {
|
|
@@ -199,8 +199,12 @@ module.exports = {
|
|
|
199
199
|
*/
|
|
200
200
|
return new Promise(res => {
|
|
201
201
|
for (let key in obj) {
|
|
202
|
-
if (key.match(/\[\]\[/i))
|
|
203
|
-
|
|
202
|
+
if (key.match(/\[\]\[/i)) {
|
|
203
|
+
throw `Array items in bracket notation need array indexes "${key}", e.g. users[0][name]`
|
|
204
|
+
}
|
|
205
|
+
if (key.indexOf('[') !== -1) {
|
|
206
|
+
setup(key)
|
|
207
|
+
}
|
|
204
208
|
}
|
|
205
209
|
res(obj)
|
|
206
210
|
})
|
|
@@ -241,7 +245,7 @@ module.exports = {
|
|
|
241
245
|
removeUndefined: (variable) => {
|
|
242
246
|
// takes an array or object
|
|
243
247
|
if (Array.isArray(variable)) {
|
|
244
|
-
for (let
|
|
248
|
+
for (let i=variable.length; i--;) {
|
|
245
249
|
if (variable[i] === undefined) variable.splice(i, 1)
|
|
246
250
|
}
|
|
247
251
|
} else {
|
|
@@ -308,7 +312,7 @@ module.exports = {
|
|
|
308
312
|
target[chunks[i]] = value
|
|
309
313
|
}
|
|
310
314
|
} else {
|
|
311
|
-
let isArray = chunks[i+1].match(/^[0-9
|
|
315
|
+
let isArray = chunks[i+1].match(/^[0-9$]+$/)
|
|
312
316
|
let parentCopy = target[chunks[i]] || (isArray? [] : {})
|
|
313
317
|
if (ignoreEmptyArrays && isArray && !parentCopy.length) break
|
|
314
318
|
target = target[chunks[i]] = parentCopy
|
|
@@ -316,7 +320,9 @@ module.exports = {
|
|
|
316
320
|
if (chunks[i+1] == '$') {
|
|
317
321
|
for (let m=0, n=target.length; m<n; m++) {
|
|
318
322
|
let newPath = chunks.slice(i+2).join('.')
|
|
319
|
-
if (newPath)
|
|
323
|
+
if (newPath) {
|
|
324
|
+
this.setDeepValue(target[m], newPath, value, onlyUndefined, onlyUndefinedNull, ignoreEmptyArrays)
|
|
325
|
+
}
|
|
320
326
|
}
|
|
321
327
|
break
|
|
322
328
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "monastery",
|
|
3
3
|
"description": "⛪ A straight forward MongoDB ODM built around Monk",
|
|
4
4
|
"author": "Ricky Boyce",
|
|
5
|
-
"version": "1.28.
|
|
5
|
+
"version": "1.28.5",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:boycce/monastery",
|
|
8
8
|
"homepage": "https://boycce.github.io/monastery/",
|
|
@@ -19,27 +19,28 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"minor": "standard-version --release-as minor && npm publish",
|
|
21
21
|
"patch": "standard-version && npm publish",
|
|
22
|
-
"test": "jest",
|
|
22
|
+
"test": "npm run lint && jest",
|
|
23
23
|
"test-one-example": "jest -t images",
|
|
24
|
-
"dev": "DEBUG=-monastery:info jest --watchAll --runInBand --verbose=false",
|
|
24
|
+
"dev": "npm run lint & DEBUG=-monastery:info jest --watchAll --runInBand --verbose=false",
|
|
25
|
+
"lint": "eslint ./lib ./plugins ./test",
|
|
25
26
|
"docs": "cd docs && bundle exec jekyll serve --livereload --livereload-port 4001"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"aws-sdk": "
|
|
29
|
+
"aws-sdk": "2.1062.0",
|
|
29
30
|
"debug": "4.1.1",
|
|
30
|
-
"file-type": "
|
|
31
|
-
"monk": "
|
|
32
|
-
"nanoid": "
|
|
33
|
-
"validator": "
|
|
31
|
+
"file-type": "15.0.0",
|
|
32
|
+
"monk": "7.3.4",
|
|
33
|
+
"nanoid": "3.2.0",
|
|
34
|
+
"validator": "13.7.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
|
-
"body-parser": "
|
|
37
|
-
"eslint": "
|
|
38
|
-
"express": "
|
|
39
|
-
"express-fileupload": "
|
|
40
|
-
"jest": "
|
|
41
|
-
"standard-version": "
|
|
42
|
-
"supertest": "
|
|
37
|
+
"body-parser": "1.19.0",
|
|
38
|
+
"eslint": "8.7.0",
|
|
39
|
+
"express": "4.17.1",
|
|
40
|
+
"express-fileupload": "1.2.0",
|
|
41
|
+
"jest": "27.4.7",
|
|
42
|
+
"standard-version": "9.3.2",
|
|
43
|
+
"supertest": "4.0.2"
|
|
43
44
|
},
|
|
44
45
|
"standard-version": {
|
|
45
46
|
"releaseCommitMessageFormat": "{{currentTag}}",
|
package/plugins/images/index.js
CHANGED
|
@@ -155,8 +155,8 @@ let plugin = module.exports = {
|
|
|
155
155
|
if (test) return [prunedData]
|
|
156
156
|
return model._update(
|
|
157
157
|
idquery,
|
|
158
|
-
{
|
|
159
|
-
{
|
|
158
|
+
{ '$set': prunedData },
|
|
159
|
+
{ 'multi': options.multi || options.create }
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
// If errors, remove inserted documents to prevent double ups when the user resaves.
|
|
@@ -246,7 +246,7 @@ let plugin = module.exports = {
|
|
|
246
246
|
// pre-existing image, push to unused
|
|
247
247
|
return plugin._findValidImages(options.files || {}, options.model).then(files => {
|
|
248
248
|
for (let filesArray of files) {
|
|
249
|
-
if (pre = preExistingImages.find(o => o.dataPath == filesArray.inputPath)) {
|
|
249
|
+
if ((pre = preExistingImages.find(o => o.dataPath == filesArray.inputPath))) {
|
|
250
250
|
useCount[pre.image.uid]--
|
|
251
251
|
}
|
|
252
252
|
}
|
|
@@ -380,7 +380,7 @@ let plugin = module.exports = {
|
|
|
380
380
|
let list = []
|
|
381
381
|
util.forEach(fields, (field, fieldName) => {
|
|
382
382
|
let path2 = `${path}.${fieldName}`.replace(/^\./, '')
|
|
383
|
-
let schema = field.schema || {}
|
|
383
|
+
// let schema = field.schema || {}
|
|
384
384
|
|
|
385
385
|
// Subdocument field
|
|
386
386
|
if (util.isSubdocument(field)) {//schema.isObject
|
package/test/blacklisting.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module.exports = function(monastery, opendb) {
|
|
2
2
|
|
|
3
|
-
test('Find blacklisting', async (
|
|
3
|
+
test('Find blacklisting', async () => {
|
|
4
4
|
// Setup
|
|
5
5
|
let db = (await opendb(null)).db
|
|
6
6
|
let bird = db.model('bird', {
|
|
@@ -150,10 +150,9 @@ module.exports = function(monastery, opendb) {
|
|
|
150
150
|
})
|
|
151
151
|
|
|
152
152
|
db.close()
|
|
153
|
-
done()
|
|
154
153
|
})
|
|
155
154
|
|
|
156
|
-
test('Find blacklisting (default fields)', async (
|
|
155
|
+
test('Find blacklisting (default fields)', async () => {
|
|
157
156
|
// Setup
|
|
158
157
|
let db = (await opendb(null)).db
|
|
159
158
|
let user = db.model('user', {
|
|
@@ -222,10 +221,9 @@ module.exports = function(monastery, opendb) {
|
|
|
222
221
|
})
|
|
223
222
|
|
|
224
223
|
db.close()
|
|
225
|
-
done()
|
|
226
224
|
})
|
|
227
225
|
|
|
228
|
-
test('Find blacklisting (populate)', async (
|
|
226
|
+
test('Find blacklisting (populate)', async () => {
|
|
229
227
|
// Setup
|
|
230
228
|
let db = (await opendb(null)).db
|
|
231
229
|
let bird = db.model('bird', {
|
|
@@ -305,10 +303,9 @@ module.exports = function(monastery, opendb) {
|
|
|
305
303
|
})
|
|
306
304
|
|
|
307
305
|
db.close()
|
|
308
|
-
done()
|
|
309
306
|
})
|
|
310
307
|
|
|
311
|
-
test('Insert/update blacklisting (validate)', async (
|
|
308
|
+
test('Insert/update blacklisting (validate)', async () => {
|
|
312
309
|
// Setup
|
|
313
310
|
let db = (await opendb(null)).db
|
|
314
311
|
let user = db.model('user', {
|
|
@@ -406,7 +403,6 @@ module.exports = function(monastery, opendb) {
|
|
|
406
403
|
}
|
|
407
404
|
})
|
|
408
405
|
db.close()
|
|
409
|
-
done()
|
|
410
406
|
})
|
|
411
407
|
|
|
412
408
|
}
|