monastery 3.5.8 → 3.5.10
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 +4 -0
- package/lib/manager.js +5 -2
- package/lib/model.js +19 -1
- package/package.json +1 -1
- package/test/manager.js +16 -5
- package/test/model.js +21 -0
- package/types/lib/util.d.ts +1 -1
- package/types/lib/util.d.ts.map +1 -1
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
|
+
### [3.5.10](https://github.com/boycce/monastery/compare/3.5.9...3.5.10) (2026-02-02)
|
|
6
|
+
|
|
7
|
+
### [3.5.9](https://github.com/boycce/monastery/compare/3.5.8...3.5.9) (2025-12-23)
|
|
8
|
+
|
|
5
9
|
### [3.5.8](https://github.com/boycce/monastery/compare/3.5.6...3.5.8) (2025-12-23)
|
|
6
10
|
|
|
7
11
|
### [3.5.7](https://github.com/boycce/monastery/compare/3.5.6...3.5.7) (2025-09-16)
|
package/lib/manager.js
CHANGED
|
@@ -37,10 +37,10 @@ function Manager(uri, opts, parent) {
|
|
|
37
37
|
if (typeof opts.logLevel == 'undefined') opts.logLevel = 2
|
|
38
38
|
|
|
39
39
|
// opts: separate out monastery options
|
|
40
|
-
const mongoOpts = Object.keys(opts||{}).reduce((acc, key) => {
|
|
40
|
+
const mongoOpts = Object.keys(opts || {}).reduce((acc, key) => {
|
|
41
41
|
if (![
|
|
42
42
|
'databaseName', 'defaultObjects', 'logLevel', 'imagePlugin', 'limit', 'noDefaults', 'nullObjects',
|
|
43
|
-
'promise', 'timestamps', 'useMilliseconds',
|
|
43
|
+
'promise', 'timestamps', 'useMilliseconds', 'forJest',
|
|
44
44
|
].includes(key)) {
|
|
45
45
|
acc[key] = opts[key]
|
|
46
46
|
}
|
|
@@ -57,6 +57,7 @@ function Manager(uri, opts, parent) {
|
|
|
57
57
|
that.collections = {}
|
|
58
58
|
that._openQueue = []
|
|
59
59
|
that.emitter = new EventEmitter()
|
|
60
|
+
that.forJest = opts.forJest || false
|
|
60
61
|
|
|
61
62
|
// If there is no DEBUG= environment variable, we will need to force the debugs on (due to bug on debug@4.3.4)
|
|
62
63
|
if (!debug.namespaces) {
|
|
@@ -283,9 +284,11 @@ Manager.prototype.open = async function() {
|
|
|
283
284
|
* @return {Promise(manager)}
|
|
284
285
|
*/
|
|
285
286
|
try {
|
|
287
|
+
this.openTimestamp = Date.now()
|
|
286
288
|
this._state = 'opening'
|
|
287
289
|
this.db = this.client.db()
|
|
288
290
|
await this.client.connect() // now optional since db().command() will auto-connect
|
|
291
|
+
if (!this.forJest) this.info(`Connected to MongoDB in ${Date.now() - this.openTimestamp}ms`)
|
|
289
292
|
this.emitter.emit(this._state = 'open', this)
|
|
290
293
|
return this
|
|
291
294
|
|
package/lib/model.js
CHANGED
|
@@ -346,7 +346,25 @@ Model.prototype._setupIndexes = async function(fields, opts={}) {
|
|
|
346
346
|
const collection = this.collection
|
|
347
347
|
|
|
348
348
|
// Get the collections indexes
|
|
349
|
-
|
|
349
|
+
let existingIndexes = []
|
|
350
|
+
try {
|
|
351
|
+
existingIndexes = await collection.indexes() // returns [] if collection doesn't exist
|
|
352
|
+
} catch (err) {
|
|
353
|
+
// Show a succinct error message for timeout errors, which is due to onOpen() timing out.
|
|
354
|
+
if (err.message.match(/Server selection timed out after/)) {
|
|
355
|
+
const msg = `Unable to create an index on the '${model.name||''}' model, the server selection has timed out already.`
|
|
356
|
+
if (model.manager.forJest) throw new Error(msg)
|
|
357
|
+
else this.error(msg)
|
|
358
|
+
return []
|
|
359
|
+
} else if (err.message.match(/Topology is closed/)) {
|
|
360
|
+
const msg = `Unable to create an index on the '${model.name||''}' model, the 'Topology is closed'. Bad connection URL?`
|
|
361
|
+
if (model.manager.forJest) throw new Error(msg)
|
|
362
|
+
else this.error(msg)
|
|
363
|
+
return []
|
|
364
|
+
} else {
|
|
365
|
+
throw err
|
|
366
|
+
}
|
|
367
|
+
}
|
|
350
368
|
|
|
351
369
|
// Remove any existing text index that has different options as createIndexes will throws error about this
|
|
352
370
|
if (existingIndexes.length) {
|
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.5.
|
|
5
|
+
"version": "3.5.10",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:boycce/monastery",
|
|
8
8
|
"homepage": "https://boycce.github.io/monastery/",
|
package/test/manager.js
CHANGED
|
@@ -21,7 +21,7 @@ test('manager > onError', async () => {
|
|
|
21
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
|
-
expect(error).toContain('connect ECONNREFUSED
|
|
24
|
+
expect(error).toContain('connect ECONNREFUSED ')
|
|
25
25
|
expect(isAPromise).toEqual(true)
|
|
26
26
|
db.close()
|
|
27
27
|
})
|
|
@@ -53,7 +53,18 @@ test('manager > onOpen error', async () => {
|
|
|
53
53
|
// Bad port (thrown by MongoDB)
|
|
54
54
|
let manager
|
|
55
55
|
const db = monastery.manager('localhost:1234/monastery', { serverSelectionTimeoutMS: 500 })
|
|
56
|
-
await expect(db.onOpen((res) => { manager = res })).rejects.toThrow('connect ECONNREFUSED
|
|
56
|
+
await expect(db.onOpen((res) => { manager = res })).rejects.toThrow('connect ECONNREFUSED ')
|
|
57
|
+
expect(manager).toEqual(undefined)
|
|
58
|
+
expect(db).toEqual(expect.any(Object))
|
|
59
|
+
db.close()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('manager > onOpen timeout error', async () => {
|
|
63
|
+
// Bad connection url, which will hang and timeout after 100ms
|
|
64
|
+
// Related: test/model.js > model index timeout topology closed
|
|
65
|
+
let manager
|
|
66
|
+
const db = monastery.manager('google.com', { serverSelectionTimeoutMS:100, logLevel: 3 }) // should hang
|
|
67
|
+
await expect(db.onOpen((res) => { manager = res })).rejects.toThrow('Server selection timed out after 100 ms')
|
|
57
68
|
expect(manager).toEqual(undefined)
|
|
58
69
|
expect(db).toEqual(expect.any(Object))
|
|
59
70
|
db.close()
|
|
@@ -110,9 +121,9 @@ test('Manager > get collection', async () => {
|
|
|
110
121
|
})
|
|
111
122
|
|
|
112
123
|
test('Manager > multiple managers', async () => {
|
|
113
|
-
const db1 = monastery.manager('localhost/monastery', { logLevel: 5 })
|
|
114
|
-
const db2 = monastery.manager('localhost/monastery', { logLevel: 6 })
|
|
115
|
-
const db3 = monastery.manager('localhost/monastery', { logLevel: 7 })
|
|
124
|
+
const db1 = monastery.manager('localhost/monastery', { logLevel: 5, forJest: true })
|
|
125
|
+
const db2 = monastery.manager('localhost/monastery', { logLevel: 6, forJest: true })
|
|
126
|
+
const db3 = monastery.manager('localhost/monastery', { logLevel: 7, forJest: true })
|
|
116
127
|
|
|
117
128
|
expect(monastery.opts.logLevel).not.toEqual(6) // default manager
|
|
118
129
|
expect(db2.opts.logLevel).not.toEqual(db1.opts.logLevel)
|
package/test/model.js
CHANGED
|
@@ -495,6 +495,27 @@ test('model indexes basic', async () => {
|
|
|
495
495
|
}])
|
|
496
496
|
})
|
|
497
497
|
|
|
498
|
+
test('model index timeout topology closed', async () => {
|
|
499
|
+
// 1. For a invalid URL, while a connection is still opening, we should expect a
|
|
500
|
+
// 'topology is closed' error when trying to create an index.
|
|
501
|
+
// 2. For valid connection URL, we should expect a 'server selection timed out' error (which we can't reproduce in tests)
|
|
502
|
+
const db2 = monastery.manager('google.com', { logLevel: 3, serverSelectionTimeoutMS: 50, forJest: true })
|
|
503
|
+
// Attempt to use the collection while the connection is still opening.
|
|
504
|
+
const userIndexErrModel = db2.model('userIndexErr', {
|
|
505
|
+
fields: {
|
|
506
|
+
age: { type: 'number' },
|
|
507
|
+
name: { type: 'string' },
|
|
508
|
+
},
|
|
509
|
+
})
|
|
510
|
+
expect(
|
|
511
|
+
userIndexErrModel._setupIndexes({ age: { type: 'number', index: 'text' }, name: { type: 'string', index: 'text' } })
|
|
512
|
+
).rejects.toThrow('Unable to create an index on the \'userIndexErr\' model, the \'Topology is closed\'. Bad connection URL?')
|
|
513
|
+
await expect(
|
|
514
|
+
db2.onOpen((res) => { })
|
|
515
|
+
).rejects.toThrow('Server selection timed out after 50 ms')
|
|
516
|
+
db2.close()
|
|
517
|
+
})
|
|
518
|
+
|
|
498
519
|
test('model indexes unique', async () => {
|
|
499
520
|
// Setup: Drop previously tested collections
|
|
500
521
|
if ((await db.db.listCollections().toArray()).find(o => o.name == 'userUniqueIndex')) {
|
package/types/lib/util.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export function deepCopy(obj: any): any;
|
|
|
4
4
|
export function deepFind(obj: any, path: any): any;
|
|
5
5
|
export function forEach(obj: any, iteratee: any, context: any): any;
|
|
6
6
|
export function forceArray(value: any): any[];
|
|
7
|
-
export function id(
|
|
7
|
+
export function id(value?: string | ObjectId): ObjectId;
|
|
8
8
|
export function inArray(array: any, key: any, value: any): any;
|
|
9
9
|
export function isArray(value: any): value is any[];
|
|
10
10
|
export function isArrayLike(collection: any): boolean;
|
package/types/lib/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../lib/util.js"],"names":[],"mappings":";AAIQ,oCAwBL;AAES,wCAUT;AAES,mDAYT;AAEQ,oEAYR;AAEW,8CAEX;
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../lib/util.js"],"names":[],"mappings":";AAIQ,oCAwBL;AAES,wCAUT;AAES,mDAYT;AAEQ,oEAYR;AAEW,8CAEX;AAWG,2BAFO,SAAU,QAAQ,YAO5B;AAEQ,+DAaR;AAEQ,oDAER;AAEY,sDAGZ;AAEU,+CAEV;AAEQ,2CAIR;AAEW,gDAEX;AAEK,0CAKL;AAEQ,6CAiBR;AAES,8CAET;AAES,8CAMT;AAEiB,sDAGjB;AAEQ,6CAER;AAES,8CAET;AAES,8CAET;AAEc,mDAmBd;AAEsB,uDAQtB;AAEY,4DAEZ;AAEK,iDAOL;AAEU,gGAWV;AAEiB,gDA+BjB;AAEqB,oDAmCrB;AAE0B,wDAsB1B;AAEK,8CAeL;AAEgB,oDAYhB;AAEU,8EAmDV;AAEa,uIAwCb;AAEkB,yDAElB;AAEQ,8CAIR;AAEQ,0CAGR;AAEK,4CAEL"}
|