monastery 3.4.2 → 3.5.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/lib/manager.js ADDED
@@ -0,0 +1,289 @@
1
+ const fs = require('fs')
2
+ const debug = require('debug')
3
+ const path = require('path')
4
+ const EventEmitter = require('events').EventEmitter
5
+ const inherits = require('util').inherits
6
+ const { MongoClient } = require('mongodb')
7
+ const Collection = require('./collection.js')
8
+ const imagePluginFile = require('../plugins/images/index.js')
9
+ const Model = require('./model.js')
10
+ const util = require('./util.js')
11
+
12
+ function Manager(uri, opts) {
13
+ /**
14
+ * Constructs a new manager which contains a new MongoDB client
15
+ *
16
+ * @param {String|Array|Object} uri - MongoDB connection URI string / replica set, or reuse a MongoClient instance
17
+ * @param {Object} opts -
18
+ * {String} <opts.databaseName> - the name of the database
19
+ * {Boolean} <opts.promise(manager)> - return a promise
20
+ *
21
+ * @return {Connection|Promise}
22
+ * @link https://www.mongodb.com/docs/drivers/node/v5.9/quick-reference/
23
+ * @link https://mongodb.github.io/node-mongodb-native/ (all versions)
24
+ */
25
+ if (!opts) opts = {}
26
+ if (!(this instanceof Manager)) return new Manager(uri, opts)
27
+
28
+ // opts: timestamps
29
+ if (typeof opts.defaultFields != 'undefined') throw Error('opts.defaultFields has been depreciated, use opts.timestamps')
30
+ if (typeof opts.timestamps == 'undefined') opts.timestamps = true
31
+
32
+ // opts: logLevel
33
+ if (typeof opts.logLevel == 'undefined') opts.logLevel = 2
34
+
35
+ // opts: separate out monastery options
36
+ const mongoOpts = Object.keys(opts||{}).reduce((acc, key) => {
37
+ if (
38
+ ![
39
+ 'databaseName', 'defaultObjects', 'logLevel', 'imagePlugin', 'limit', 'noDefaults', 'nullObjects',
40
+ 'promise', 'timestamps', 'useMilliseconds',
41
+ ].includes(key)) {
42
+ acc[key] = opts[key]
43
+ }
44
+ return acc
45
+ }, {})
46
+
47
+ // Add properties
48
+ this.uri = uri
49
+ this.error = debug('monastery:error' + (opts.logLevel > 0 ? '*' : ''))
50
+ this.warn = debug('monastery:warn' + (opts.logLevel > 1 ? '*' : ''))
51
+ this.info = debug('monastery:info' + (opts.logLevel > 2 ? '*' : ''))
52
+ this.opts = opts
53
+ this.beforeModel = []
54
+ this.collections = {}
55
+ this._openQueue = []
56
+
57
+ // If there is no DEBUG= environment variable, we will need to force the debugs on (due to bug on debug@4.3.4)
58
+ if (!debug.namespaces) {
59
+ if (opts.logLevel > 0) this.error.enabled = true
60
+ if (opts.logLevel > 1) this.warn.enabled = true
61
+ if (opts.logLevel > 2) this.info.enabled = true
62
+ }
63
+
64
+ // Create a new MongoDB Client
65
+ if (typeof this.uri == 'string' || Array.isArray(this.uri)) {
66
+ this.uri = this.connectionString(this.uri, opts.databaseName)
67
+ this.client = new MongoClient(this.uri, mongoOpts)
68
+ } else {
69
+ this.client = this.uri
70
+ }
71
+
72
+ // Listen to MongoDB events
73
+ for (let eventName of ['close', 'error', 'timeout']) {
74
+ this.client.on(eventName, (e) => this.emit(eventName, e))
75
+ }
76
+
77
+ // Listen to custom open event
78
+ this.on('open', () => {
79
+ // wait for all the on('open') events to get called first
80
+ setTimeout(() => {
81
+ for (let item of this._openQueue) {
82
+ item()
83
+ }
84
+ })
85
+ })
86
+
87
+ // Initiate any plugins
88
+ if (opts.imagePlugin) {
89
+ imagePluginFile.setup(this, util.isObject(opts.imagePlugin) ? opts.imagePlugin : {})
90
+ }
91
+
92
+ // Connect to the database
93
+ if (opts.promise) return this.open()
94
+ else this.open()
95
+ }
96
+
97
+ Manager.prototype.arrayWithSchema = function(array, schema) {
98
+ array.schema = schema
99
+ return array
100
+ }
101
+
102
+ Manager.prototype.close = async function() {
103
+ /**
104
+ * Close the database connection, gracefully
105
+ */
106
+ const _close = async () => {
107
+ this.emit(this._state = 'closing')
108
+ await this.client.close()
109
+ this.emit(this._state = 'close')
110
+ }
111
+ if (this._state == 'open') {
112
+ return await _close()
113
+
114
+ } else if (this._state == 'opening') {
115
+ return new Promise((resolve) => {
116
+ this._openQueue.push(() => _close().then(resolve))
117
+ })
118
+
119
+ } else if (this._state == 'close' || this._state == 'closing') {
120
+ return
121
+ }
122
+ }
123
+
124
+ Manager.prototype.command = function(...args) {
125
+ /**
126
+ * Run a raw MongoDB command
127
+ */
128
+ return this.db.command(...args)
129
+ }
130
+
131
+ Manager.prototype.connectionString = function(uri, databaseName) {
132
+ /**
133
+ * get the connection string
134
+ * @param {string|array} uri
135
+ * @param {string} <databaseName>
136
+ * @return {string}
137
+ */
138
+ if (!uri) {
139
+ throw Error('No connection URI provided.')
140
+ }
141
+ // uri: array, sort out the connection string
142
+ if (util.isArray(uri)) {
143
+ if (!databaseName) {
144
+ for (var i=0, l=uri.length; i<l; i++) {
145
+ if (!databaseName) databaseName = uri[i].replace(/([^\/])+\/?/, '') // eslint-disable-line
146
+ uri[i] = uri[i].replace(/\/.*/, '')
147
+ }
148
+ }
149
+ uri = uri.join(',') + '/' + databaseName
150
+ }
151
+ // uri: string, sort out the connection string
152
+ if (typeof uri === 'string') {
153
+ if (!/^mongodb(\+srv)?:\/\//.test(uri)) {
154
+ uri = 'mongodb://' + uri
155
+ }
156
+ }
157
+ return uri
158
+ }
159
+
160
+ Manager.prototype.get = function(name, options) {
161
+ /**
162
+ * Returns a MongoDB collection
163
+ * @param {String} name
164
+ * @param {Object} [options] - options to pass to the collection
165
+ * @return {MongoDB Collection}
166
+ */
167
+ if (!this.collections[name] || (options||{}).cache === false) {
168
+ delete (options||{}).cache
169
+ this.collections[name] = new Collection(this, name, options)
170
+ }
171
+ return this.collections[name]
172
+ }
173
+
174
+ Manager.prototype.id = function(str) {
175
+ return util.id(str)
176
+ }
177
+
178
+ Manager.prototype.isId = function(value) {
179
+ return util.isId(value)
180
+ }
181
+
182
+ Manager.prototype.models = async function(pathname, opts) {
183
+ /**
184
+ * Setup model definitions from a folder location
185
+ * @param {string} pathname
186
+ * @param {object} opts:
187
+ * @param {boolean} opts.waitForIndexes - Wait for indexes to be created?
188
+ * @return {Promise(object)} - e.g. { user: , article: , .. }
189
+ * @this Manager
190
+ */
191
+ let out = {}
192
+ let { waitForIndexes } = opts || {}
193
+ if (!pathname || typeof pathname !== 'string') {
194
+ throw 'The path must be a valid pathname'
195
+ }
196
+ let filenames = fs.readdirSync(pathname)
197
+ for (let filename of filenames) {
198
+ // Ignore folders
199
+ if (!filename.match(/\.[cm]?js$/)) continue
200
+ let name = filename.replace('.js', '')
201
+ let filepath = path.join(pathname, filename)
202
+ // We can't use require() here since we need to be able to import both CJS and ES6 modules
203
+ let definition = ((await import(filepath))||{}).default
204
+ // When a commonJS project uses babel (e.g. `nodemon -r @babel/register`, similar to `-r esm`), import()
205
+ // will return ES6 model definitions in another nested `default` object
206
+ if (definition && definition.default) definition = definition.default
207
+ if (!definition) throw new Error(`The model definition for '${name}' must export a default object`)
208
+ // Wait for indexes to be created?
209
+ if (waitForIndexes) out[name] = await this.model(name, definition, waitForIndexes)
210
+ else out[name] = this.model(name, definition)
211
+ }
212
+ return out
213
+ }
214
+
215
+ Manager.prototype.onError = function(fn) {
216
+ /**
217
+ * Called when an error occurs when trying to connect to the MongoClient.
218
+ * @param {Function} fn
219
+ * @return {Promise}
220
+ */
221
+ return new Promise((resolve, reject) => {
222
+ this.on('error', (err) => {
223
+ resolve(err)
224
+ })
225
+ }).then((err) => {
226
+ return fn(err)
227
+ })
228
+ }
229
+
230
+ Manager.prototype.onOpen = function(fn) {
231
+ /**
232
+ * Called when a successful MongoClient connection has been made.
233
+ * @param {Function} fn
234
+ * @return {Promise(manager)}
235
+ */
236
+ return new Promise((resolve, reject) => {
237
+ if (this._state == 'open') {
238
+ resolve(this)
239
+ }
240
+ this.on('open', () => {
241
+ resolve(this)
242
+ })
243
+ this.on('error', (err) => {
244
+ reject(err)
245
+ })
246
+ }).then((err) => { // If `then` is not chained, the error will be thrown, detached!
247
+ return fn(err)
248
+ })
249
+ }
250
+
251
+ Manager.prototype.open = async function() {
252
+ /**
253
+ * Connect to the database
254
+ * @return {Promise(manager)}
255
+ */
256
+ try {
257
+ this._state = 'opening'
258
+ this.db = this.client.db()
259
+ await this.client.connect() // now optional since db().command() will auto-connect
260
+ this.emit(this._state = 'open', this)
261
+ return this
262
+
263
+ } catch (err) {
264
+ this._state = 'closed'
265
+ // Only emit the error if there are listeners, since it will throw an unhandled error
266
+ if (this.listeners('error').length > 0) {
267
+ this.emit('error', err)
268
+ }
269
+ if (this.opts.promise || this.listeners('error').length == 0) {
270
+ throw new Error(err)
271
+ }
272
+ }
273
+ }
274
+
275
+ Manager.prototype.parseData = function(obj, parseBracketToDotNotation, parseDotNotation) {
276
+ return util.parseData(obj, parseBracketToDotNotation, parseDotNotation)
277
+ }
278
+
279
+ Manager.prototype.model = Model
280
+
281
+ Manager.prototype.getSignedUrl = imagePluginFile.getSignedUrl
282
+
283
+ Manager.prototype._getSignedUrl = () => {
284
+ throw new Error('monastery._getSignedUrl() has been moved to monastery.getSignedUrl()')
285
+ }
286
+
287
+ inherits(Manager, EventEmitter)
288
+
289
+ module.exports = Manager
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.5.0",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
@@ -4,7 +4,7 @@ const bird = require('./mock/blacklisting.js').bird
4
4
  const user = require('./mock/blacklisting.js').user
5
5
 
6
6
  let db
7
- beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
7
+ beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery', { timestamps: false }) })
8
8
  afterAll(async () => { db.close() })
9
9
 
10
10
  test('find blacklisting basic', async () => {
@@ -5,7 +5,7 @@ const util = require('../lib/util.js')
5
5
  // Setup/destroy
6
6
  let db, userCol, indexCol, indexDropCol
7
7
  beforeAll(async () => {
8
- db = monastery('127.0.0.1/monastery')
8
+ db = monastery.manager('127.0.0.1/monastery')
9
9
  userCol = db.get('users-' + Date.now())
10
10
  indexCol = db.get('index-' + Date.now())
11
11
  indexDropCol = db.get('index-' + Date.now())
@@ -2,7 +2,7 @@ const monastery = require('../lib/index.js')
2
2
  const mongoose = require('mongoose') // very slow initialisation
3
3
 
4
4
  test('comparison insert', async () => {
5
- const db = monastery('127.0.0.1/monastery', { timestamps: false })
5
+ const db = monastery.manager('127.0.0.1/monastery', { timestamps: false })
6
6
  const Test1 = db.model('Test1', { fields: {
7
7
  raw: {
8
8
  words: [{
@@ -70,7 +70,7 @@ test('comparison validate', async () => {
70
70
  })),
71
71
  }
72
72
  }
73
- const db = monastery('127.0.0.1/monastery', { timestamps: false })
73
+ const db = monastery.manager('127.0.0.1/monastery', { timestamps: false })
74
74
  const Test1 = db.model('Test1', { fields: {
75
75
  raw: {
76
76
  words: [{
package/test/crud.js CHANGED
@@ -2,11 +2,11 @@
2
2
  const monastery = require('../lib/index.js')
3
3
 
4
4
  let db
5
- beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
5
+ beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery', { timestamps: false }) })
6
6
  afterAll(async () => { db.close() })
7
7
 
8
8
  test('insert basics', async () => {
9
- let db2 = monastery('127.0.0.1/monastery', { timestamps: false })
9
+ let db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
10
10
  let user = db2.model('user', { fields: {
11
11
  name: { type: 'string' },
12
12
  names: [{ type: 'string' }],
@@ -52,7 +52,7 @@ test('insert basics', async () => {
52
52
  })
53
53
 
54
54
  test('insert option defaultObjects', async () => {
55
- let db2 = monastery('127.0.0.1/monastery', {
55
+ let db2 = monastery.manager('127.0.0.1/monastery', {
56
56
  defaultObjects: true,
57
57
  timestamps: false,
58
58
  imagePlugin: {
@@ -97,7 +97,7 @@ test('insert option defaultObjects', async () => {
97
97
  })
98
98
 
99
99
  test('insert option timestamps', async () => {
100
- let db2 = monastery('127.0.0.1/monastery', { timestamps: true })
100
+ let db2 = monastery.manager('127.0.0.1/monastery', { timestamps: true })
101
101
  let schema = {
102
102
  fields: {
103
103
  name: { type: 'string' },
@@ -353,12 +353,9 @@ 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
- const db = monastery('127.0.0.1/monastery', { noDefaults: noDefaults, timestamps: false })
358
+ const db = monastery.manager('127.0.0.1/monastery', { noDefaults: noDefaults, timestamps: false })
362
359
  const userDefinition = {
363
360
  fields: {
364
361
  name: { type: 'string', default: 'Martin Luther' },
@@ -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 () => {
@@ -577,7 +577,7 @@ test('update general', async () => {
577
577
  })
578
578
 
579
579
  test('update defaults', async () => {
580
- const db2 = monastery('127.0.0.1/monastery', { useMilliseconds: true })
580
+ const db2 = monastery.manager('127.0.0.1/monastery', { useMilliseconds: true })
581
581
  let user = db2.model('user', {
582
582
  fields: {
583
583
  name: { type: 'string' },
@@ -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 = [
@@ -1277,7 +1276,7 @@ test('hooks > async', async () => {
1277
1276
  })
1278
1277
 
1279
1278
  test('hooks > async and next conflict', async () => {
1280
- const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
1279
+ const db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
1281
1280
  let user1 = db2.model('user', {
1282
1281
  fields: { age: { type: 'number'} },
1283
1282
  afterFind: [
@@ -1442,7 +1441,7 @@ test('hooks > option skipHooks', async () => {
1442
1441
  })
1443
1442
 
1444
1443
  test('update set and unset with option skipValidation', async () => {
1445
- const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
1444
+ const db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
1446
1445
  let user = db2.model('user_set_and_unset', {
1447
1446
  fields: {
1448
1447
  profile: {
@@ -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/manager.js CHANGED
@@ -2,23 +2,23 @@ const { MongoClient } = require('mongodb')
2
2
  const monastery = require('../lib/index.js')
3
3
 
4
4
  test('manager > basics', async () => {
5
- const manager = monastery('localhost/monastery', { serverSelectionTimeoutMS: 2000 })
5
+ const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 2000 })
6
6
  // Manager is exposed
7
- expect(manager).toEqual(monastery.manager)
7
+ expect(monastery.uri).toEqual(expect.any(String))
8
8
  // Basic find command
9
- expect(await manager.db.collection('non-collection').findOne({})).toEqual(null)
9
+ expect(await db.db.collection('non-collection').findOne({})).toEqual(null)
10
10
  // Raw MongoDB ping command
11
- expect(await manager.command({ ping: 1 })).toMatchObject({ ok: 1 }) // cluster connections return extra fields
12
- manager.close()
11
+ expect(await db.command({ ping: 1 })).toMatchObject({ ok: 1 }) // cluster connections return extra fields
12
+ db.close()
13
13
  })
14
14
 
15
15
  test('manager > uri error', async () => {
16
- expect(() => monastery('', {})).toThrow('No connection URI provided.')
16
+ expect(() => monastery.manager('', {})).toThrow('No connection URI provided.')
17
17
  })
18
18
 
19
19
  test('manager > onError', async () => {
20
20
  // Bad port (thrown by MongoDB)
21
- const db = monastery('localhost:1234/monastery', { serverSelectionTimeoutMS: 500 })
21
+ const db = monastery.manager('localhost:1234/monastery', { serverSelectionTimeoutMS: 500 })
22
22
  let error, isAPromise
23
23
  await db.onError((res) => { error = res.message }).then(() => { isAPromise = true })
24
24
  expect(error).toEqual('connect ECONNREFUSED 127.0.0.1:1234')
@@ -27,7 +27,7 @@ test('manager > onError', async () => {
27
27
  })
28
28
 
29
29
  test('manager > onOpen', async () => {
30
- const db = monastery('localhost/monastery', { serverSelectionTimeoutMS: 500 })
30
+ const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 500 })
31
31
 
32
32
  let manager1
33
33
  await db.onOpen((res) => { manager1 = res })
@@ -52,7 +52,7 @@ test('manager > onOpen', async () => {
52
52
  test('manager > onOpen error', async () => {
53
53
  // Bad port (thrown by MongoDB)
54
54
  let manager
55
- const db = monastery('localhost:1234/monastery', { serverSelectionTimeoutMS: 500 })
55
+ const db = monastery.manager('localhost:1234/monastery', { serverSelectionTimeoutMS: 500 })
56
56
  await expect(db.onOpen((res) => { manager = res })).rejects.toThrow('connect ECONNREFUSED 127.0.0.1:1234')
57
57
  expect(manager).toEqual(undefined)
58
58
  expect(db).toEqual(expect.any(Object))
@@ -60,19 +60,19 @@ test('manager > onOpen error', async () => {
60
60
  })
61
61
 
62
62
  test('manager > return a promise', async () => {
63
- const db = await monastery('localhost/monastery', { serverSelectionTimeoutMS: 500, promise: true })
63
+ const db = await monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 500, promise: true })
64
64
  expect(db).toEqual(expect.any(Object))
65
65
  db.close()
66
66
  })
67
67
 
68
68
  test('manager > return a promise with uri error', async () => {
69
- await expect(monastery('badlocalhost/monastery', { serverSelectionTimeoutMS: 500, promise: true }))
69
+ await expect(monastery.manager('badlocalhost/monastery', { serverSelectionTimeoutMS: 500, promise: true }))
70
70
  .rejects.toThrow('getaddrinfo EAI_AGAIN badlocalhost')
71
71
  })
72
72
 
73
73
  test('manager > reuse MongoDB Client', async () => {
74
74
  const mongoClient = new MongoClient('mongodb://localhost/monastery', {})
75
- const db = await monastery(mongoClient, { serverSelectionTimeoutMS: 500, promise: true })
75
+ const db = await monastery.manager(mongoClient, { serverSelectionTimeoutMS: 500, promise: true })
76
76
  expect(db).toEqual(expect.any(Object))
77
77
  expect(db.client).toEqual(expect.any(Object))
78
78
  expect(db.isId).toEqual(expect.any(Function))
@@ -87,7 +87,7 @@ test('manager > events', async () => {
87
87
  })
88
88
  }
89
89
  // Triggers on opening/open
90
- const db = monastery('localhost/monastery', { serverSelectionTimeoutMS: 2000 })
90
+ const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 2000 })
91
91
  expect(db._state).toEqual('opening')
92
92
  // Start waiting for the following events
93
93
  const promises = Promise.all([
@@ -101,10 +101,10 @@ test('manager > events', async () => {
101
101
  })
102
102
 
103
103
  test('Manager > get collection', async () => {
104
- const manager = monastery('localhost/monastery', { serverSelectionTimeoutMS: 500 })
104
+ const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 500 })
105
105
  // Basic aggregate command
106
- expect(await manager.get('non-collection').aggregate([], {})).toEqual([])
106
+ expect(await db.get('non-collection').aggregate([], {})).toEqual([])
107
107
  // Basic find command
108
- expect(await manager.get('non-collection').find({})).toEqual([])
109
- manager.close()
108
+ expect(await db.get('non-collection').find({})).toEqual([])
109
+ db.close()
110
110
  })