monastery 1.41.1 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
+ ## [1.42.0](https://github.com/boycce/monastery/compare/1.41.2...1.42.0) (2023-10-09)
6
+
7
+ ### [1.41.2](https://github.com/boycce/monastery/compare/1.41.1...1.41.2) (2023-10-04)
8
+
5
9
  ### [1.41.1](https://github.com/boycce/monastery/compare/1.41.0...1.41.1) (2023-04-17)
6
10
 
7
11
  ## [1.41.0](https://github.com/boycce/monastery/compare/1.40.5...1.41.0) (2023-04-16)
@@ -30,15 +30,18 @@ A monk manager instance with additional Monastery methods, i.e. `model` `models`
30
30
  ### Example
31
31
 
32
32
  ```js
33
- const db = require('monastery')('localhost/mydb', options)
33
+ import monastery from 'monastery'
34
+ const db = monastery('localhost/mydb', options)
34
35
  ```
35
36
 
36
37
  ```js
37
- const db = require('monastery')('localhost/mydb,192.168.1.1') // replica set
38
+ import monastery from 'monastery'
39
+ const db = monastery('localhost/mydb,192.168.1.1') // replica set
38
40
  ```
39
41
 
40
42
  ```js
41
- require('monastery')('localhost/mydb,192.168.1.1').then((db) => {
43
+ import monastery from 'monastery'
44
+ monastery('localhost/mydb,192.168.1.1').then((db) => {
42
45
  // db is the connected instance of the Manager
43
46
  }).catch((err) => {
44
47
  // error connecting to the database
@@ -9,7 +9,7 @@ Setup model definitions from a folder location
9
9
 
10
10
  ### Arguments
11
11
 
12
- `path` *(string)*: path to model definitions, the filenames are used as the corresponding model name.
12
+ `path` *(string)*: path to model definitions, the filenames are used as the corresponding model name. Make sure the model definition is exported as the default
13
13
 
14
14
  ### Returns
15
15
 
@@ -23,7 +23,7 @@ db.model.{model-name}
23
23
 
24
24
  ```js
25
25
  // ./models/user.js
26
- export default {
26
+ export default { // Make sure the model definition is exported as the default
27
27
  fields: {
28
28
  name: { type: 'string', required: true },
29
29
  email: { type: 'email', required: true, index: 'unique' }
package/docs/readme.md CHANGED
@@ -24,9 +24,11 @@ $ npm install --save monastery
24
24
  ## Usage
25
25
 
26
26
  ```javascript
27
+ import monastery from 'monastery'
28
+
27
29
  // Initialise a monastery manager
28
- const db = require('monastery')('localhost/mydb')
29
- // const db = require('monastery')('user:pass@localhost:port/mydb')
30
+ const db = monastery('localhost/mydb')
31
+ // const db = monastery('user:pass@localhost:port/mydb')
30
32
 
31
33
  // Define a model
32
34
  db.model('user', {
@@ -101,6 +103,7 @@ Coming soon...
101
103
  - Split away from Monk (unless updated)
102
104
  - Add a warning if an invalid model is referenced in jthe schema
103
105
  - Remove leading forward slashes from custom image paths (AWS adds this as a seperate folder)
106
+ - double check await db.model.remove({ query: idfromparam }) doesnt cause issues for null, undefined or '', but continue to allow {}
104
107
 
105
108
  ## Versions
106
109
 
package/lib/index.js CHANGED
@@ -93,9 +93,17 @@ let models = async function(pathname, waitForIndexes) {
93
93
  }
94
94
  let filenames = fs.readdirSync(pathname)
95
95
  for (let filename of filenames) {
96
- let filepath = path.join(pathname, filename)
97
- let definition = (await import(filepath)).default
96
+ // Ignore folders
97
+ if (!filename.match(/\.[cm]?js$/)) continue
98
98
  let name = filename.replace('.js', '')
99
+ let filepath = path.join(pathname, filename)
100
+ // We can't use require() here since we need to be able to import both CJS and ES6 modules
101
+ let definition = (await import(filepath))?.default
102
+ // When a commonJS project uses babel (e.g. `nodemon -r @babel/register`, similar to `-r esm`), import()
103
+ // will return ES6 model definitions in another nested `default` object
104
+ if (definition?.default) definition = definition.default
105
+ if (!definition) throw new Error(`The model definition for '${name}' must export a default object`)
106
+ // Wait for indexes to be created?
99
107
  if (waitForIndexes) out[name] = await this.model(name, { ...definition, waitForIndexes })
100
108
  else out[name] = this.model(name, definition)
101
109
  }
package/lib/model-crud.js CHANGED
@@ -25,9 +25,13 @@ module.exports = {
25
25
  try {
26
26
  opts = await this._queryObject(opts, 'insert')
27
27
 
28
+ // console.log(11, opts.data )
29
+
28
30
  // Validate
29
31
  let data = await this.validate(opts.data || {}, opts) // was { ...opts }
30
32
 
33
+ // console.log(22, data)
34
+
31
35
  // Insert
32
36
  await util.runSeries(this.beforeInsert.map(f => f.bind(opts, data)))
33
37
  let response = await this._insert(data, util.omit(opts, this._queryOptions))
@@ -108,6 +108,8 @@ module.exports = {
108
108
  let data2 = util.isArray(fields)? [] : {}
109
109
  let timestamps = util.isDefined(opts.timestamps)? opts.timestamps : this.manager.timestamps
110
110
 
111
+ // console.log(8888, fields)
112
+
111
113
  util.forEach(util.forceArray(data), function(data, i) {
112
114
  util.forEach(fields, function(field, fieldName) {
113
115
  let verrors = []
@@ -131,8 +133,11 @@ module.exports = {
131
133
  }
132
134
  }
133
135
 
136
+ // console.log(333,path3)
137
+
134
138
  // Ignore blacklisted
135
139
  if (this._pathBlacklisted(path3, opts.projectionValidate) && !schema.defaultOverride) return
140
+ // console.log(444,path3)
136
141
  // Ignore insert only
137
142
  if (opts.update && schema.insertOnly) return
138
143
  // Ignore virtual fields
@@ -141,6 +146,7 @@ module.exports = {
141
146
  if (isTypeRule && util.isFunction(isTypeRule.tryParse)) {
142
147
  value = isTypeRule.tryParse.call(dataRoot, value, fieldName, this)
143
148
  }
149
+ // console.log(555,path3)
144
150
 
145
151
  // Schema field (ignore object/array schemas)
146
152
  if (util.isSchema(field) && fieldName !== 'schema') {
package/lib/model.js CHANGED
@@ -14,16 +14,18 @@ let Model = module.exports = function(name, opts, manager) {
14
14
  */
15
15
  if (!(this instanceof Model)) {
16
16
  return new Model(name, opts, this)
17
-
18
17
  } else if (!name) {
19
18
  throw 'No model name defined'
20
-
21
19
  } else if (name.match(/^_/)) {
22
20
  throw 'Model names cannot start with an underscore'
21
+ } else if (!opts) {
22
+ throw `No model definition passed for "${name}"`
23
+ } else if (!opts.fields) {
24
+ throw `We couldn't find ${name}.fields in the model definition, the model maybe setup `
25
+ + `or exported incorrectly:\n${JSON.stringify(opts, null, 2)}`
23
26
  }
24
27
 
25
28
  // Add schema options
26
- opts = opts || {}
27
29
  Object.assign(this, {
28
30
  ...(opts.methods || {}),
29
31
  afterFind: opts.afterFind || [],
@@ -37,14 +39,14 @@ let Model = module.exports = function(name, opts, manager) {
37
39
  error: manager.error,
38
40
  info: manager.info,
39
41
  warn: manager.warn,
40
- insertBL: opts.insertBL || [],
42
+ insertBL: opts.insertBL || ['_id'],
41
43
  fields: { ...(util.deepCopy(opts.fields) || {}) },
42
44
  findBL: opts.findBL || ['password'],
43
45
  manager: manager,
44
46
  messages: opts.messages || {},
45
47
  name: name,
46
48
  rules: { ...(opts.rules || {}) },
47
- updateBL: opts.updateBL || [],
49
+ updateBL: opts.updateBL || ['_id'],
48
50
  })
49
51
 
50
52
  // Run before model hooks
@@ -69,7 +71,7 @@ let Model = module.exports = function(name, opts, manager) {
69
71
  }, this)
70
72
 
71
73
  // Extend default fields with passed in fields and check for invalid fields
72
- this._setupFields(this.fields = Object.assign({}, this._timestampFields, this.fields))
74
+ this._setupFields(this.fields = Object.assign({}, this._defaultFields, this.fields))
73
75
  this.fieldsFlattened = this._getFieldsFlattened(this.fields, '') // test output?
74
76
 
75
77
  // Extend model with monk collection queries
@@ -319,7 +321,11 @@ Model.prototype._setupIndexes = function(fields, opts={}) {
319
321
  }
320
322
  }
321
323
 
322
- Model.prototype._timestampFields = {
324
+ Model.prototype._defaultFields = {
325
+ _id: {
326
+ insertOnly: true,
327
+ type: 'id'
328
+ },
323
329
  createdAt: {
324
330
  default: function(fieldName, model) {
325
331
  return model.manager.useMilliseconds? Date.now() : Math.floor(Date.now() / 1000)
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.41.1",
5
+ "version": "1.42.0",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
@@ -339,7 +339,7 @@ module.exports = function(monastery, opendb) {
339
339
  db.close()
340
340
  })
341
341
 
342
- test('insert update blacklisting (validate)', async () => {
342
+ test('insert blacklisting (validate)', async () => {
343
343
  // Setup
344
344
  let db = (await opendb(null)).db
345
345
  let user = db.model('user', {
@@ -365,15 +365,21 @@ module.exports = function(monastery, opendb) {
365
365
  }
366
366
  },
367
367
  insertBL: [
368
+ '_id', // default
368
369
  'dog',
369
370
  'animals.cat',
370
371
  'pets.age',
371
372
  'hiddenPets',
372
373
  'hiddenList',
373
374
  'deep.deep2.deep3'
374
- ]
375
+ ],
376
+ updateBL: [
377
+ '_id' // default
378
+ ],
375
379
  })
380
+ let doc1Id = db.id()
376
381
  let doc1 = {
382
+ _id: doc1Id,
377
383
  list: [44, 54],
378
384
  dog: 'Bruce',
379
385
  pet: 'Freddy',
@@ -409,9 +415,10 @@ module.exports = function(monastery, opendb) {
409
415
  }
410
416
  })
411
417
 
412
- // Custom blacklist (remove and add to the current schema blacklist)
418
+ // Custom insert blacklist (remove and add to the current schema blacklist)
413
419
  let user2 = await user.validate(doc1, {
414
420
  blacklist: [
421
+ '-_id',
415
422
  '-dog',
416
423
  '-animals.dog', // wrong property
417
424
  'pets.name',
@@ -421,6 +428,7 @@ module.exports = function(monastery, opendb) {
421
428
  })
422
429
  let customBlacklist
423
430
  expect(user2).toEqual((customBlacklist = {
431
+ _id: doc1Id,
424
432
  list: [44, 54],
425
433
  dog: 'Bruce',
426
434
  pet: 'Freddy',
@@ -440,7 +448,7 @@ module.exports = function(monastery, opendb) {
440
448
 
441
449
  // Blacklist string
442
450
  let user3 = await user.validate(doc1, {
443
- blacklist: '-dog -animals.dog pets.name -hiddenList -deep'
451
+ blacklist: '-_id -dog -animals.dog pets.name -hiddenList -deep'
444
452
  })
445
453
  expect(user3).toEqual(customBlacklist)
446
454
 
@@ -467,6 +475,14 @@ module.exports = function(monastery, opendb) {
467
475
  }
468
476
  }
469
477
  })
478
+
479
+ // double check that _id.insertOnly is working
480
+ let user6 = await user.validate(doc1, { update: true, blacklist: false })
481
+ expect(user6).toEqual({
482
+ ...doc1,
483
+ _id: undefined,
484
+ })
485
+
470
486
  db.close()
471
487
  })
472
488
 
package/test/model.js CHANGED
@@ -13,7 +13,12 @@ module.exports = function(monastery, opendb) {
13
13
  }})
14
14
 
15
15
  // no fields defined
16
- expect(db.model('user2').fields).toEqual({
16
+ expect(db.model('user2', { fields: {} }).fields).toEqual({
17
+ _id: {
18
+ insertOnly: true,
19
+ isId: true,
20
+ type: 'id',
21
+ },
17
22
  createdAt: {
18
23
  default: expect.any(Function),
19
24
  insertOnly: true,
@@ -73,7 +78,12 @@ module.exports = function(monastery, opendb) {
73
78
  let db = (await opendb(false, { defaultObjects: true })).db
74
79
 
75
80
  // Default fields
76
- expect(db.model('user2').fields).toEqual({
81
+ expect(db.model('user2', { fields: {} }).fields).toEqual({
82
+ _id: {
83
+ insertOnly: true,
84
+ isId: true,
85
+ type: 'id',
86
+ },
77
87
  createdAt: {
78
88
  default: expect.any(Function),
79
89
  insertOnly: true,
@@ -195,7 +205,7 @@ module.exports = function(monastery, opendb) {
195
205
  }
196
206
 
197
207
  // Unique & text index (after model initialisation, in serial)
198
- let userIndexRawModel = db.model('userIndexRaw', {})
208
+ let userIndexRawModel = db.model('userIndexRaw', {fields: {}})
199
209
  await userIndexRawModel._setupIndexes({
200
210
  email: { type: 'string', index: 'unique' },
201
211
  })
package/test/monk.js CHANGED
@@ -4,8 +4,8 @@ module.exports = function(monastery, opendb) {
4
4
  // Setup
5
5
  let db = (await opendb(false)).db
6
6
  let monkdb = require('monk')(':badconnection', () => {})
7
- db.model('user', {})
8
- let modelNamedConnected = db.model('connected', {})
7
+ db.model('user', { fields: {} })
8
+ let modelNamedConnected = db.model('connected', { fields: {} })
9
9
 
10
10
  // Any of our monastery properties already exist on the manager?
11
11
  for (let name of ['connected', 'debug', 'log', 'model', 'models']) {
package/test/validate.js CHANGED
@@ -765,6 +765,11 @@ module.exports = function(monastery, opendb) {
765
765
  // Subdocument -> array -> subdocument data (empty)
766
766
  await expect(user.validate({ animals: { dogs: [{}] }}))
767
767
  .resolves.toEqual({ animals: { dogs: [{}] }})
768
+
769
+ // _id is blacklisted by default
770
+ let id = db.id()
771
+ await expect(user.validate({ _id: id })).resolves.toEqual({})
772
+ await expect(user.validate({ _id: id }, { update: true })).resolves.toEqual({})
768
773
  })
769
774
 
770
775
  test('schema options', async () => {