monastery 3.4.2 → 3.4.3

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,8 @@
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.4.3](https://github.com/boycce/monastery/compare/3.4.2...3.4.3) (2024-08-27)
6
+
5
7
  ### [3.4.2](https://github.com/boycce/monastery/compare/3.4.1...3.4.2) (2024-08-24)
6
8
 
7
9
  ### [3.4.1](https://github.com/boycce/monastery/compare/3.4.0...3.4.1) (2024-08-09)
@@ -11,7 +11,9 @@ Sets up a model, retrieves a collection, and sets up any required indexes
11
11
 
12
12
  `name` *(string)*: name of the mongo collection
13
13
 
14
- [`definition`] *(object)*: [definition](../definition)
14
+ `definition` *(object)*: [definition](../definition)
15
+
16
+ `waitForIndexes` *(boolean)*: wait for indexes to be setup (returns a promise instead of a model)
15
17
 
16
18
  ### Returns
17
19
 
@@ -13,7 +13,7 @@ Setup model definitions from a folder location
13
13
 
14
14
  [`options`] *(object)*:
15
15
  - [`commonJs=false`] *(boolean)*: for old commonjs projects, you will need to set this to `true` which uses `require` instead of `import` (removed in `3.0.0`)
16
- - [`waitForIndexes=false`] *(boolean)*: returns a proimse that waits for the Mongo collection indexes to be setup
16
+ - [`waitForIndexes=false`] *(boolean)*: wait for collection indexes to be setup
17
17
 
18
18
  ### Returns
19
19
 
@@ -39,5 +39,5 @@ export default { // Make sure the model definition is exported as the default
39
39
  ```
40
40
 
41
41
  ```js
42
- await db.models(__dirname + "models")
42
+ await db.models(__dirname + 'models', { waitForIndexes: true })
43
43
  ```
package/lib/index.js CHANGED
@@ -211,7 +211,7 @@ Manager.prototype.models = async function(pathname, opts) {
211
211
  if (definition && definition.default) definition = definition.default
212
212
  if (!definition) throw new Error(`The model definition for '${name}' must export a default object`)
213
213
  // Wait for indexes to be created?
214
- if (waitForIndexes) out[name] = await this.model(name, { ...definition, waitForIndexes })
214
+ if (waitForIndexes) out[name] = await this.model(name, definition, waitForIndexes)
215
215
  else out[name] = this.model(name, definition)
216
216
  }
217
217
  return out
package/lib/model.js CHANGED
@@ -1,58 +1,59 @@
1
1
  const rules = require('./rules.js')
2
2
  const util = require('./util.js')
3
3
 
4
- function Model(name, opts, manager) {
4
+ function Model(name, definition, waitForIndexes, manager) {
5
5
  /**
6
6
  * Setup a model
7
7
  * @param {string} name
8
- * @param {object} opts - see mongodb collection documentation
9
- * @param {boolean} opts.waitForIndexes
10
- * @return Promise(model) | this
11
- * @this model
8
+ * @param {object} definition - model definition
9
+ * @param {boolean} waitForIndexes - wait for indexes to be created before returning (returns a promise)
10
+ *
11
+ * @return model or Promise(model)
12
+ * @this manager
12
13
  */
13
14
  if (!(this instanceof Model)) {
14
- return new Model(name, opts, this)
15
+ return new Model(name, definition, waitForIndexes, this)
15
16
  } else if (!name) {
16
17
  throw 'No model name defined'
17
18
  } else if (name.match(/^_/)) {
18
19
  throw 'Model names cannot start with an underscore'
19
- } else if (!opts) {
20
+ } else if (!definition) {
20
21
  throw `No model definition passed for "${name}"`
21
- } else if (!opts.fields) {
22
+ } else if (!definition.fields) {
22
23
  throw `We couldn't find ${name}.fields in the model definition, the model maybe setup `
23
- + `or exported incorrectly:\n${JSON.stringify(opts, null, 2)}`
24
- } else if (!util.isSubdocument(opts.fields) && opts.fields.type == 'any') {
24
+ + `or exported incorrectly:\n${JSON.stringify(definition, null, 2)}`
25
+ } else if (!util.isSubdocument(definition.fields) && definition.fields.type == 'any') {
25
26
  throw `Instead of using { type: 'any' } for ${name}.fields, please use the new 'strict' definition rule` +
26
27
  ', e.g. { schema: { strict: false }}'
27
- } else if (!util.isSubdocument(opts.fields) && !util.isEmpty(opts.fields)) {
28
+ } else if (!util.isSubdocument(definition.fields) && !util.isEmpty(definition.fields)) {
28
29
  throw `The ${name}.fields object should be a valid document, e.g. { name: { type: 'string' }}`
29
30
  }
30
31
 
31
32
  // Add schema options
32
33
  Object.assign(this, {
33
- ...(opts.methods || {}),
34
- afterFind: opts.afterFind || [],
35
- afterInsert: (opts.afterInsert || []).concat(opts.afterInsertUpdate || []),
36
- afterUpdate: (opts.afterUpdate || []).concat(opts.afterInsertUpdate || []),
37
- afterRemove: opts.afterRemove || [],
38
- beforeInsert: (opts.beforeInsert || []).concat(opts.beforeInsertUpdate || []),
39
- beforeUpdate: (opts.beforeUpdate || []).concat(opts.beforeInsertUpdate || []),
40
- beforeRemove: opts.beforeRemove || [],
41
- beforeValidate: opts.beforeValidate || [],
34
+ ...(definition.methods || {}),
35
+ afterFind: definition.afterFind || [],
36
+ afterInsert: (definition.afterInsert || []).concat(definition.afterInsertUpdate || []),
37
+ afterUpdate: (definition.afterUpdate || []).concat(definition.afterInsertUpdate || []),
38
+ afterRemove: definition.afterRemove || [],
39
+ beforeInsert: (definition.beforeInsert || []).concat(definition.beforeInsertUpdate || []),
40
+ beforeUpdate: (definition.beforeUpdate || []).concat(definition.beforeInsertUpdate || []),
41
+ beforeRemove: definition.beforeRemove || [],
42
+ beforeValidate: definition.beforeValidate || [],
42
43
  error: manager.error,
43
44
  info: manager.info,
44
45
  warn: manager.warn,
45
- insertBL: opts.insertBL
46
- ? !opts.insertBL.includes('_id') && !opts.insertBL.includes('-_id') ? ['_id'].concat(opts.insertBL) : opts.insertBL
47
- : ['_id'],
48
- fields: { ...(util.deepCopy(opts.fields) || {}) },
49
- findBL: opts.findBL || ['password'], // todo: password should be removed
46
+ insertBL: !definition.insertBL
47
+ ? ['_id'] : !definition.insertBL.includes('_id') && !definition.insertBL.includes('-_id')
48
+ ? ['_id'].concat(definition.insertBL) : definition.insertBL,
49
+ fields: { ...(util.deepCopy(definition.fields) || {}) },
50
+ findBL: definition.findBL || ['password'], // todo: password should be removed
50
51
  manager: manager,
51
- messages: opts.messages || {},
52
- messagesLen: Object.keys(opts.messages || {}).length > 0,
52
+ messages: definition.messages || {},
53
+ messagesLen: Object.keys(definition.messages || {}).length > 0,
53
54
  name: name,
54
- rules: { ...(opts.rules || {}) },
55
- updateBL: opts.updateBL || [],
55
+ rules: { ...(definition.rules || {}) },
56
+ updateBL: definition.updateBL || [],
56
57
  })
57
58
 
58
59
  // Sort messages by specifity first, then we can just return the first match
@@ -140,7 +141,7 @@ function Model(name, opts, manager) {
140
141
  if (err.type == 'info') this.info(err.detail)
141
142
  else this.error(err)
142
143
  }
143
- if (opts.waitForIndexes) return this._setupIndexes().catch(errHandler).then(() => this)
144
+ if (waitForIndexes) return this._setupIndexes().catch(errHandler).then(() => this)
144
145
  else this._setupIndexes().catch(errHandler) // returns this
145
146
  }
146
147
 
@@ -446,4 +447,4 @@ module.exports = Model
446
447
 
447
448
  // Extend Model prototype
448
449
  require('./model-crud.js')
449
- require('./model-validate.js')
450
+ require('./model-validate.js')
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.4.2",
5
+ "version": "3.4.3",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
package/test/crud.js CHANGED
@@ -353,10 +353,7 @@ test('find default field blacklisted', async () => {
353
353
 
354
354
  test('find default field population with option noDefaults', async () => {
355
355
  async function setup(noDefaults) {
356
- /**
357
- * Setup
358
- * @returns {Object} {dog, user, dog1Doc, dog2Doc, user1Doc}
359
- */
356
+ // @returns {Object} {dog, user, dog1Doc, dog2Doc, user1Doc}
360
357
  // similar to "find default field population"
361
358
  const db = monastery('127.0.0.1/monastery', { noDefaults: noDefaults, timestamps: false })
362
359
  const userDefinition = {
@@ -508,6 +505,9 @@ test('find default field population with option noDefaults', async () => {
508
505
  },
509
506
  dogs: [{ _id: s2.dog1Doc._id, user: s2.user1Doc._id }], // should not have a default name
510
507
  })
508
+
509
+ s1.db.close()
510
+ s2.db.close()
511
511
  })
512
512
 
513
513
  test('update general', async () => {
@@ -1074,7 +1074,6 @@ test('hooks > basic', async () => {
1074
1074
  await expect(user2.update({ query: userDoc2._id, data: { first: 'MM' } })).resolves.toEqual({ first: 'MM' })
1075
1075
  await expect(user2.update({ query: userDoc2._id, data: { first: 'M', bad: true } })).rejects.toThrow('error2')
1076
1076
  })
1077
-
1078
1077
  test('hooks > chained values', async () => {
1079
1078
  let bookCount = 0
1080
1079
  const afterInsertAsync = [
@@ -1514,4 +1513,6 @@ test('update set and unset with option skipValidation', async () => {
1514
1513
  const u8 = { query: userId, $unset: { 'profile.name': '' }, skipValidation: true }
1515
1514
  await expect(user.update(u8)).resolves.toEqual({})
1516
1515
  await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: {} })
1516
+
1517
+ db2.close()
1517
1518
  })
package/test/model.js CHANGED
@@ -449,12 +449,11 @@ test('model indexes basic', async () => {
449
449
 
450
450
  // Unique & text index
451
451
  let userIndexModel = await db.model('userIndex', {
452
- waitForIndexes: true,
453
452
  fields: {
454
453
  email: { type: 'string', index: 'unique' },
455
454
  name: { type: 'string', index: 'text' },
456
455
  },
457
- })
456
+ }, { waitForIndexes: true })
458
457
 
459
458
  let userIndexModelIndexes = await db.db.collection('userIndex').indexes()
460
459
  expect(userIndexModelIndexes[0]).toEqual({
@@ -504,7 +503,6 @@ test('model indexes unique', async () => {
504
503
 
505
504
  // Partial unique indexes (allows mulitple null values)
506
505
  await db.model('userUniqueIndex', {
507
- waitForIndexes: true,
508
506
  fields: {
509
507
  email: {
510
508
  type: 'string',
@@ -516,7 +514,7 @@ test('model indexes unique', async () => {
516
514
  },
517
515
  },
518
516
  },
519
- })
517
+ }, { waitForIndexes: true })
520
518
 
521
519
  let indexes2 = await db.db.collection('userUniqueIndex').indexes()
522
520
  expect(indexes2[0]).toEqual({
@@ -648,7 +646,6 @@ test('model indexes 2dsphere', async () => {
648
646
  // Setup. The tested model needs to be unique as race condition issue arises when the same model
649
647
  // with text indexes are setup at the same time
650
648
  await db.model('user99', {
651
- waitForIndexes: true,
652
649
  fields: {
653
650
  location: {
654
651
  index: '2dsphere',
@@ -661,7 +658,7 @@ test('model indexes 2dsphere', async () => {
661
658
  coordinates: [{ type: 'number' }], // lat, lng
662
659
  },
663
660
  },
664
- })
661
+ }, { waitForIndexes: true })
665
662
 
666
663
  // Schema check
667
664
  expect(db.user99.fields.location).toEqual({
@@ -778,27 +778,26 @@ test('images option getSignedUrls', async () => {
778
778
  })
779
779
 
780
780
  // Find signed URL via query option
781
- // await expect(db3.user.findOne({ query: userInserted._id, getSignedUrls: true })).resolves.toEqual({
782
- // _id: expect.any(Object),
783
- // photos: [imageWithSignedUrl, imageWithSignedUrl],
784
- // photos2: [imageWithSignedUrl, imageWithSignedUrl],
785
- // })
786
-
787
- // // Find signed URL via schema option
788
- // await expect(db3.user.findOne({ query: userInserted._id })).resolves.toEqual({
789
- // _id: expect.any(Object),
790
- // photos: [image, image],
791
- // photos2: [imageWithSignedUrl, imageWithSignedUrl],
792
- // })
781
+ await expect(db3.user.findOne({ query: userInserted._id, getSignedUrls: true })).resolves.toEqual({
782
+ _id: expect.any(Object),
783
+ photos: [imageWithSignedUrl, imageWithSignedUrl],
784
+ photos2: [imageWithSignedUrl, imageWithSignedUrl],
785
+ })
786
+
787
+ // Find signed URL via schema option
788
+ await expect(db3.user.findOne({ query: userInserted._id })).resolves.toEqual({
789
+ _id: expect.any(Object),
790
+ photos: [image, image],
791
+ photos2: [imageWithSignedUrl, imageWithSignedUrl],
792
+ })
793
793
 
794
794
  // Works with _processAfterFind
795
795
  let rawUser = await db3.user._findOne({ _id: userInserted._id })
796
- db3.user._processAfterFind(rawUser)
797
- // await expect(db3.user._processAfterFind(rawUser)).resolves.toEqual({
798
- // _id: expect.any(Object),
799
- // photos: [image, image],
800
- // photos2: [imageWithSignedUrl, imageWithSignedUrl],
801
- // })
796
+ await expect(db3.user._processAfterFind(rawUser)).resolves.toEqual({
797
+ _id: expect.any(Object),
798
+ photos: [image, image],
799
+ photos2: [imageWithSignedUrl, imageWithSignedUrl],
800
+ })
802
801
  db3.close()
803
802
  })
804
803