monastery 3.4.3 → 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/changelog.md +2 -0
- package/docs/definition/index.md +1 -1
- package/docs/manager/index.md +9 -8
- package/docs/readme.md +3 -2
- package/lib/index.js +17 -286
- package/lib/manager.js +289 -0
- package/package.json +1 -1
- package/test/blacklisting.js +1 -1
- package/test/collection.js +1 -1
- package/test/comparison.js +2 -2
- package/test/crud.js +8 -8
- package/test/manager.js +17 -17
- package/test/model.js +4 -4
- package/test/plugin-images.js +6 -6
- package/test/populate.js +1 -1
- package/test/util.js +3 -3
- package/test/validate.js +5 -5
- package/test/virtuals.js +1 -1
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.5.0](https://github.com/boycce/monastery/compare/3.4.3...3.5.0) (2024-12-20)
|
|
6
|
+
|
|
5
7
|
### [3.4.3](https://github.com/boycce/monastery/compare/3.4.2...3.4.3) (2024-08-27)
|
|
6
8
|
|
|
7
9
|
### [3.4.2](https://github.com/boycce/monastery/compare/3.4.1...3.4.2) (2024-08-24)
|
package/docs/definition/index.md
CHANGED
|
@@ -304,7 +304,7 @@ You are able to define custom error messages for each field rule.
|
|
|
304
304
|
|
|
305
305
|
### Operation hooks
|
|
306
306
|
|
|
307
|
-
You are able provide an array of
|
|
307
|
+
You are able provide an array of promises to the following model operation hooks. `this` is the operation details.
|
|
308
308
|
|
|
309
309
|
```js
|
|
310
310
|
{
|
package/docs/manager/index.md
CHANGED
|
@@ -6,7 +6,7 @@ has_children: true
|
|
|
6
6
|
|
|
7
7
|
# Manager
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Creates a new manager instance and makes the first instance available globally via the `db`.
|
|
10
10
|
|
|
11
11
|
### Arguments
|
|
12
12
|
|
|
@@ -24,26 +24,27 @@ Monastery manager constructor.
|
|
|
24
24
|
|
|
25
25
|
### Returns
|
|
26
26
|
|
|
27
|
-
A manager instance.
|
|
27
|
+
A new manager instance.
|
|
28
28
|
|
|
29
29
|
### Example
|
|
30
30
|
|
|
31
31
|
```js
|
|
32
|
-
import
|
|
32
|
+
import db from 'monastery'
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
// this manager instance is now available via the `db` object on subsequent imports
|
|
35
|
+
const manager = db.manager('localhost/mydb', options)
|
|
35
36
|
// replica set
|
|
36
|
-
const
|
|
37
|
+
const manager = db.manager('localhost/mydb,192.168.1.1')
|
|
37
38
|
// you can wait for the connection (which is not required before calling methods)
|
|
38
|
-
const
|
|
39
|
+
const manager = await db.manager('localhost/mydb,192.168.1.1', { promise: true })
|
|
39
40
|
```
|
|
40
41
|
|
|
41
42
|
You can also listen for errors or successful connection using these hooks
|
|
42
43
|
```js
|
|
43
|
-
|
|
44
|
+
manager.onOpen((manager) => {
|
|
44
45
|
// manager.client is connected...
|
|
45
46
|
})
|
|
46
|
-
|
|
47
|
+
manager.onError((err) => {
|
|
47
48
|
// connection error
|
|
48
49
|
})
|
|
49
50
|
```
|
package/docs/readme.md
CHANGED
|
@@ -35,10 +35,10 @@ $ npm install --save monastery
|
|
|
35
35
|
## Usage
|
|
36
36
|
|
|
37
37
|
```javascript
|
|
38
|
-
import
|
|
38
|
+
import db from 'monastery'
|
|
39
39
|
|
|
40
40
|
// Initialize a monastery manager
|
|
41
|
-
|
|
41
|
+
db.manager('localhost/mydb')
|
|
42
42
|
|
|
43
43
|
// Define a model
|
|
44
44
|
db.model('user', {
|
|
@@ -96,6 +96,7 @@ You can view MongoDB's [compatibility table here](https://www.mongodb.com/docs/d
|
|
|
96
96
|
- db.catch/then() moved to db.onError/db.onOpen()
|
|
97
97
|
- next() is now redundant when returning promises from hooks, e.g. `afterFind: [async (data) => {...}]`
|
|
98
98
|
- deep paths in data, e.g. `books[].title` are now validated, and don't replace the whole object, e.g. `books`
|
|
99
|
+
- `db()` moved to `db.manager()`
|
|
99
100
|
|
|
100
101
|
## v2 Breaking Changes
|
|
101
102
|
|
package/lib/index.js
CHANGED
|
@@ -1,301 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const debug = require('debug')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const EventEmitter = require('events').EventEmitter
|
|
1
|
+
const Manager = require('./manager')
|
|
6
2
|
const inherits = require('util').inherits
|
|
7
|
-
const { MongoClient } = require('mongodb')
|
|
8
|
-
const Collection = require('./collection.js')
|
|
9
|
-
const imagePluginFile = require('../plugins/images/index.js')
|
|
10
|
-
const Model = require('./model.js')
|
|
11
3
|
const rules = require('./rules.js')
|
|
12
|
-
const util = require('./util.js')
|
|
13
4
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
* Constructs a new manager which contains a new MongoDB client
|
|
17
|
-
*
|
|
18
|
-
* @param {String|Array|Object} uri - MongoDB connection URI string / replica set, or reuse a MongoClient instance
|
|
19
|
-
* @param {Object} opts -
|
|
20
|
-
* {String} <opts.databaseName> - the name of the database
|
|
21
|
-
* {Boolean} <opts.promise(manager)> - return a promise
|
|
22
|
-
*
|
|
23
|
-
* @return {Connection|Promise}
|
|
24
|
-
* @link https://www.mongodb.com/docs/drivers/node/v5.9/quick-reference/
|
|
25
|
-
* @link https://mongodb.github.io/node-mongodb-native/ (all versions)
|
|
26
|
-
*/
|
|
27
|
-
if (!opts) opts = {}
|
|
28
|
-
if (!(this instanceof Manager)) return new Manager(uri, opts)
|
|
5
|
+
function Monastery() {
|
|
6
|
+
let hasDefaultManager = false
|
|
29
7
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// opts: separate out monastery options
|
|
38
|
-
const mongoOpts = Object.keys(opts||{}).reduce((acc, key) => {
|
|
39
|
-
if (
|
|
40
|
-
![
|
|
41
|
-
'databaseName', 'defaultObjects', 'logLevel', 'imagePlugin', 'limit', 'noDefaults', 'nullObjects',
|
|
42
|
-
'promise', 'timestamps', 'useMilliseconds',
|
|
43
|
-
].includes(key)) {
|
|
44
|
-
acc[key] = opts[key]
|
|
45
|
-
}
|
|
46
|
-
return acc
|
|
47
|
-
}, {})
|
|
48
|
-
|
|
49
|
-
// Add properties
|
|
50
|
-
this.uri = uri
|
|
51
|
-
this.error = debug('monastery:error' + (opts.logLevel > 0 ? '*' : ''))
|
|
52
|
-
this.warn = debug('monastery:warn' + (opts.logLevel > 1 ? '*' : ''))
|
|
53
|
-
this.info = debug('monastery:info' + (opts.logLevel > 2 ? '*' : ''))
|
|
54
|
-
this.opts = opts
|
|
55
|
-
this.beforeModel = []
|
|
56
|
-
this.collections = {}
|
|
57
|
-
this._openQueue = []
|
|
58
|
-
|
|
59
|
-
// If there is no DEBUG= environment variable, we will need to force the debugs on (due to bug on debug@4.3.4)
|
|
60
|
-
if (!debug.namespaces) {
|
|
61
|
-
if (opts.logLevel > 0) this.error.enabled = true
|
|
62
|
-
if (opts.logLevel > 1) this.warn.enabled = true
|
|
63
|
-
if (opts.logLevel > 2) this.info.enabled = true
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Create a new MongoDB Client
|
|
67
|
-
if (typeof this.uri == 'string' || Array.isArray(this.uri)) {
|
|
68
|
-
this.uri = this.connectionString(this.uri, opts.databaseName)
|
|
69
|
-
this.client = new MongoClient(this.uri, mongoOpts)
|
|
70
|
-
} else {
|
|
71
|
-
this.client = this.uri
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Listen to MongoDB events
|
|
75
|
-
for (let eventName of ['close', 'error', 'timeout']) {
|
|
76
|
-
this.client.on(eventName, (e) => this.emit(eventName, e))
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Listen to custom open event
|
|
80
|
-
this.on('open', () => {
|
|
81
|
-
// wait for all the on('open') events to get called first
|
|
82
|
-
setTimeout(() => {
|
|
83
|
-
for (let item of this._openQueue) {
|
|
84
|
-
item()
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// Initiate any plugins
|
|
90
|
-
if (opts.imagePlugin) {
|
|
91
|
-
imagePluginFile.setup(this, util.isObject(opts.imagePlugin) ? opts.imagePlugin : {})
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Expose the last manager
|
|
95
|
-
module.exports.manager = this
|
|
96
|
-
|
|
97
|
-
// Connect to the database
|
|
98
|
-
if (opts.promise) return this.open()
|
|
99
|
-
else this.open()
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
Manager.prototype.arrayWithSchema = function(array, schema) {
|
|
103
|
-
array.schema = schema
|
|
104
|
-
return array
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
Manager.prototype.close = async function() {
|
|
108
|
-
/**
|
|
109
|
-
* Close the database connection, gracefully
|
|
110
|
-
*/
|
|
111
|
-
const _close = async () => {
|
|
112
|
-
this.emit(this._state = 'closing')
|
|
113
|
-
await this.client.close()
|
|
114
|
-
this.emit(this._state = 'close')
|
|
115
|
-
}
|
|
116
|
-
if (this._state == 'open') {
|
|
117
|
-
return await _close()
|
|
118
|
-
|
|
119
|
-
} else if (this._state == 'opening') {
|
|
120
|
-
return new Promise((resolve) => {
|
|
121
|
-
this._openQueue.push(() => _close().then(resolve))
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
} else if (this._state == 'close' || this._state == 'closing') {
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
Manager.prototype.command = function(...args) {
|
|
130
|
-
/**
|
|
131
|
-
* Run a raw MongoDB command
|
|
132
|
-
*/
|
|
133
|
-
return this.db.command(...args)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
Manager.prototype.connectionString = function(uri, databaseName) {
|
|
137
|
-
/**
|
|
138
|
-
* get the connection string
|
|
139
|
-
* @param {string|array} uri
|
|
140
|
-
* @param {string} <databaseName>
|
|
141
|
-
* @return {string}
|
|
142
|
-
*/
|
|
143
|
-
if (!uri) {
|
|
144
|
-
throw Error('No connection URI provided.')
|
|
145
|
-
}
|
|
146
|
-
// uri: array, sort out the connection string
|
|
147
|
-
if (util.isArray(uri)) {
|
|
148
|
-
if (!databaseName) {
|
|
149
|
-
for (var i=0, l=uri.length; i<l; i++) {
|
|
150
|
-
if (!databaseName) databaseName = uri[i].replace(/([^\/])+\/?/, '') // eslint-disable-line
|
|
151
|
-
uri[i] = uri[i].replace(/\/.*/, '')
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
uri = uri.join(',') + '/' + databaseName
|
|
155
|
-
}
|
|
156
|
-
// uri: string, sort out the connection string
|
|
157
|
-
if (typeof uri === 'string') {
|
|
158
|
-
if (!/^mongodb(\+srv)?:\/\//.test(uri)) {
|
|
159
|
-
uri = 'mongodb://' + uri
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return uri
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
Manager.prototype.get = function(name, options) {
|
|
166
|
-
/**
|
|
167
|
-
* Returns a MongoDB collection
|
|
168
|
-
* @param {String} name
|
|
169
|
-
* @param {Object} [options] - options to pass to the collection
|
|
170
|
-
* @return {MongoDB Collection}
|
|
171
|
-
*/
|
|
172
|
-
if (!this.collections[name] || (options||{}).cache === false) {
|
|
173
|
-
delete (options||{}).cache
|
|
174
|
-
this.collections[name] = new Collection(this, name, options)
|
|
175
|
-
}
|
|
176
|
-
return this.collections[name]
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
Manager.prototype.id = function(str) {
|
|
180
|
-
return util.id(str)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
Manager.prototype.isId = function(value) {
|
|
184
|
-
return util.isId(value)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
Manager.prototype.models = async function(pathname, opts) {
|
|
188
|
-
/**
|
|
189
|
-
* Setup model definitions from a folder location
|
|
190
|
-
* @param {string} pathname
|
|
191
|
-
* @param {object} opts:
|
|
192
|
-
* @param {boolean} opts.waitForIndexes - Wait for indexes to be created?
|
|
193
|
-
* @return {Promise(object)} - e.g. { user: , article: , .. }
|
|
194
|
-
* @this Manager
|
|
195
|
-
*/
|
|
196
|
-
let out = {}
|
|
197
|
-
let { waitForIndexes } = opts || {}
|
|
198
|
-
if (!pathname || typeof pathname !== 'string') {
|
|
199
|
-
throw 'The path must be a valid pathname'
|
|
200
|
-
}
|
|
201
|
-
let filenames = fs.readdirSync(pathname)
|
|
202
|
-
for (let filename of filenames) {
|
|
203
|
-
// Ignore folders
|
|
204
|
-
if (!filename.match(/\.[cm]?js$/)) continue
|
|
205
|
-
let name = filename.replace('.js', '')
|
|
206
|
-
let filepath = path.join(pathname, filename)
|
|
207
|
-
// We can't use require() here since we need to be able to import both CJS and ES6 modules
|
|
208
|
-
let definition = ((await import(filepath))||{}).default
|
|
209
|
-
// When a commonJS project uses babel (e.g. `nodemon -r @babel/register`, similar to `-r esm`), import()
|
|
210
|
-
// will return ES6 model definitions in another nested `default` object
|
|
211
|
-
if (definition && definition.default) definition = definition.default
|
|
212
|
-
if (!definition) throw new Error(`The model definition for '${name}' must export a default object`)
|
|
213
|
-
// Wait for indexes to be created?
|
|
214
|
-
if (waitForIndexes) out[name] = await this.model(name, definition, waitForIndexes)
|
|
215
|
-
else out[name] = this.model(name, definition)
|
|
216
|
-
}
|
|
217
|
-
return out
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
Manager.prototype.onError = function(fn) {
|
|
221
|
-
/**
|
|
222
|
-
* Called when an error occurs when trying to connect to the MongoClient.
|
|
223
|
-
* @param {Function} fn
|
|
224
|
-
* @return {Promise}
|
|
225
|
-
*/
|
|
226
|
-
return new Promise((resolve, reject) => {
|
|
227
|
-
this.on('error', (err) => {
|
|
228
|
-
resolve(err)
|
|
229
|
-
})
|
|
230
|
-
}).then((err) => {
|
|
231
|
-
return fn(err)
|
|
232
|
-
})
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
Manager.prototype.onOpen = function(fn) {
|
|
236
|
-
/**
|
|
237
|
-
* Called when a successful MongoClient connection has been made.
|
|
238
|
-
* @param {Function} fn
|
|
239
|
-
* @return {Promise(manager)}
|
|
240
|
-
*/
|
|
241
|
-
return new Promise((resolve, reject) => {
|
|
242
|
-
if (this._state == 'open') {
|
|
243
|
-
resolve(this)
|
|
244
|
-
}
|
|
245
|
-
this.on('open', () => {
|
|
246
|
-
resolve(this)
|
|
247
|
-
})
|
|
248
|
-
this.on('error', (err) => {
|
|
249
|
-
reject(err)
|
|
250
|
-
})
|
|
251
|
-
}).then((err) => { // If `then` is not chained, the error will be thrown, detached!
|
|
252
|
-
return fn(err)
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
Manager.prototype.open = async function() {
|
|
257
|
-
/**
|
|
258
|
-
* Connect to the database
|
|
259
|
-
* @return {Promise(manager)}
|
|
260
|
-
*/
|
|
261
|
-
try {
|
|
262
|
-
this._state = 'opening'
|
|
263
|
-
this.db = this.client.db()
|
|
264
|
-
await this.client.connect() // now optional since db().command() will auto-connect
|
|
265
|
-
this.emit(this._state = 'open', this)
|
|
266
|
-
return this
|
|
267
|
-
|
|
268
|
-
} catch (err) {
|
|
269
|
-
this._state = 'closed'
|
|
270
|
-
// Only emit the error if there are listeners, since it will throw an unhandled error
|
|
271
|
-
if (this.listeners('error').length > 0) {
|
|
272
|
-
this.emit('error', err)
|
|
273
|
-
}
|
|
274
|
-
if (this.opts.promise || this.listeners('error').length == 0) {
|
|
275
|
-
throw new Error(err)
|
|
8
|
+
this.manager = function(uri, opts) {
|
|
9
|
+
const manager = new Manager(uri, opts)
|
|
10
|
+
// Inherit the default manager onto Monastery once
|
|
11
|
+
if (!hasDefaultManager) {
|
|
12
|
+
hasDefaultManager = true
|
|
13
|
+
Object.assign(this, manager)
|
|
276
14
|
}
|
|
15
|
+
return manager
|
|
277
16
|
}
|
|
278
17
|
}
|
|
279
18
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
19
|
+
// Inherit Manager prototypes onto Monastery
|
|
20
|
+
inherits(Monastery, Manager)
|
|
283
21
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
inherits(Manager, EventEmitter)
|
|
291
|
-
module.exports = Manager
|
|
22
|
+
// Exports
|
|
23
|
+
module.exports = new Monastery()
|
|
24
|
+
module.exports.arrayWithSchema = Manager.prototype.arrayWithSchema
|
|
25
|
+
module.exports.getSignedUrl = Manager.prototype.getSignedUrl
|
|
292
26
|
module.exports.id = Manager.prototype.id
|
|
293
27
|
module.exports.isId = Manager.prototype.isId
|
|
294
|
-
module.exports.arrayWithSchema = Manager.prototype.arrayWithSchema
|
|
295
|
-
module.exports.parseData = Manager.prototype.parseData
|
|
296
28
|
module.exports.parseBracketNotation = Manager.prototype.parseBracketNotation
|
|
297
29
|
module.exports.parseBracketToDotNotation = Manager.prototype.parseBracketToDotNotation
|
|
30
|
+
module.exports.parseData = Manager.prototype.parseData
|
|
298
31
|
module.exports.parseDotNotation = Manager.prototype.parseDotNotation
|
|
299
|
-
module.exports.getSignedUrl = Manager.prototype.getSignedUrl
|
|
300
|
-
module.exports.manager = null
|
|
301
32
|
module.exports.rules = rules
|
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/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
|
+
"version": "3.5.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "github:boycce/monastery",
|
|
8
8
|
"homepage": "https://boycce.github.io/monastery/",
|
package/test/blacklisting.js
CHANGED
|
@@ -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 () => {
|
package/test/collection.js
CHANGED
|
@@ -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())
|
package/test/comparison.js
CHANGED
|
@@ -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' },
|
|
@@ -355,7 +355,7 @@ test('find default field population with option noDefaults', async () => {
|
|
|
355
355
|
async function setup(noDefaults) {
|
|
356
356
|
// @returns {Object} {dog, user, dog1Doc, dog2Doc, user1Doc}
|
|
357
357
|
// similar to "find default field population"
|
|
358
|
-
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 })
|
|
359
359
|
const userDefinition = {
|
|
360
360
|
fields: {
|
|
361
361
|
name: { type: 'string', default: 'Martin Luther' },
|
|
@@ -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' },
|
|
@@ -1276,7 +1276,7 @@ test('hooks > async', async () => {
|
|
|
1276
1276
|
})
|
|
1277
1277
|
|
|
1278
1278
|
test('hooks > async and next conflict', async () => {
|
|
1279
|
-
const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
|
|
1279
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
|
|
1280
1280
|
let user1 = db2.model('user', {
|
|
1281
1281
|
fields: { age: { type: 'number'} },
|
|
1282
1282
|
afterFind: [
|
|
@@ -1441,7 +1441,7 @@ test('hooks > option skipHooks', async () => {
|
|
|
1441
1441
|
})
|
|
1442
1442
|
|
|
1443
1443
|
test('update set and unset with option skipValidation', async () => {
|
|
1444
|
-
const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
|
|
1444
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
|
|
1445
1445
|
let user = db2.model('user_set_and_unset', {
|
|
1446
1446
|
fields: {
|
|
1447
1447
|
profile: {
|
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
|
|
5
|
+
const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 2000 })
|
|
6
6
|
// Manager is exposed
|
|
7
|
-
expect(
|
|
7
|
+
expect(monastery.uri).toEqual(expect.any(String))
|
|
8
8
|
// Basic find command
|
|
9
|
-
expect(await
|
|
9
|
+
expect(await db.db.collection('non-collection').findOne({})).toEqual(null)
|
|
10
10
|
// Raw MongoDB ping command
|
|
11
|
-
expect(await
|
|
12
|
-
|
|
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
|
|
104
|
+
const db = monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 500 })
|
|
105
105
|
// Basic aggregate command
|
|
106
|
-
expect(await
|
|
106
|
+
expect(await db.get('non-collection').aggregate([], {})).toEqual([])
|
|
107
107
|
// Basic find command
|
|
108
|
-
expect(await
|
|
109
|
-
|
|
108
|
+
expect(await db.get('non-collection').find({})).toEqual([])
|
|
109
|
+
db.close()
|
|
110
110
|
})
|
package/test/model.js
CHANGED
|
@@ -3,11 +3,11 @@ const Model = require('../lib/model.js')
|
|
|
3
3
|
const monastery = require('../lib/index.js')
|
|
4
4
|
|
|
5
5
|
let db
|
|
6
|
-
beforeAll(async () => { db = monastery('127.0.0.1/monastery') })
|
|
6
|
+
beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery') })
|
|
7
7
|
afterAll(async () => { db.close() })
|
|
8
8
|
|
|
9
9
|
test('model > model on manager', async () => {
|
|
10
|
-
const db2 = monastery('127.0.0.1', { logLevel: 0 })
|
|
10
|
+
const db2 = monastery.manager('127.0.0.1', { logLevel: 0 })
|
|
11
11
|
db2.model('user', { fields: {} })
|
|
12
12
|
let modelNamedConflict = db2.model('open', { fields: {} })
|
|
13
13
|
|
|
@@ -132,7 +132,7 @@ test('model setup basics', async () => {
|
|
|
132
132
|
})
|
|
133
133
|
|
|
134
134
|
test('model setup with default objects', async () => {
|
|
135
|
-
const db2 = monastery('127.0.0.1/monastery', { defaultObjects: true })
|
|
135
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { defaultObjects: true })
|
|
136
136
|
let user = db2.model('user', { fields: {
|
|
137
137
|
name: { type: 'string' },
|
|
138
138
|
pets: [{ type: 'string' }],
|
|
@@ -376,7 +376,7 @@ test('model setup with messages', async () => {
|
|
|
376
376
|
|
|
377
377
|
test('model setup with reserved and invalid rules', async () => {
|
|
378
378
|
// Setup
|
|
379
|
-
const db2 = monastery('127.0.0.1/monastery', { logLevel: 0 })
|
|
379
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { logLevel: 0 })
|
|
380
380
|
let user = db2.model('user-model', {
|
|
381
381
|
fields: {
|
|
382
382
|
name: {
|
package/test/plugin-images.js
CHANGED
|
@@ -7,14 +7,14 @@ const imagePluginFakeOpts = { awsBucket: 'fake', awsRegion: 'fake', awsAccessKey
|
|
|
7
7
|
let db
|
|
8
8
|
afterAll(async () => { db.close() })
|
|
9
9
|
beforeAll(async () => {
|
|
10
|
-
db = monastery('127.0.0.1/monastery', {
|
|
10
|
+
db = monastery.manager('127.0.0.1/monastery', {
|
|
11
11
|
timestamps: false,
|
|
12
12
|
imagePlugin: imagePluginFakeOpts,
|
|
13
13
|
})
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
test('images no initialisation', async () => {
|
|
17
|
-
const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
|
|
17
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { timestamps: false })
|
|
18
18
|
db2.model('company', {
|
|
19
19
|
fields: {
|
|
20
20
|
logo: { type: 'image' },
|
|
@@ -666,7 +666,7 @@ test('images option defaults', async () => {
|
|
|
666
666
|
})
|
|
667
667
|
|
|
668
668
|
test('images options formats & filesizes', async () => {
|
|
669
|
-
const db3 = monastery('127.0.0.1/monastery', {
|
|
669
|
+
const db3 = monastery.manager('127.0.0.1/monastery', {
|
|
670
670
|
timestamps: false,
|
|
671
671
|
imagePlugin: {
|
|
672
672
|
...imagePluginFakeOpts,
|
|
@@ -745,7 +745,7 @@ test('images options formats & filesizes', async () => {
|
|
|
745
745
|
|
|
746
746
|
test('images option getSignedUrls', async () => {
|
|
747
747
|
// latest (2022.02)
|
|
748
|
-
const db3 = monastery('127.0.0.1/monastery', {
|
|
748
|
+
const db3 = monastery.manager('127.0.0.1/monastery', {
|
|
749
749
|
timestamps: false,
|
|
750
750
|
imagePlugin: {
|
|
751
751
|
...imagePluginFakeOpts,
|
|
@@ -802,7 +802,7 @@ test('images option getSignedUrls', async () => {
|
|
|
802
802
|
})
|
|
803
803
|
|
|
804
804
|
test('images options awsAcl, awsBucket, metadata, params, path', async () => {
|
|
805
|
-
const db3 = monastery('127.0.0.1/monastery', {
|
|
805
|
+
const db3 = monastery.manager('127.0.0.1/monastery', {
|
|
806
806
|
timestamps: false,
|
|
807
807
|
imagePlugin: {
|
|
808
808
|
...imagePluginFakeOpts,
|
|
@@ -902,7 +902,7 @@ test('images options awsAcl, awsBucket, metadata, params, path', async () => {
|
|
|
902
902
|
|
|
903
903
|
test('images option depreciations', async () => {
|
|
904
904
|
// testing (filename bucketDir)
|
|
905
|
-
const db3 = monastery('127.0.0.1/monastery', {
|
|
905
|
+
const db3 = monastery.manager('127.0.0.1/monastery', {
|
|
906
906
|
logLevel: 1,
|
|
907
907
|
timestamps: false,
|
|
908
908
|
imagePlugin: {
|
package/test/populate.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const monastery = require('../lib/index.js')
|
|
2
2
|
|
|
3
3
|
let db
|
|
4
|
-
beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
|
|
4
|
+
beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery', { timestamps: false }) })
|
|
5
5
|
afterAll(async () => { db.close() })
|
|
6
6
|
|
|
7
7
|
test('model populate', async () => {
|
package/test/util.js
CHANGED
|
@@ -254,7 +254,7 @@ test('util > isId', async () => {
|
|
|
254
254
|
expect(util.isId({})).toEqual(false)
|
|
255
255
|
expect(util.isId(['5ff50fe955da2c00170de734'])).toEqual(false)
|
|
256
256
|
expect(util.isId('5ff50fe955da2c00170de734')).toEqual(true)
|
|
257
|
-
expect(util.isId(monastery.
|
|
257
|
+
expect(util.isId(monastery.id())).toEqual(true)
|
|
258
258
|
})
|
|
259
259
|
|
|
260
260
|
test('util > isHex24', async () => {
|
|
@@ -265,12 +265,12 @@ test('util > isHex24', async () => {
|
|
|
265
265
|
expect(util.isHex24({})).toEqual(false)
|
|
266
266
|
expect(util.isHex24(['5ff50fe955da2c00170de734'])).toEqual(false)
|
|
267
267
|
expect(util.isHex24('5ff50fe955da2c00170de734')).toEqual(true)
|
|
268
|
-
expect(util.isHex24(monastery.
|
|
268
|
+
expect(util.isHex24(monastery.id())).toEqual(true)
|
|
269
269
|
})
|
|
270
270
|
|
|
271
271
|
|
|
272
272
|
test('util > arrayWithSchema', async () => {
|
|
273
|
-
let res = monastery.
|
|
273
|
+
let res = monastery.arrayWithSchema([{ name: { type: 'string' }}], { minLength: 1 })
|
|
274
274
|
expect(res).toContainEqual({ name: { type: 'string' }})
|
|
275
275
|
expect(res.schema).toEqual({ minLength: 1 })
|
|
276
276
|
})
|
package/test/validate.js
CHANGED
|
@@ -3,7 +3,7 @@ const monastery = require('../lib/index.js')
|
|
|
3
3
|
const Model = require('../lib/model.js')
|
|
4
4
|
|
|
5
5
|
let db
|
|
6
|
-
beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
|
|
6
|
+
beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery', { timestamps: false }) })
|
|
7
7
|
afterAll(async () => { db.close() })
|
|
8
8
|
|
|
9
9
|
test('validation basic errors', async () => {
|
|
@@ -171,7 +171,7 @@ test('validation type any', async () => {
|
|
|
171
171
|
})
|
|
172
172
|
|
|
173
173
|
test('validation schema with reserved and invalid rules', async () => {
|
|
174
|
-
const db2 = monastery('127.0.0.1/monastery', { logLevel: 0 })
|
|
174
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { logLevel: 0 })
|
|
175
175
|
let user = db2.model('user-model', {
|
|
176
176
|
fields: {
|
|
177
177
|
sub: {
|
|
@@ -972,7 +972,7 @@ test('schema options default', async () => {
|
|
|
972
972
|
})
|
|
973
973
|
|
|
974
974
|
test('schema options objects', async () => {
|
|
975
|
-
const db2 = monastery('127.0.0.1/monastery', { nullObjects: true, timestamps: false })
|
|
975
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { nullObjects: true, timestamps: false })
|
|
976
976
|
let user = db2.model('user', {
|
|
977
977
|
fields: {
|
|
978
978
|
location: {
|
|
@@ -998,7 +998,7 @@ test('schema options objects', async () => {
|
|
|
998
998
|
})
|
|
999
999
|
|
|
1000
1000
|
test('validate defaultObjects', async () => {
|
|
1001
|
-
const db2 = monastery('127.0.0.1/monastery', { defaultObjects: true, timestamps: false })
|
|
1001
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { defaultObjects: true, timestamps: false })
|
|
1002
1002
|
// let base = { names: [], animals: { dogs: [] }}
|
|
1003
1003
|
let user = db2.model('user', { fields: {
|
|
1004
1004
|
name: { type: 'string' },
|
|
@@ -1018,7 +1018,7 @@ test('validate defaultObjects', async () => {
|
|
|
1018
1018
|
})
|
|
1019
1019
|
|
|
1020
1020
|
test('validate nullObjects', async () => {
|
|
1021
|
-
const db2 = monastery('127.0.0.1/monastery', { nullObjects: true, timestamps: false })
|
|
1021
|
+
const db2 = monastery.manager('127.0.0.1/monastery', { nullObjects: true, timestamps: false })
|
|
1022
1022
|
let user = db2.model('user', { fields: {
|
|
1023
1023
|
names: [{ type: 'string' }],
|
|
1024
1024
|
animals: {
|
package/test/virtuals.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const monastery = require('../lib/index.js')
|
|
2
2
|
|
|
3
3
|
let db
|
|
4
|
-
beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
|
|
4
|
+
beforeAll(async () => { db = monastery.manager('127.0.0.1/monastery', { timestamps: false }) })
|
|
5
5
|
afterAll(async () => { db.close() })
|
|
6
6
|
|
|
7
7
|
test('virtuals', async () => {
|