monastery 1.30.2 → 1.31.1

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/model-crud.js CHANGED
@@ -21,14 +21,14 @@ module.exports = {
21
21
  opts = opts || {}
22
22
  opts.insert = true
23
23
  opts.model = this
24
- let data = opts.data = opts.data || (opts.req? opts.req.body : {})
24
+ let req = opts.req
25
+ let data = opts.data = util.isDefined(opts.data)? opts.data : util.isDefined((req||{}).body) ? req.body : {}
25
26
  let options = util.omit(opts, [
26
27
  'data', 'insert', 'model', 'respond', 'validateUndefined', 'skipValidation', 'blacklist'
27
28
  ])
28
29
  if (cb && !util.isFunction(cb)) {
29
30
  throw new Error(`The callback passed to ${this.name}.insert() is not a function`)
30
31
  }
31
-
32
32
  return util.parseData(data).then(data => {
33
33
  opts.data = data
34
34
  return this.validate(data, { ...opts })
@@ -124,12 +124,16 @@ module.exports = {
124
124
  } else {
125
125
  let modelName = (path.split('.').reduce((o,i) => o[i], this.fields) ||{}).model
126
126
  if (!modelName) {
127
- this.error(`The field "${path}" passed to populate is not of type
128
- model. You would need to add the field option e.g. { model: 'comment' } in your schema.`)
127
+ this.error(
128
+ `The field "${path}" passed to populate is not of type model. You would ` +
129
+ 'need to add the field option e.g. { model: \'comment\' } in your schema.'
130
+ )
129
131
  continue
130
132
  } else if (!this.manager.model[modelName]) {
131
- this.error(`The field's model defined in your schema does not exist:
132
- ${path}: { model: "${modelName}" }`)
133
+ this.error(
134
+ `The field's model defined in your schema does not exist: ${path}: ` +
135
+ `{ model: "${modelName}" }`
136
+ )
133
137
  continue
134
138
  }
135
139
  // Populate model (convert array into document & create lookup)
@@ -212,7 +216,8 @@ module.exports = {
212
216
  opts = this._queryObject(opts)
213
217
  opts.update = true
214
218
  opts.model = this
215
- data = opts.data = opts.data || (opts.req? opts.req.body : null)
219
+ let req = opts.req
220
+ data = opts.data = util.isDefined(opts.data)? opts.data : util.isDefined((req||{}).body) ? req.body : undefined
216
221
  operators = util.pluck(opts, [/^\$/])
217
222
  // Operation options
218
223
  options = util.omit(opts, ['data', 'query', 'respond', 'validateUndefined', 'skipValidation', 'blacklist'])
@@ -224,23 +229,32 @@ module.exports = {
224
229
  let order = (options.sort.match(/:(-?[0-9])/) || [])[1]
225
230
  options.sort = { [name]: parseInt(order || 1) }
226
231
  }
227
- if (operators['$set'] && data) {
228
- throw new Error(`Please only pass options.$set or options.data to ${this.name}.update()`)
229
- }
230
232
  util.parseData(data).then(d => resolve(d))
231
233
 
232
234
  }).then(data => {
233
235
  opts.data = data
234
- if (util.isEmpty(operators)) return this.validate(data, { ...opts })
236
+ if (util.isDefined(data)) return this.validate(data, { ...opts })
237
+ else return Promise.resolve(data)
235
238
 
236
239
  }).then(data => {
237
- if (util.isEmpty(operators) && (!data || util.isEmpty(data))) {
238
- throw new Error(`No valid data passed to ${this.name}.update()`)
240
+ if (util.isDefined(data) && (!data || util.isEmpty(data))) {
241
+ throw new Error(`No valid data passed to ${this.name}.update({ data: .. })`)
242
+ }
243
+ if (!util.isDefined(data) && util.isEmpty(operators)) {
244
+ throw new Error(`Please pass an update operator to ${this.name}.update(), e.g. data, $unset, etc`)
239
245
  }
240
246
  return util.runSeries(this.beforeUpdate.map(f => f.bind(opts, data||{}))).then(() => data)
241
247
 
242
248
  }).then(data => {
243
- if (data) operators['$set'] = data
249
+ if (data && operators['$set']) {
250
+ this.warn(`'$set' fields take precedence over the data fields for \`${this.name}.update()\``)
251
+ }
252
+ if (data || operators['$set']) {
253
+ operators['$set'] = {
254
+ ...data,
255
+ ...(operators['$set'] || {}),
256
+ }
257
+ }
244
258
  return this._update(opts.query, operators, options).then(output => {
245
259
  if (!output.n) return null
246
260
  let response = Object.assign(Object.create({ _output: output }), operators['$set']||{})
@@ -377,7 +391,8 @@ module.exports = {
377
391
  if (!this._pathInProjection(pathWithoutArrays, projection, true)) return
378
392
  // Ignore default
379
393
  let value = util.isFunction(schema.default)? schema.default(this.manager) : schema.default
380
- util.setDeepValue(item.dataRef, path.replace(/\.0(\.|$)/g, '.$$$1'), value, false, true, true)
394
+ // console.log(item.dataRef)
395
+ util.setDeepValue(item.dataRef, path.replace(/\.0(\.|$)/g, '.$$$1'), value, true, false, true)
381
396
  })
382
397
  }
383
398
  // Collect all of the model's afterFind hooks
@@ -140,7 +140,7 @@ module.exports = {
140
140
  let value = util.isArray(fields)? data : (data||{})[fieldName]
141
141
  let indexOrFieldName = util.isArray(fields)? i : fieldName
142
142
  let path2 = `${path}.${indexOrFieldName}`.replace(/^\./, '')
143
- let path3 = path2.replace(/(^|\.)[0-9]+(\.|$)/, '$2') // no numirical keys, e.g. pets.1.name
143
+ let path3 = path2.replace(/(^|\.)[0-9]+(\.|$)/, '$2') // no numerical keys, e.g. pets.1.name
144
144
  let isType = 'is' + util.ucFirst(schema.type)
145
145
  let isTypeRule = this.rules[isType] || rules[isType]
146
146
 
@@ -162,7 +162,7 @@ module.exports = {
162
162
  if (opts.update && schema.insertOnly) return
163
163
  // Ignore virtual fields
164
164
  if (schema.virtual) return
165
- // Type cast the value if tryParse is avaliable, .e.g. isInteger.tryParse
165
+ // Type cast the value if tryParse is available, .e.g. isInteger.tryParse
166
166
  if (isTypeRule && util.isFunction(isTypeRule.tryParse)) {
167
167
  value = isTypeRule.tryParse.call(dataRoot, value, fieldName, this)
168
168
  }
@@ -266,13 +266,16 @@ module.exports = {
266
266
  if (!ruleMessage) ruleMessage = rule.message
267
267
 
268
268
  // Ignore undefined (if updated root property, or ignoring)
269
- if ((!validateUndefined || (opts.update && !path.match(/\./))) && typeof value === 'undefined') return
269
+ if (typeof value === 'undefined' && (!validateUndefined || (opts.update && !path.match(/\./)))) return
270
270
 
271
- // Ignore null (if nullObject is set on objects or arrays) (todo: change to ignoreNull)
272
- if (field.nullObject && (field.isObject || field.isArray) && value === null) return
271
+ // Ignore null (if nullObject is set on objects or arrays)
272
+ if (value === null && (field.isObject || field.isArray) && field.nullObject) return
273
+
274
+ // Ignore null
275
+ if (value === null && !(field.isObject || field.isArray) && !rule.validateNull) return
273
276
 
274
277
  // Ignore empty strings
275
- if (!rule.validateEmptyString && value === '') return
278
+ if (value === '' && !rule.validateEmptyString) return
276
279
 
277
280
  // Rule failed
278
281
  if (!rule.fn.call(dataRoot, value, ruleArg, path, this)) return {
package/lib/model.js CHANGED
@@ -36,6 +36,7 @@ let Model = module.exports = function(name, opts, manager) {
36
36
  beforeValidate: opts.beforeValidate || [],
37
37
  error: manager.error,
38
38
  info: manager.info,
39
+ warn: manager.warn,
39
40
  insertBL: opts.insertBL || [],
40
41
  fields: { ...(util.deepCopy(opts.fields) || {}) },
41
42
  findBL: opts.findBL || ['password'],
@@ -61,6 +62,7 @@ let Model = module.exports = function(name, opts, manager) {
61
62
  // Update with formatted rule
62
63
  let formattedRule = util.isObject(rule)? rule : { fn: rule }
63
64
  if (!formattedRule.message) formattedRule.message = `Invalid data property for rule "${ruleName}".`
65
+ if (typeof formattedRule.validateNull == 'undefined') formattedRule.validateNull = true
64
66
  if (typeof formattedRule.validateEmptyString == 'undefined') formattedRule.validateEmptyString = true
65
67
  this.rules[ruleName] = formattedRule
66
68
  }
package/lib/rules.js CHANGED
@@ -5,7 +5,8 @@ let validator = require('validator')
5
5
  module.exports = {
6
6
 
7
7
  required: {
8
- validateUndefined: true,
8
+ validateUndefined: true, // (false for custom rules)
9
+ validateNull: true,
9
10
  validateEmptyString: true,
10
11
  message: 'This field is required.',
11
12
  fn: function(x) {
@@ -14,12 +15,13 @@ module.exports = {
14
15
  }
15
16
  },
16
17
 
17
- // Type rules below ignore undefined (default for custom model rules)
18
+ // "Type" rules below ignore undefined and null
18
19
 
19
- 'isBoolean': {
20
+ isBoolean: {
20
21
  validateEmptyString: true,
21
22
  message: 'Value was not a boolean.',
22
23
  tryParse: function(x) {
24
+ if (x === '') return null
23
25
  if (typeof x === 'string' && x === 'true') return true
24
26
  else if (typeof x === 'string' && x === 'false') return false
25
27
  else return x
@@ -28,7 +30,7 @@ module.exports = {
28
30
  return typeof x === 'boolean'
29
31
  }
30
32
  },
31
- 'isArray': {
33
+ isArray: {
32
34
  validateEmptyString: true,
33
35
  message: 'Value was not an array.',
34
36
  tryParse: function(x) {
@@ -41,10 +43,11 @@ module.exports = {
41
43
  return Array.isArray(x)
42
44
  }
43
45
  },
44
- 'isDate': {
46
+ isDate: {
45
47
  validateEmptyString: true,
46
48
  message: 'Value was not a unix timestamp.',
47
49
  tryParse: function(x) {
50
+ if (x === '') return null
48
51
  if (util.isString(x) && x.match(/^[+-]?[0-9]+$/)) return x // keep string nums intact
49
52
  return isNaN(parseInt(x))? x : parseInt(x)
50
53
  },
@@ -53,7 +56,7 @@ module.exports = {
53
56
  return typeof x === 'number' && (parseInt(x) === x)
54
57
  }
55
58
  },
56
- 'isImageObject': {
59
+ isImageObject: {
57
60
  validateEmptyString: true,
58
61
  message: 'Invalid image value',
59
62
  messageLong: 'Image fields need to either be null, undefined, file, or an object containing the following '
@@ -69,10 +72,11 @@ module.exports = {
69
72
  if (isObject && x.bucket && x.date && x.filename && x.filesize && x.path && x.uid) return true
70
73
  }
71
74
  },
72
- 'isInteger': {
75
+ isInteger: {
73
76
  validateEmptyString: true,
74
77
  message: 'Value was not an integer.',
75
78
  tryParse: function(x) {
79
+ if (x === '') return null
76
80
  if (util.isString(x) && x.match(/^[+-][0-9]+$/)) return x // keep string nums intact
77
81
  return isNaN(parseInt(x)) || (!x && x!==0) || x===true? x : parseInt(x)
78
82
  },
@@ -81,10 +85,11 @@ module.exports = {
81
85
  return typeof x === 'number' && (parseInt(x) === x)
82
86
  }
83
87
  },
84
- 'isNumber': {
88
+ isNumber: {
85
89
  validateEmptyString: true,
86
90
  message: 'Value was not a number.',
87
91
  tryParse: function(x) {
92
+ if (x === '') return null
88
93
  if (util.isString(x) && x.match(/^[+-][0-9]+$/)) return x // keep string nums intact
89
94
  return isNaN(Number(x)) || (!x && x!==0) || x===true? x : Number(x)
90
95
  },
@@ -93,7 +98,7 @@ module.exports = {
93
98
  return typeof x === 'number'
94
99
  }
95
100
  },
96
- 'isObject': {
101
+ isObject: {
97
102
  validateEmptyString: true,
98
103
  message: 'Value was not an object.',
99
104
  tryParse: function(x) {
@@ -106,21 +111,25 @@ module.exports = {
106
111
  return x !== null && typeof x === 'object' && !(x instanceof Array)
107
112
  }
108
113
  },
109
- 'isString': {
114
+ isString: {
110
115
  validateEmptyString: true,
111
116
  message: 'Value was not a string.',
117
+ tryParse: function(x) {
118
+ if (typeof x === 'number') return x + ''
119
+ else return x
120
+ },
112
121
  fn: function(x) {
113
122
  return typeof x === 'string'
114
123
  }
115
124
  },
116
- 'isAny': {
125
+ isAny: {
117
126
  validateEmptyString: true,
118
127
  message: '',
119
128
  fn: function(x) {
120
129
  return true
121
130
  }
122
131
  },
123
- 'isId': {
132
+ isId: {
124
133
  validateEmptyString: true,
125
134
  message: 'Value was not a valid ObjectId.',
126
135
  tryParse: function(x) {
@@ -135,34 +144,27 @@ module.exports = {
135
144
  return util.isObject(x) && ObjectId.isValid(x)/*x.get_inc*/? true : false
136
145
  }
137
146
  },
138
- 'max': {
139
- validateEmptyString: true,
147
+
148
+ /* "Number" rules below ignore undefined and null */
149
+
150
+ max: {
140
151
  message: (x, arg) => 'Value was greater than the configured maximum (' + arg + ')',
141
152
  fn: function(x, arg) {
142
153
  if (typeof x !== 'number') { throw new Error ('Value was not a number.') }
143
154
  return x <= arg
144
155
  }
145
156
  },
146
- 'min': {
147
- validateEmptyString: true,
157
+ min: {
148
158
  message: (x, arg) => 'Value was less than the configured minimum (' + arg + ')',
149
159
  fn: function(x, arg) {
150
160
  if (typeof x !== 'number') { throw new Error ('Value was not a number.') }
151
161
  return x >= arg
152
162
  }
153
163
  },
154
- 'isNotEmptyString': {
155
- validateEmptyString: true,
156
- message: 'Value was an empty string.',
157
- fn: function(x) {
158
- return x !== ''
159
- }
160
- },
161
164
 
162
- // Rules below ignore undefined, & empty strings
163
- // (e.g. an empty email field can be saved that isn't required)
165
+ /* "String" rules below ignore undefined, null, and empty strings */
164
166
 
165
- 'enum': {
167
+ enum: {
166
168
  message: (x, arg) => 'Invalid enum value',
167
169
  fn: function(x, arg) {
168
170
  for (let item of arg) {
@@ -170,51 +172,54 @@ module.exports = {
170
172
  }
171
173
  }
172
174
  },
173
- // 'hasAgreed': {
174
- // message: (x, arg) => 'Please agree to the terms and conditions.',
175
- // fn: function(x, arg) { return !x }
176
- // },
177
- 'isAfter': {
175
+ isAfter: {
178
176
  message: (x, arg) => 'Value was before the configured time (' + arg + ')',
179
177
  fn: function(x, arg) { return validator.isAfter(x, arg) }
180
178
  },
181
- 'isBefore': {
179
+ isBefore: {
182
180
  message: (x, arg) => 'Value was after the configured time (' + arg + ')',
183
181
  fn: function(x, arg) { return validator.isBefore(x, arg) }
184
182
  },
185
- 'isCreditCard': {
183
+ isCreditCard: {
186
184
  message: 'Value was not a valid credit card.',
187
185
  fn: function(x, arg) { return validator.isCreditCard(x, arg) }
188
186
  },
189
- 'isEmail': {
187
+ isEmail: {
190
188
  message: 'Please enter a valid email address.',
191
189
  fn: function(x, arg) { return validator.isEmail(x, arg) }
192
190
  },
193
- 'isHexColor': {
191
+ isHexColor: {
194
192
  message: 'Value was not a valid hex color.',
195
193
  fn: function(x, arg) { return validator.isHexColor(x, arg) }
196
194
  },
197
- 'isIn': {
195
+ isIn: {
198
196
  message: (x, arg) => 'Value was not in the configured whitelist (' + arg.join(', ') + ')',
199
197
  fn: function(x, arg) { return validator.isIn(x, arg) }
200
198
  },
201
- 'isIP': {
199
+ isIP: {
202
200
  message: 'Value was not a valid IP address.',
203
201
  fn: function(x, arg) { return validator.isIP(x, arg) }
204
202
  },
205
- 'isNotIn': {
203
+ isNotEmptyString: {
204
+ validateEmptyString: true,
205
+ message: 'Value was an empty string.',
206
+ fn: function(x) {
207
+ return x !== ''
208
+ }
209
+ },
210
+ isNotIn: {
206
211
  message: (x, arg) => 'Value was in the configured blacklist (' + arg.join(', ') + ')',
207
212
  fn: function(x, arg) { return !validator.isIn(x, arg) }
208
213
  },
209
- 'isURL': {
214
+ isURL: {
210
215
  message: 'Value was not a valid URL.',
211
216
  fn: function(x, arg) { return validator.isURL(x, arg === true? undefined : arg) }
212
217
  },
213
- 'isUUID': {
218
+ isUUID: {
214
219
  message: 'Value was not a valid UUID.',
215
220
  fn: function(x, arg) { return validator.isUUID(x) }
216
221
  },
217
- 'minLength': {
222
+ minLength: {
218
223
  message: function(x, arg) {
219
224
  if (typeof x === 'string') return 'Value needs to be at least ' + arg + ' characters long.'
220
225
  else return 'Value needs to contain a minimum of ' + arg + ' items.'
@@ -225,7 +230,7 @@ module.exports = {
225
230
  else return x.length >= arg
226
231
  }
227
232
  },
228
- 'maxLength': {
233
+ maxLength: {
229
234
  message: function(x, arg) {
230
235
  if (typeof x === 'string') return 'Value was longer than the configured maximum length (' + arg + ')'
231
236
  else return 'Value cannot contain more than ' + arg + ' items.'
@@ -236,7 +241,7 @@ module.exports = {
236
241
  else return x.length <= arg
237
242
  }
238
243
  },
239
- 'regex': {
244
+ regex: {
240
245
  message: (x, arg) => 'Value did not match the configured regular expression (' + arg + ')',
241
246
  fn: function(x, arg) {
242
247
  if (util.isRegex(arg)) return validator.matches(x, arg)
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.30.2",
5
+ "version": "1.31.1",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
@@ -23,7 +23,8 @@
23
23
  "test-one-example": "jest -t images",
24
24
  "dev": "npm run lint & DEBUG=-monastery:info jest --watchAll --runInBand --verbose=false",
25
25
  "lint": "eslint ./lib ./plugins ./test",
26
- "docs": "cd docs && bundle exec jekyll serve --livereload --livereload-port 4001"
26
+ "docs": "cd docs && bundle exec jekyll serve --livereload --livereload-port 4001",
27
+ "mong": "nodemon resources/mong.js"
27
28
  },
28
29
  "dependencies": {
29
30
  "aws-sdk": "2.1062.0",
@@ -39,6 +40,7 @@
39
40
  "express": "4.17.1",
40
41
  "express-fileupload": "1.2.0",
41
42
  "jest": "27.4.7",
43
+ "nodemon": "2.0.15",
42
44
  "standard-version": "9.3.2",
43
45
  "supertest": "4.0.2"
44
46
  },
@@ -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', {
@@ -152,7 +152,7 @@ module.exports = function(monastery, opendb) {
152
152
  db.close()
153
153
  })
154
154
 
155
- test('Find blacklisting (default fields)', async () => {
155
+ test('find blacklisting (default fields)', async () => {
156
156
  // Setup
157
157
  let db = (await opendb(null)).db
158
158
  let user = db.model('user', {
@@ -223,7 +223,7 @@ module.exports = function(monastery, opendb) {
223
223
  db.close()
224
224
  })
225
225
 
226
- test('Find blacklisting (populate)', async () => {
226
+ test('find blacklisting (populate)', async () => {
227
227
  // Setup
228
228
  let db = (await opendb(null)).db
229
229
  let bird = db.model('bird', {
@@ -305,7 +305,7 @@ module.exports = function(monastery, opendb) {
305
305
  db.close()
306
306
  })
307
307
 
308
- test('Insert/update blacklisting (validate)', async () => {
308
+ test('insert update blacklisting (validate)', async () => {
309
309
  // Setup
310
310
  let db = (await opendb(null)).db
311
311
  let user = db.model('user', {
package/test/crud.js CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  module.exports = function(monastery, opendb) {
4
4
 
5
- test('Basic operator calls', async () => {
5
+ test('basic operator calls', async () => {
6
6
  let db = (await opendb(null)).db
7
7
  let user = db.model('user', {
8
- fields: { name: { type: 'string' }},
9
- beforeValidate: [(data, next) => { beforeValidateHookCalled = true; next() }]
8
+ fields: {
9
+ name: { type: 'string' },
10
+ },
10
11
  })
11
12
 
12
13
  // Insert one
@@ -79,60 +80,6 @@ module.exports = function(monastery, opendb) {
79
80
  let findOne3 = await user.findOne(inserted2[0]._id.toString())
80
81
  expect(findOne3).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
81
82
 
82
- // Update
83
- let update = await user.update({
84
- query: inserted._id,
85
- data: { name: 'Martin Luther2' }
86
- })
87
- expect(update).toEqual({
88
- name: 'Martin Luther2'
89
- })
90
-
91
- // Update (no/empty data object)
92
- await expect(user.update({ query: inserted._id, data: {}}))
93
- .rejects.toThrow('No valid data passed to user.update()')
94
-
95
- await expect(user.update({ query: inserted._id }))
96
- .rejects.toThrow('No valid data passed to user.update()')
97
-
98
- // Update (no/empty data object, but has update operators
99
- await expect(user.update({ query: inserted._id, $set: { name: 'bruce' }}))
100
- .resolves.toEqual({ name: 'bruce' })
101
-
102
- await expect(user.update({ query: inserted._id, $pull: { name: 'bruce' }}))
103
- .rejects.toThrow('Cannot apply $pull to a non-array value') // gets passed no valid data check
104
-
105
- // Update (data & $set)
106
- await expect(user.update({ query: inserted._id, data: {}, $set: { name: 'bruce' }}))
107
- .rejects.toThrow('Please only pass options.$set or options.data to user.update()')
108
-
109
- // Update (with operators. Make sure beforeValidate isn't called)
110
- var beforeValidateHookCalled = false
111
- await user.update({ query: inserted._id, data: { name: 'bruce' }})
112
- expect(beforeValidateHookCalled).toEqual(true)
113
- beforeValidateHookCalled = false
114
- await user.update({ query: inserted._id, $set: { name: 'bruce' }})
115
- expect(beforeValidateHookCalled).toEqual(false)
116
-
117
- // Update multiple
118
- await user.update({
119
- query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }},
120
- data: { name: 'Martin Luther3' },
121
- multi: true
122
- })
123
- let findUpdated2 = await user.find({
124
- query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }}
125
- })
126
- expect(findUpdated2).toEqual([
127
- {
128
- _id: expect.any(Object),
129
- name: 'Martin Luther3'
130
- }, {
131
- _id: expect.any(Object),
132
- name: 'Martin Luther3'
133
- }
134
- ])
135
-
136
83
  // Remove
137
84
  let remove = await user.remove({ query: inserted._id })
138
85
  expect(remove.result).toEqual({ n: 1, ok: 1 })
@@ -140,7 +87,7 @@ module.exports = function(monastery, opendb) {
140
87
  db.close()
141
88
  })
142
89
 
143
- test('Insert defaults', async () => {
90
+ test('insert defaults', async () => {
144
91
  let db = (await opendb(null, { defaultObjects: true, serverSelectionTimeoutMS: 2000 })).db
145
92
  let db2 = (await opendb(null, { useMilliseconds: true, serverSelectionTimeoutMS: 2000 })).db
146
93
  let user = db.model('user', { fields: {
@@ -194,6 +141,65 @@ module.exports = function(monastery, opendb) {
194
141
  db2.close()
195
142
  })
196
143
 
144
+ test('update basics', async () => {
145
+ let db = (await opendb(null)).db
146
+ let user = db.model('user', {
147
+ fields: {
148
+ name: { type: 'string' },
149
+ },
150
+ })
151
+
152
+ // Insert
153
+ let inserted = await user.insert({ data: { name: 'Martin Luther' }})
154
+ expect(inserted).toEqual({
155
+ _id: expect.any(Object),
156
+ name: 'Martin Luther'
157
+ })
158
+
159
+ // Insert multiple
160
+ let inserted2 = await user.insert({ data: [{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }]})
161
+ expect(inserted2).toEqual([
162
+ {
163
+ _id: expect.any(Object),
164
+ name: 'Martin Luther1'
165
+ }, {
166
+ _id: expect.any(Object),
167
+ name: 'Martin Luther2'
168
+ }
169
+ ])
170
+
171
+ // Update
172
+ await expect(user.update({ query: inserted._id, data: { name: 'Martin Luther2' }}))
173
+ .resolves.toEqual({ name: 'Martin Luther2' })
174
+
175
+ // Update (no/empty data object)
176
+ await expect(user.update({ query: inserted._id, data: {}}))
177
+ .rejects.toThrow('No valid data passed to user.update({ data: .. })')
178
+
179
+ await expect(user.update({ query: inserted._id }))
180
+ .rejects.toThrow('Please pass an update operator to user.update(), e.g. data, $unset, etc')
181
+
182
+ // Update multiple
183
+ await user.update({
184
+ query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }},
185
+ data: { name: 'Martin Luther3' },
186
+ multi: true
187
+ })
188
+ let findUpdated2 = await user.find({
189
+ query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }}
190
+ })
191
+ expect(findUpdated2).toEqual([
192
+ {
193
+ _id: expect.any(Object),
194
+ name: 'Martin Luther3'
195
+ }, {
196
+ _id: expect.any(Object),
197
+ name: 'Martin Luther3'
198
+ }
199
+ ])
200
+ db.close()
201
+ })
202
+
197
203
  test('update defaults', async () => {
198
204
  let db = (await opendb(null, { useMilliseconds: true, serverSelectionTimeoutMS: 2000 })).db
199
205
  let user = db.model('user', {
@@ -235,7 +241,7 @@ module.exports = function(monastery, opendb) {
235
241
  query: inserted._id,
236
242
  data: {},
237
243
  timestamps: false
238
- })).rejects.toThrow('No valid data passed to user.update()')
244
+ })).rejects.toThrow('No valid data passed to user.update({ data: .. })')
239
245
 
240
246
  // UpdatedAt override (wont work)
241
247
  let updated4 = await user.update({
@@ -255,7 +261,51 @@ module.exports = function(monastery, opendb) {
255
261
  db.close()
256
262
  })
257
263
 
258
- test('Insert with id casting', async () => {
264
+ test('update operators', async () => {
265
+ let db = (await opendb(null)).db
266
+ let user = db.model('userOperators', {
267
+ fields: {
268
+ name: { type: 'string', minLength: 5 },
269
+ age: { type: 'number' },
270
+ },
271
+ beforeValidate: [(data, next) => { beforeValidateHookCalled = true; next() }]
272
+ })
273
+
274
+ let inserted = await user.insert({
275
+ data: { name: 'Bruce', age: 12 }
276
+ })
277
+
278
+ // No data object, but has another update operators
279
+ await expect(user.update({ query: inserted._id, $set: { name: 'bruce' }}))
280
+ .resolves.toEqual({ name: 'bruce' })
281
+
282
+ // Mixing data and $set, and $set skips validation (minLength)
283
+ await expect(user.update({ query: inserted._id, data: { name: 'bruce2', age: 12 }, $set: { name: 'john' }}))
284
+ .resolves.toEqual({ age: 12, name: 'john' })
285
+
286
+ // Two operators
287
+ await user.update({ query: inserted._id, $set: { name: 'john' }, $unset: { age: 1 }})
288
+ await expect(user.findOne({ query: inserted._id })).resolves.toEqual({
289
+ _id: expect.any(Object),
290
+ name: 'john',
291
+ })
292
+
293
+ // $pull on a non array (also gets passed no valid data check)
294
+ await expect(user.update({ query: inserted._id, $pull: { name: 'bruce' }}))
295
+ .rejects.toThrow('Cannot apply $pull to a non-array value')
296
+
297
+ // Non-data operators don't call beforeValidate
298
+ var beforeValidateHookCalled = false
299
+ await user.update({ query: inserted._id, data: { name: 'bruce' }})
300
+ expect(beforeValidateHookCalled).toEqual(true)
301
+ beforeValidateHookCalled = false
302
+ await user.update({ query: inserted._id, $set: { name: 'bruce' }})
303
+ expect(beforeValidateHookCalled).toEqual(false)
304
+
305
+ db.close()
306
+ })
307
+
308
+ test('insert with id casting', async () => {
259
309
  let db = (await opendb(null)).db
260
310
  db.model('company', { fields: {
261
311
  name: { type: 'string' }
@@ -279,56 +329,52 @@ module.exports = function(monastery, opendb) {
279
329
  db.close()
280
330
  })
281
331
 
282
- test('Find default field population', async () => {
332
+ test('find default field population', async () => {
283
333
  let db = (await opendb(null)).db
284
334
  let user = db.model('user', {
285
335
  fields: {
286
- name: { type: 'string'},
287
- addresses: [{ city: { type: 'string' }, country: { type: 'string' }}],
336
+ name: { type: 'string', default: 'Martin Luther' },
337
+ addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
338
+ address: { country: { type: 'string', default: 'Germany' }},
288
339
  pet: { dog: { model: 'dog' }},
289
340
  dogs: [{ model: 'dog' }], // virtual association
290
341
  }
291
342
  })
292
343
  let dog = db.model('dog', {
293
344
  fields: {
294
- name: { type: 'string' },
345
+ name: { type: 'string', default: 'Scruff' },
295
346
  user: { model: 'user' }
296
347
  }
297
348
  })
298
349
 
299
- // Insert documents and add
300
- let inserted = await dog.insert({ data: {} })
301
- let inserted2 = await user.insert({ data: {
350
+ // Default field doesn't override null
351
+ let nulldoc1 = await dog.insert({ data: { name: null }})
352
+ let nullfind1 = await dog.findOne({ query: nulldoc1._id })
353
+ expect(nullfind1).toEqual({ _id: nulldoc1._id, name: null })
354
+
355
+ // Default field doesn't override empty string
356
+ let nulldoc2 = await dog.insert({ data: { name: '' }})
357
+ let nullfind2 = await dog.findOne({ query: nulldoc2._id })
358
+ expect(nullfind2).toEqual({ _id: nulldoc2._id, name: '' })
359
+
360
+ // Default field overrides undefined
361
+ let nulldoc3 = await dog.insert({ data: { name: undefined }})
362
+ let nullfind3 = await dog.findOne({ query: nulldoc3._id })
363
+ expect(nullfind3).toEqual({ _id: nullfind3._id, name: 'Scruff' })
364
+
365
+ // Default field population test
366
+ // Note that addresses.1.country shouldn't be overriden
367
+ // Insert documents (without defaults)
368
+ let inserted = await dog._insert({})
369
+ let inserted2 = await user._insert({
302
370
  addresses: [
303
371
  { city: 'Frankfurt' },
304
372
  { city: 'Christchurch', country: 'New Zealand' }
305
373
  ],
306
374
  pet: { dog: inserted._id }
307
- }})
308
- await dog.update({
309
- query: inserted._id,
310
- data: { user: inserted2._id }
311
375
  })
376
+ await dog._update(inserted._id, { $set: { user: inserted2._id }})
312
377
 
313
- // Update models
314
- db.model('user', {
315
- fields: {
316
- name: { type: 'string', default: 'Martin Luther' },
317
- addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
318
- address: { country: { type: 'string', default: 'Germany' }},
319
- pet: { dog: { model: 'dog' }},
320
- dogs: [{ model: 'dog' }], // virtual association
321
- }
322
- })
323
- db.model('dog', {
324
- fields: {
325
- name: { type: 'string', default: 'Scruff' },
326
- user: { model: 'user' }
327
- }
328
- })
329
-
330
- // Default field population test
331
- // Note that addresses.1.country shouldn't be overriden
332
378
  let find1 = await user.findOne({
333
379
  query: inserted2._id,
334
380
  populate: ['pet.dog', {
@@ -369,7 +415,7 @@ module.exports = function(monastery, opendb) {
369
415
  db.close()
370
416
  })
371
417
 
372
- test('Hooks', async () => {
418
+ test('hooks', async () => {
373
419
  let db = (await opendb(null)).db
374
420
  let user = db.model('user', {
375
421
  fields: {
package/test/model.js CHANGED
@@ -1,6 +1,6 @@
1
1
  module.exports = function(monastery, opendb) {
2
2
 
3
- test('Model setup', async () => {
3
+ test('model setup', async () => {
4
4
  // Setup
5
5
  let db = (await opendb(false)).db
6
6
  let user = db.model('user', { fields: {
@@ -68,7 +68,7 @@ module.exports = function(monastery, opendb) {
68
68
  ))
69
69
  })
70
70
 
71
- test('Model setup with default fields', async () => {
71
+ test('model setup with default fields', async () => {
72
72
  // Setup
73
73
  let db = (await opendb(false, { defaultObjects: true })).db
74
74
 
@@ -90,7 +90,7 @@ module.exports = function(monastery, opendb) {
90
90
  })
91
91
  })
92
92
 
93
- test('Model setup with default objects', async () => {
93
+ test('model setup with default objects', async () => {
94
94
  // Setup
95
95
  let db = (await opendb(false, { defaultObjects: true })).db
96
96
  let user = db.model('user', { fields: {
@@ -115,7 +115,7 @@ module.exports = function(monastery, opendb) {
115
115
  })
116
116
  })
117
117
 
118
- test('Model indexes', async () => {
118
+ test('model indexes', async () => {
119
119
  // Setup: Need to test different types of indexes
120
120
  let db = (await opendb(null)).db
121
121
  // Setup: Drop previously tested collections
@@ -189,7 +189,7 @@ module.exports = function(monastery, opendb) {
189
189
  db.close()
190
190
  })
191
191
 
192
- test('Model subdocument indexes', async () => {
192
+ test('model subdocument indexes', async () => {
193
193
  // Setup: Need to test different types of indexes
194
194
  let db = (await opendb(null)).db
195
195
  // Setup: Drop previously tested collections
@@ -234,7 +234,7 @@ module.exports = function(monastery, opendb) {
234
234
  db.close()
235
235
  })
236
236
 
237
- test('Model array indexes', async () => {
237
+ test('model array indexes', async () => {
238
238
  // Setup: Need to test different types of indexes
239
239
  let db = (await opendb(null)).db
240
240
  // Setup: Drop previously tested collections
@@ -279,7 +279,7 @@ module.exports = function(monastery, opendb) {
279
279
  db.close()
280
280
  })
281
281
 
282
- test('Model 2dsphere indexes', async () => {
282
+ test('model 2dsphere indexes', async () => {
283
283
  // Setup. The tested model needs to be unique as race condition issue arises when the same model
284
284
  // with text indexes are setup at the same time
285
285
  let db = (await opendb(null)).db
@@ -339,7 +339,7 @@ module.exports = function(monastery, opendb) {
339
339
  db.close()
340
340
  })
341
341
 
342
- test('Model findBL, findBLProject', async () => {
342
+ test('model findBL findBLProject', async () => {
343
343
  let db = (await opendb(null)).db
344
344
  db.model('bird', { fields: {
345
345
  name: { type: 'string' }
package/test/populate.js CHANGED
@@ -1,6 +1,6 @@
1
1
  module.exports = function(monastery, opendb) {
2
2
 
3
- test('Model populate', async () => {
3
+ test('model populate', async () => {
4
4
  // Setup
5
5
  let db = (await opendb(null)).db
6
6
  let bird = db.model('bird', { fields: {
@@ -82,7 +82,7 @@ module.exports = function(monastery, opendb) {
82
82
  db.close()
83
83
  })
84
84
 
85
- test('Model populate type=any', async () => {
85
+ test('model populate type=any', async () => {
86
86
  let db = (await opendb(null)).db
87
87
  db.model('company', { fields: {
88
88
  address: { type: 'any' }
@@ -132,7 +132,7 @@ module.exports = function(monastery, opendb) {
132
132
  db.close()
133
133
  })
134
134
 
135
- test('Model populate/blacklisting via $lookup', async () => {
135
+ test('model populate or blacklisting via $lookup', async () => {
136
136
  // Setup
137
137
  let db = (await opendb(null)).db
138
138
  let user = db.model('user', {
package/test/util.js CHANGED
@@ -2,7 +2,7 @@ let util = require('../lib/util')
2
2
 
3
3
  module.exports = function(monastery, opendb) {
4
4
 
5
- test('Utilities: formdata', async () => {
5
+ test('utilities formdata', async () => {
6
6
  expect(await util.parseFormData({
7
7
  'name': 'Martin',
8
8
  'pets[]': '',
@@ -31,7 +31,7 @@ module.exports = function(monastery, opendb) {
31
31
  .toEqual('Array items in bracket notation need array indexes "users[][\'name\']", e.g. users[0][name]')
32
32
  })
33
33
 
34
- test('Utilities: isId', async () => {
34
+ test('utilities isId', async () => {
35
35
  let db = (await opendb(false)).db
36
36
  expect(db.isId('')).toEqual(false)
37
37
  expect(db.isId(1234)).toEqual(false)
package/test/validate.js CHANGED
@@ -2,7 +2,7 @@ let validate = require('../lib/model-validate')
2
2
 
3
3
  module.exports = function(monastery, opendb) {
4
4
 
5
- test('Validation basic errors', async () => {
5
+ test('validation basic errors', async () => {
6
6
  // Setup
7
7
  let db = (await opendb(false)).db
8
8
  let user = db.model('user', { fields: {
@@ -19,7 +19,7 @@ module.exports = function(monastery, opendb) {
19
19
  detail: 'This field is required.',
20
20
  meta: { rule: 'required', model: 'user', field: 'name' }
21
21
  })
22
- await expect(user.validate({ name : '' }, { validateUndefined: false })).rejects.toContainEqual({
22
+ await expect(user.validate({ name : '' })).rejects.toContainEqual({
23
23
  status: '400',
24
24
  title: 'name',
25
25
  detail: 'This field is required.',
@@ -34,7 +34,16 @@ module.exports = function(monastery, opendb) {
34
34
  await expect(user.validate({}, { update: true })).resolves.toEqual({})
35
35
 
36
36
  // Type error (string)
37
- await expect(user.validate({ name: 1 })).rejects.toContainEqual({
37
+ await expect(user.validate({ name: 1 })).resolves.toEqual({ name: '1' })
38
+ await expect(user.validate({ name: 1.123 })).resolves.toEqual({ name: '1.123' })
39
+ await expect(user.validate({ name: undefined }, { validateUndefined: false })).resolves.toEqual({})
40
+ await expect(user.validate({ name: null })).rejects.toContainEqual({
41
+ status: '400',
42
+ title: 'name',
43
+ detail: 'This field is required.',
44
+ meta: { rule: 'required', model: 'user', field: 'name' }
45
+ })
46
+ await expect(user.validate({ name: true })).rejects.toContainEqual({
38
47
  status: '400',
39
48
  title: 'name',
40
49
  detail: 'Value was not a string.',
@@ -42,6 +51,7 @@ module.exports = function(monastery, opendb) {
42
51
  })
43
52
 
44
53
  // Type error (date)
54
+ await expect(user.validate({ name: 'a', date: null })).resolves.toEqual({ name: 'a', date: null })
45
55
  await expect(user.validate({ name: 'a', date: 'fe' })).rejects.toContainEqual({
46
56
  status: '400',
47
57
  title: 'date',
@@ -49,6 +59,32 @@ module.exports = function(monastery, opendb) {
49
59
  meta: { rule: 'isDate', model: 'user', field: 'date' }
50
60
  })
51
61
 
62
+ // Type error (number)
63
+ let usernum = db.model('usernum', { fields: { amount: { type: 'number', required: true }}})
64
+ let usernum2 = db.model('usernum2', { fields: { amount: { type: 'number' }}})
65
+ await expect(usernum.validate({ amount: 0 })).resolves.toEqual({ amount: 0 })
66
+ await expect(usernum.validate({ amount: '0' })).resolves.toEqual({ amount: 0 })
67
+ await expect(usernum2.validate({ amount: '' })).resolves.toEqual({ amount: null })
68
+ await expect(usernum.validate({ amount: undefined }, { validateUndefined: false })).resolves.toEqual({})
69
+ await expect(usernum.validate({ amount: false })).rejects.toEqual([{
70
+ status: '400',
71
+ title: 'amount',
72
+ detail: 'Value was not a number.',
73
+ meta: { rule: 'isNumber', model: 'usernum', field: 'amount' }
74
+ }])
75
+ await expect(usernum.validate({ amount: null })).rejects.toEqual([{
76
+ status: '400',
77
+ title: 'amount',
78
+ detail: 'This field is required.',
79
+ meta: { rule: 'required', model: 'usernum', field: 'amount' },
80
+ }])
81
+ await expect(usernum.validate({ amount: null }, { validateUndefined: false })).rejects.toEqual([{
82
+ status: '400',
83
+ title: 'amount',
84
+ detail: 'This field is required.',
85
+ meta: { rule: 'required', model: 'usernum', field: 'amount' },
86
+ }])
87
+
52
88
  // Type error (array)
53
89
  await expect(user.validate({ name: 'a', colors: 1 })).rejects.toContainEqual({
54
90
  status: '400',
@@ -82,7 +118,7 @@ module.exports = function(monastery, opendb) {
82
118
  })
83
119
  })
84
120
 
85
- test('Validation subdocument errors', async () => {
121
+ test('validation subdocument errors', async () => {
86
122
  // Setup
87
123
  let db = (await opendb(false)).db
88
124
  let user = db.model('user', { fields: {
@@ -209,7 +245,7 @@ module.exports = function(monastery, opendb) {
209
245
  })
210
246
  })
211
247
 
212
- test('Validation array errors', async () => {
248
+ test('validation array errors', async () => {
213
249
  // Setup
214
250
  let db = (await opendb(false)).db
215
251
  let user = db.model('user', { fields: {
@@ -224,7 +260,7 @@ module.exports = function(monastery, opendb) {
224
260
 
225
261
  // Type error within an array (string)
226
262
  await expect(user.validate({
227
- animals: { cats: [1] }
263
+ animals: { cats: [true] }
228
264
  })).rejects.toContainEqual({
229
265
  status: '400',
230
266
  title: 'animals.cats.0',
@@ -239,7 +275,7 @@ module.exports = function(monastery, opendb) {
239
275
  detail: 'This field is required.',
240
276
  meta: { rule: 'required', model: 'user', field: 'color' }
241
277
  }
242
- await expect(user.validate({ animals: { dogs: [{ name: 'sparky', color: 1 }] }}))
278
+ await expect(user.validate({ animals: { dogs: [{ name: 'sparky', color: false }] }}))
243
279
  .rejects.toContainEqual({
244
280
  ...error,
245
281
  detail: 'Value was not a string.',
@@ -273,7 +309,7 @@ module.exports = function(monastery, opendb) {
273
309
  .rejects.toContainEqual(error)
274
310
  })
275
311
 
276
- test('Validation getMostSpecificKeyMatchingPath', async () => {
312
+ test('validation getMostSpecificKeyMatchingPath', async () => {
277
313
  let fn = validate._getMostSpecificKeyMatchingPath
278
314
  let mock = {
279
315
  'cats.name': true,
@@ -305,7 +341,7 @@ module.exports = function(monastery, opendb) {
305
341
  expect(fn(mock, 'gulls.1')).toEqual('gulls.$')
306
342
  })
307
343
 
308
- test('Validation default messages', async () => {
344
+ test('validation default messages', async () => {
309
345
  // Setup
310
346
  let db = (await opendb(false)).db
311
347
  let user = db.model('user', {
@@ -357,7 +393,7 @@ module.exports = function(monastery, opendb) {
357
393
  })
358
394
  })
359
395
 
360
- test('Validation custom messages', async () => {
396
+ test('validation custom messages', async () => {
361
397
  // Setup
362
398
  // Todo: Setup testing for array array subdocument field messages
363
399
  let db = (await opendb(false)).db
@@ -399,7 +435,7 @@ module.exports = function(monastery, opendb) {
399
435
  })
400
436
  })
401
437
 
402
- test('Validation custom messages for arrays', async () => {
438
+ test('validation custom messages for arrays', async () => {
403
439
  // Setup
404
440
  // Todo: Setup testing for array array subdocument field messages
405
441
  let db = (await opendb(false)).db
@@ -516,7 +552,7 @@ module.exports = function(monastery, opendb) {
516
552
  })
517
553
  })
518
554
 
519
- test('Validation custom rules', async () => {
555
+ test('validation custom rules', async () => {
520
556
  // Setup
521
557
  let db = (await opendb(false)).db
522
558
  let user = db.model('user', {
@@ -602,7 +638,7 @@ module.exports = function(monastery, opendb) {
602
638
  }])
603
639
  })
604
640
 
605
- test('Validated data', async () => {
641
+ test('validated data', async () => {
606
642
  // Setup
607
643
  let db = (await opendb(false)).db
608
644
  let fields = {
@@ -623,16 +659,9 @@ module.exports = function(monastery, opendb) {
623
659
  // Ignores invalid data
624
660
  await expect(user.validate({ badprop: true, schema: {} })).resolves.toEqual({})
625
661
 
626
- // Rejects null for non object/array fields
627
- await expect(user.validate({ name: null })).rejects.toEqual([{
628
- 'detail': 'Value was not a string.',
629
- 'meta': {'detailLong': undefined, 'field': 'name', 'model': 'user', 'rule': 'isString'},
630
- 'status':'400',
631
- 'title': 'name'
632
- }])
633
-
634
662
  // String data
635
663
  await expect(user.validate({ name: 'Martin Luther' })).resolves.toEqual({ name: 'Martin Luther' })
664
+ await expect(user.validate({ name: null })).resolves.toEqual({ name: null })
636
665
 
637
666
  // Array data
638
667
  await expect(user.validate({ names: ['blue'] })).resolves.toEqual({ names: ['blue'] })
@@ -652,12 +681,7 @@ module.exports = function(monastery, opendb) {
652
681
 
653
682
  // Subdocument property data (null)
654
683
  await expect(user.validate({ animals: { dog: null }}))
655
- .rejects.toEqual([{
656
- 'detail': 'Value was not a string.',
657
- 'meta': {'detailLong': undefined, 'field': 'dog', 'model': 'user', 'rule': 'isString'},
658
- 'status': '400',
659
- 'title': 'animals.dog',
660
- }])
684
+ .resolves.toEqual({ animals: { dog: null }})
661
685
 
662
686
  // Subdocument property data (unknown data)
663
687
  await expect(user.validate({ animals: { dog: 'sparky', cat: 'grumpy' } }))
@@ -672,7 +696,7 @@ module.exports = function(monastery, opendb) {
672
696
  .resolves.toEqual({ animals: { dogs: [{}] }})
673
697
  })
674
698
 
675
- test('Schema options', async () => {
699
+ test('schema options', async () => {
676
700
  // Setup
677
701
  let db = (await opendb(false)).db
678
702
  let user = db.model('user', { fields: {
@@ -713,7 +737,7 @@ module.exports = function(monastery, opendb) {
713
737
  })
714
738
  })
715
739
 
716
- test('Schema default rules', async () => {
740
+ test('schema default rules', async () => {
717
741
  // Setup
718
742
  let db = (await opendb(false)).db
719
743
  let user = db.model('user', { fields: {
@@ -766,15 +790,10 @@ module.exports = function(monastery, opendb) {
766
790
  })
767
791
 
768
792
  // Number valid
769
- await expect(user2.validate({ amount: 0 })).resolves.toEqual({ amount: 0 }) // required
770
- await expect(user.validate({ amount: '0' })).resolves.toEqual({ amount: 0 }) // required
771
- await expect(user.validate({ amount: undefined })).resolves.toEqual({}) // not required
772
- await expect(user.validate({ amount: null })).rejects.toEqual([{ // type error
773
- 'detail': 'Value was not a number.',
774
- 'meta': { 'field': 'amount', 'model': 'user', 'rule': 'isNumber'},
775
- 'status': '400',
776
- 'title': 'amount'
777
- }])
793
+ await expect(user2.validate({ amount: 0 })).resolves.toEqual({ amount: 0 })
794
+ await expect(user2.validate({ amount: '0' })).resolves.toEqual({ amount: 0 })
795
+ await expect(user.validate({ amount: undefined })).resolves.toEqual({})
796
+ await expect(user.validate({ amount: null })).resolves.toEqual({ amount: null })
778
797
 
779
798
  // Number required
780
799
  let mock1 = {
@@ -799,7 +818,7 @@ module.exports = function(monastery, opendb) {
799
818
  await expect(user.validate({ amount: 'bad' })).rejects.toContainEqual(mock2)
800
819
  })
801
820
 
802
- test('Schema default objects', async () => {
821
+ test('schema default objects', async () => {
803
822
  let db = (await opendb(null, {
804
823
  timestamps: false,
805
824
  defaultObjects: true,
@@ -825,7 +844,7 @@ module.exports = function(monastery, opendb) {
825
844
  db.close()
826
845
  })
827
846
 
828
- test('Schema nullObjects', async () => {
847
+ test('schema nullObjects', async () => {
829
848
  let db = (await opendb(null, {
830
849
  timestamps: false,
831
850
  nullObjects: true,
@@ -851,7 +870,7 @@ module.exports = function(monastery, opendb) {
851
870
  db.close()
852
871
  })
853
872
 
854
- test('Validation options', async () => {
873
+ test('validation options', async () => {
855
874
  let db = (await opendb(false)).db
856
875
  let user = db.model('user', { fields: {
857
876
  name: { type: 'string', required: true }
@@ -936,7 +955,7 @@ module.exports = function(monastery, opendb) {
936
955
  })
937
956
  })
938
957
 
939
- test('Validation hooks', async () => {
958
+ test('validation hooks', async () => {
940
959
  let db = (await opendb(null)).db
941
960
  let user = db.model('user', {
942
961
  fields: {
package/test/virtuals.js CHANGED
@@ -1,6 +1,6 @@
1
1
  module.exports = function(monastery, opendb) {
2
2
 
3
- test('Virtuals', async () => {
3
+ test('virtuals', async () => {
4
4
  // Setup
5
5
  let db = (await opendb(null)).db
6
6
  // Test model setup
@@ -147,7 +147,7 @@ module.exports = function(monastery, opendb) {
147
147
  db.close()
148
148
  })
149
149
 
150
- test('Insert/update virtuals (validate)', async () => {
150
+ test('insert update virtuals (validate)', async () => {
151
151
  // Setup
152
152
  let db = (await opendb(null)).db
153
153
  let user = db.model('user', {