monastery 2.2.3 → 3.0.1

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/test/crud.js CHANGED
@@ -1,779 +1,859 @@
1
- module.exports = function(monastery, opendb) {
2
-
3
- test('basic operator calls', async () => {
4
- // Todo: take out and group query/id parsing tests
5
- let db = (await opendb(null)).db
6
- let user = db.model('user', {
7
- fields: {
8
- name: { type: 'string' },
9
- },
10
- })
1
+ // todo: test defaultObejcts=true, milliseconds=true, timestamps=true, nullObjects=true in seperate tests
2
+ const monastery = require('../lib/index.js')
3
+
4
+ let db
5
+ beforeAll(async () => { db = monastery('127.0.0.1/monastery', { timestamps: false }) })
6
+ afterAll(async () => { db.close() })
7
+
8
+ test('insert basics', async () => {
9
+ let db2 = monastery('127.0.0.1/monastery', { timestamps: false })
10
+ let user = db2.model('user', { fields: {
11
+ name: { type: 'string' },
12
+ names: [{ type: 'string' }],
13
+ animals: {
14
+ dog: { type: 'string' },
15
+ dogs: [{ name: { type: 'string' } }],
16
+ },
17
+ }})
18
+
19
+ // pass: insert one
20
+ let inserted = await user.insert({ data: { name: 'Martin Luther' }})
21
+ expect(inserted).toEqual({
22
+ _id: expect.any(Object),
23
+ name: 'Martin Luther',
24
+ })
11
25
 
12
- // Insert one
13
- let inserted = await user.insert({ data: { name: 'Martin Luther' }})
14
- expect(inserted).toEqual({
15
- _id: expect.any(Object),
16
- name: 'Martin Luther'
17
- })
26
+ // pass: insert multiple
27
+ let inserted2 = await user.insert({ data: [{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }]})
28
+ expect(inserted2).toEqual([
29
+ { _id: inserted2[0]._id, name: 'Martin Luther1' },
30
+ { _id: inserted2[1]._id, name: 'Martin Luther2' },
31
+ ])
32
+
33
+ // pass: empty data object
34
+ let inserted3 = await user.insert({ data: {} })
35
+ expect(inserted3).toEqual({
36
+ _id: inserted3._id,
37
+ })
18
38
 
19
- // Insert multiple
20
- let inserted2 = await user.insert({ data: [{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }]})
21
- expect(inserted2).toEqual([
22
- {
23
- _id: expect.any(Object),
24
- name: 'Martin Luther1'
25
- }, {
26
- _id: expect.any(Object),
27
- name: 'Martin Luther2'
28
- }
29
- ])
30
-
31
- // Find (basic match)
32
- let find = await user.find({ query: { name: 'Martin Luther' }})
33
- expect(find[0]).toMatchObject({ name: 'Martin Luther' })
34
-
35
- // Find (empty query)
36
- let find2 = await user.find({ query: {} })
37
- expect(find2.length).toBeGreaterThan(0)
38
-
39
- // Find (id)
40
- let find3 = await user.find({ query: inserted._id })
41
- expect(find3).toEqual({ _id: inserted._id, name: 'Martin Luther' })
42
-
43
- // Find (id string)
44
- let find4 = await user.find({ query: inserted._id.toString() })
45
- expect(find4).toEqual({ _id: inserted._id, name: 'Martin Luther' })
46
-
47
- // Find (id expansion)
48
- let find5 = await user.find(inserted2[0]._id)
49
- expect(find5).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
50
-
51
- // Find (id string expansion)
52
- let find6 = await user.find(inserted2[0]._id.toString())
53
- expect(find6).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
54
-
55
- // Bad ids
56
- let badIdOrQuery = 'Please pass an object or MongoId to options.query'
57
- await expect(user.find()).rejects.toThrow(badIdOrQuery)
58
- await expect(user.find(1)).rejects.toThrow(badIdOrQuery)
59
- await expect(user.find(null)).rejects.toThrow(badIdOrQuery)
60
- await expect(user.find(undefined)).rejects.toThrow(badIdOrQuery)
61
- await expect(user.find({})).rejects.toThrow(badIdOrQuery)
62
- await expect(user.find({ query: null })).rejects.toThrow(badIdOrQuery)
63
- await expect(user.find({ query: undefined })).rejects.toThrow(badIdOrQuery)
64
- await expect(user.find({ query: { _id: undefined }})).rejects.toThrow(badIdOrQuery)
65
-
66
- // Parseable
67
- await expect(user.find('')).resolves.toEqual(null)
68
- await expect(user.find('invalid-id')).resolves.toEqual(null)
69
- await expect(user.find({ query: '' })).resolves.toEqual(null)
70
- await expect(user.find({ query: { _id: '' }})).resolves.toEqual(null)
71
- await expect(user.find({ query: { _id: null }})).resolves.toEqual([]) // should throw error
72
-
73
- // FindOne (query id)
74
- let findOne = await user.findOne({ query: inserted._id })
75
- expect(findOne).toEqual({ _id: inserted._id, name: 'Martin Luther' })
76
-
77
- // Findone (id)
78
- let findOne2 = await user.findOne(inserted2[0]._id)
79
- expect(findOne2).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
80
-
81
- // Findone (id string)
82
- let findOne3 = await user.findOne(inserted2[0]._id.toString())
83
- expect(findOne3).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
84
-
85
- // Remove
86
- let remove = await user.remove({ query: inserted._id })
87
- expect(remove.result).toEqual({ n: 1, ok: 1 })
88
-
89
- db.close()
90
- })
91
-
92
- test('insert defaults', async () => {
93
- let db = (await opendb(null, { defaultObjects: true, serverSelectionTimeoutMS: 2000 })).db
94
- let db2 = (await opendb(null, { useMilliseconds: true, serverSelectionTimeoutMS: 2000 })).db
95
- let user = db.model('user', { fields: {
39
+ // pass: No data object
40
+ let inserted4 = await user.insert({})
41
+ expect(inserted4).toEqual({
42
+ _id: inserted4._id,
43
+ })
44
+
45
+ // pass: No arguments
46
+ let inserted5 = await user.insert()
47
+ expect(inserted5).toEqual({
48
+ _id: inserted5._id,
49
+ })
50
+
51
+ db2.close()
52
+ })
53
+
54
+ test('insert option defaultObjects', async () => {
55
+ let db2 = monastery('127.0.0.1/monastery', { defaultObjects: true, timestamps: false })
56
+ let schema = {
57
+ fields: {
96
58
  name: { type: 'string' },
97
59
  names: [{ type: 'string' }],
98
60
  animals: {
99
61
  dog: { type: 'string' },
100
- dogs: [{ name: { type: 'string' } }]
101
- },
102
- }})
103
- let user2 = db2.model('user2', { fields: {}})
104
-
105
- let inserted = await user.insert({ data: {} })
106
- expect(inserted).toEqual({
107
- _id: inserted._id,
108
- names: [],
109
- animals: { dogs: [] },
110
- createdAt: expect.any(Number),
111
- updatedAt: expect.any(Number)
112
- })
113
-
114
- // No data object
115
- let inserted2 = await user.insert({})
116
- expect(inserted2).toEqual({
117
- _id: inserted2._id,
118
- names: [],
119
- animals: { dogs: [] },
120
- createdAt: expect.any(Number),
121
- updatedAt: expect.any(Number)
122
- })
123
-
124
- // No arguments
125
- let inserted3 = await user.insert()
126
- expect(inserted3).toEqual({
127
- _id: inserted3._id,
128
- names: [],
129
- animals: { dogs: [] },
130
- createdAt: expect.any(Number),
131
- updatedAt: expect.any(Number)
132
- })
133
-
134
- // Milliseconds
135
- let inserted4 = await user2.insert()
136
- expect(inserted4).toEqual({
137
- _id: inserted4._id,
138
- createdAt: expect.any(Number),
139
- updatedAt: expect.any(Number)
140
- })
141
-
142
- db.close()
143
- db2.close()
144
- })
145
-
146
- test('update general', async () => {
147
- let db = (await opendb(null)).db
148
- let user = db.model('user', {
149
- fields: {
150
- name: { type: 'string' },
62
+ dogs: [{ name: { type: 'string' } }],
151
63
  },
152
- })
153
-
154
- // Insert
155
- let inserted = await user.insert({ data: { name: 'Martin Luther' }})
156
- expect(inserted).toEqual({
157
- _id: expect.any(Object),
158
- name: 'Martin Luther'
159
- })
160
-
161
- // Insert multiple
162
- let inserted2 = await user.insert({ data: [{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }]})
163
- expect(inserted2).toEqual([
164
- {
165
- _id: expect.any(Object),
166
- name: 'Martin Luther1'
167
- }, {
168
- _id: expect.any(Object),
169
- name: 'Martin Luther2'
170
- }
171
- ])
172
-
173
- // Update
174
- await expect(user.update({ query: inserted._id, data: { name: 'Martin Luther2' }}))
175
- .resolves.toEqual({ name: 'Martin Luther2' })
176
-
177
- // Update (no/empty data object)
178
- await expect(user.update({ query: inserted._id, data: {}}))
179
- .rejects.toThrow('No valid data passed to user.update({ data: .. })')
180
-
181
- await expect(user.update({ query: inserted._id }))
182
- .rejects.toThrow('Please pass an update operator to user.update(), e.g. data, $unset, etc')
183
-
184
- // Update multiple
185
- await user.update({
186
- query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }},
187
- data: { name: 'Martin Luther3' },
188
- multi: true
189
- })
190
- let findUpdated2 = await user.find({
191
- query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }}
192
- })
193
- expect(findUpdated2).toEqual([
194
- {
195
- _id: expect.any(Object),
196
- name: 'Martin Luther3'
197
- }, {
198
- _id: expect.any(Object),
199
- name: 'Martin Luther3'
200
- }
201
- ])
64
+ },
65
+ }
66
+ let user1 = db.model('user', schema)
67
+ let user2 = db2.model('user', schema)
68
+
69
+ // defaultObjects off (default)
70
+ let inserted1 = await user1.insert({ data: {} })
71
+ expect(inserted1).toEqual({
72
+ _id: inserted1._id,
73
+ })
202
74
 
203
- // Upsert
204
- let newId = db.id()
205
- await expect(user.update({ query: newId, data: { name: 'Martin Luther3' }, upsert: true }))
206
- .resolves.toEqual({ _id: newId, name: 'Martin Luther3' }) // inserted
75
+ // defaultObjects on
76
+ let inserted2 = await user2.insert({ data: {} })
77
+ expect(inserted2).toEqual({
78
+ _id: inserted2._id,
79
+ names: [],
80
+ animals: { dogs: [] },
81
+ })
82
+ db2.close()
83
+ })
207
84
 
208
- await expect(user.update({ query: inserted._id, data: { name: 'Martin Luther4' }, upsert: true }))
209
- .resolves.toEqual({ name: 'Martin Luther4' }) // updated
85
+ test('insert option timestamps', async () => {
86
+ let db2 = monastery('127.0.0.1/monastery', { timestamps: true })
87
+ let schema = {
88
+ fields: {
89
+ name: { type: 'string' },
90
+ },
91
+ }
92
+ let user1 = db.model('user', schema)
93
+ let user2 = db2.model('user', schema)
94
+
95
+ // timestamps off (default)
96
+ let inserted1 = await user1.insert({ data: {} })
97
+ expect(inserted1).toEqual({
98
+ _id: inserted1._id,
99
+ })
210
100
 
211
- db.close()
101
+ // timestamps on
102
+ let inserted2 = await user2.insert({ data: {} })
103
+ expect(inserted2).toEqual({
104
+ _id: inserted2._id,
105
+ createdAt: expect.any(Number),
106
+ updatedAt: expect.any(Number),
212
107
  })
108
+ db2.close()
109
+ })
213
110
 
214
- test('update general max', async () => {
215
- let db = (await opendb(null)).db
216
- let user = db.model('user', {
217
- fields: {
218
- name: { type: 'string' },
219
- active: { type: 'boolean' },
220
- },
221
- })
111
+ test('insert id casting', async () => {
112
+ db.model('company', {
113
+ fields: {
114
+ name: { type: 'string' },
115
+ },
116
+ })
117
+ let user = db.model('user', { fields: {
118
+ randomId: { type: 'id' },
119
+ company: { model: 'company' },
120
+ companies: [{ model: 'company' }],
121
+ }})
122
+
123
+ let id = '5edf17ff7e2d5020913f98cc'
124
+ let inserted = await user.insert({ data: { randomId: id, company: id, companies: [id] } })
125
+
126
+ expect(inserted).toEqual({
127
+ _id: inserted._id,
128
+ randomId: db.id(id),
129
+ company: db.id(id),
130
+ companies: [db.id(id)],
131
+ })
132
+ })
222
133
 
223
- // Insert
224
- let inserted = await user.insert({ data: { name: 'Martin Luther' }})
134
+ test('find defaults', async () => {
135
+ // Todo: take out and group query/id parsing tests
136
+ let user = db.model('user-find', {
137
+ fields: {
138
+ name: { type: 'string' },
139
+ },
140
+ })
225
141
 
226
- expect(inserted).toEqual({
227
- _id: expect.any(Object),
228
- name: 'Martin Luther',
229
- })
142
+ // Insert one
143
+ let inserted = await user._insert({ name: 'Martin Luther' })
144
+ // Insert multiple
145
+ let inserted2 = await user._insert([{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }])
146
+
147
+ // Find (basic match)
148
+ let find = await user.find({ query: { name: 'Martin Luther' }})
149
+ expect(find[0]).toEqual({ _id: find[0]._id, name: 'Martin Luther' }) // no timestamps
150
+
151
+ // Find (empty query)
152
+ let find2 = await user.find({ query: {} })
153
+ expect(find2.length).toBeGreaterThan(0)
154
+
155
+ // Find (id)
156
+ let find3 = await user.find({ query: inserted._id })
157
+ expect(find3).toEqual({ _id: inserted._id, name: 'Martin Luther' })
158
+
159
+ // Find (id string)
160
+ let find4 = await user.find({ query: inserted._id.toString() })
161
+ expect(find4).toEqual({ _id: inserted._id, name: 'Martin Luther' })
162
+
163
+ // Find (id expansion)
164
+ let find5 = await user.find(inserted2[0]._id)
165
+ expect(find5).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
166
+
167
+ // Find (id string expansion)
168
+ let find6 = await user.find(inserted2[0]._id.toString())
169
+ expect(find6).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
170
+
171
+ // Bad ids
172
+ let badIdOrQuery = 'Please pass an object or MongoId to options.query'
173
+ await expect(user.find()).rejects.toThrow(badIdOrQuery)
174
+ await expect(user.find(1)).rejects.toThrow(badIdOrQuery)
175
+ await expect(user.find(null)).rejects.toThrow(badIdOrQuery)
176
+ await expect(user.find(undefined)).rejects.toThrow(badIdOrQuery)
177
+ await expect(user.find({})).rejects.toThrow(badIdOrQuery)
178
+ await expect(user.find({ query: null })).rejects.toThrow(badIdOrQuery)
179
+ await expect(user.find({ query: undefined })).rejects.toThrow(badIdOrQuery)
180
+ await expect(user.find({ query: { _id: undefined }})).rejects.toThrow(badIdOrQuery)
181
+
182
+ // Parseable
183
+ await expect(user.find('')).resolves.toEqual(null)
184
+ await expect(user.find('invalid-id')).resolves.toEqual(null)
185
+ await expect(user.find({ query: '' })).resolves.toEqual(null)
186
+ await expect(user.find({ query: { _id: '' }})).resolves.toEqual(null)
187
+ await expect(user.find({ query: { _id: null }})).resolves.toEqual([]) // should throw error
188
+
189
+ // FindOne (query id)
190
+ let findOne = await user.findOne({ query: inserted._id })
191
+ expect(findOne).toEqual({ _id: inserted._id, name: 'Martin Luther' })
192
+
193
+ // Findone (id)
194
+ let findOne2 = await user.findOne(inserted2[0]._id)
195
+ expect(findOne2).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
196
+
197
+ // Findone (id string)
198
+ let findOne3 = await user.findOne(inserted2[0]._id.toString())
199
+ expect(findOne3).toEqual({ _id: inserted2[0]._id, name: 'Martin Luther1' })
200
+ })
201
+
202
+ test('find default field population', async () => {
203
+ db.model('user', {
204
+ fields: {
205
+ name: { type: 'string', default: 'Martin Luther' },
206
+ addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
207
+ address: { country: { type: 'string', default: 'Germany' }},
208
+ pet: { dog: { model: 'dog' }},
209
+ pets: { dog: [{ model: 'dog' }]},
210
+ dogs: [{ model: 'dog' }], // virtual association
211
+ },
212
+ })
213
+ db.model('dog', {
214
+ fields: {
215
+ name: { type: 'string', default: 'Scruff' },
216
+ user: { model: 'user' },
217
+ },
218
+ })
230
219
 
231
- let updatedUser1 = await user.update({
232
- query: { _id: inserted._id },
233
- data: { name: 'Martin' },
234
- blacklist: ['active'],
235
- })
220
+ // Default field doesn't override null
221
+ let nulldoc1 = await db.dog.insert({ data: { name: null }})
222
+ let nullfind1 = await db.dog.findOne({ query: nulldoc1._id })
223
+ expect(nullfind1).toEqual({ _id: nulldoc1._id, name: null })
224
+
225
+ // Default field doesn't override empty string
226
+ let nulldoc2 = await db.dog.insert({ data: { name: '' }})
227
+ let nullfind2 = await db.dog.findOne({ query: nulldoc2._id })
228
+ expect(nullfind2).toEqual({ _id: nulldoc2._id, name: '' })
229
+
230
+ // Default field overrides undefined
231
+ let nulldoc3 = await db.dog.insert({ data: { name: undefined }})
232
+ let nullfind3 = await db.dog.findOne({ query: nulldoc3._id })
233
+ expect(nullfind3).toEqual({ _id: nullfind3._id, name: 'Scruff' })
234
+
235
+ // Default field population test
236
+ // Note that addresses.1.country shouldn't be overridden
237
+ // Insert documents (without defaults)
238
+ let dog1 = await db.dog._insert({})
239
+ let dog2 = await db.dog._insert({})
240
+ let user1 = await db.user._insert({
241
+ addresses: [
242
+ { city: 'Frankfurt' },
243
+ { city: 'Christchurch', country: 'New Zealand' },
244
+ ],
245
+ pet: { dog: dog1._id },
246
+ pets: { dog: [dog1._id, dog2._id]},
247
+ })
248
+ await db.dog._update(dog1._id, { $set: { user: user1._id }})
249
+
250
+ let find1 = await db.user.findOne({
251
+ query: user1._id,
252
+ populate: ['pet.dog', 'pets.dog', {
253
+ from: 'dog',
254
+ localField: '_id',
255
+ foreignField: 'user',
256
+ as: 'dogs',
257
+ }],
258
+ })
259
+ expect(find1).toEqual({
260
+ _id: user1._id,
261
+ name: 'Martin Luther',
262
+ addresses: [
263
+ { city: 'Frankfurt', country: 'Germany' },
264
+ { city: 'Christchurch', country: 'New Zealand' },
265
+ ],
266
+ address: { country: 'Germany' },
267
+ pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
268
+ pets: {
269
+ dog: [
270
+ { _id: dog1._id, name: 'Scruff', user: user1._id },
271
+ { _id: dog2._id, name: 'Scruff' },
272
+ ],
273
+ },
274
+ dogs: [{ _id: dog1._id, name: 'Scruff', user: user1._id }],
275
+ })
276
+ })
277
+
278
+ test('find default field blacklisted', async () => {
279
+ db.model('user', {
280
+ fields: {
281
+ name: { type: 'string', default: 'Martin Luther' },
282
+ addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
283
+ address: { country: { type: 'string', default: 'Germany' }},
284
+ pet: { dog: { model: 'dog' }},
285
+ pets: { dog: [{ model: 'dog' }]},
286
+ dogs: [{ model: 'dog' }], // virtual association
287
+ },
288
+ })
289
+ db.model('dog', {
290
+ fields: {
291
+ age: { type: 'number', default: 12 },
292
+ name: { type: 'string', default: 'Scruff' },
293
+ user: { model: 'user' },
294
+ },
295
+ findBL: ['age'],
296
+ })
297
+ let dog1 = await db.dog._insert({})
298
+ let dog2 = await db.dog._insert({})
299
+ let user1 = await db.user._insert({
300
+ addresses: [
301
+ { city: 'Frankfurt' },
302
+ { city: 'Christchurch', country: 'New Zealand' },
303
+ ],
304
+ pet: { dog: dog1._id },
305
+ pets: { dog: [dog1._id, dog2._id]},
306
+ })
307
+ await db.dog._update(dog1._id, { $set: { user: user1._id }})
308
+
309
+ // Blacklisted direct/populated default fields (should be removed)
310
+ let find2 = await db.user.findOne({
311
+ query: user1._id,
312
+ populate: [
313
+ 'pet.dog',
314
+ 'pets.dog',
315
+ {
316
+ from: 'dog',
317
+ localField: '_id',
318
+ foreignField: 'user',
319
+ as: 'dogs',
320
+ },
321
+ ],
322
+ blacklist: ['address', 'addresses.country', 'pets.dog.name', 'dogs.name'],
323
+ // ^ great test (address should cancel addresses if not stopping at the .)
324
+ })
325
+ expect(find2).toEqual({
326
+ _id: user1._id,
327
+ name: 'Martin Luther',
328
+ addresses: [{ city: 'Frankfurt' }, { city: 'Christchurch' }],
329
+ pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
330
+ dogs: [{ _id: dog1._id, user: user1._id }],
331
+ pets: {
332
+ dog: [
333
+ { _id: dog1._id, user: user1._id }, //, age, name
334
+ { _id: dog2._id }, //, age, name
335
+ ],
336
+ },
337
+ })
338
+ })
236
339
 
237
- expect(updatedUser1).toEqual({ name: 'Martin' })
340
+ test('update general', async () => {
341
+ let user = db.model('user', {
342
+ fields: {
343
+ name: { type: 'string' },
344
+ },
345
+ })
238
346
 
239
- let updatedUser2 = await user._update(
240
- { _id: db.id(inserted._id) },
241
- { $set: { name: 'Martin2' }},
242
- )
347
+ // Insert
348
+ let inserted = await user.insert({ data: { name: 'Martin Luther' }})
349
+ expect(inserted).toEqual({
350
+ _id: expect.any(Object),
351
+ name: 'Martin Luther',
352
+ })
243
353
 
354
+ // Insert multiple
355
+ let inserted2 = await user.insert({ data: [{ name: 'Martin Luther1' }, { name: 'Martin Luther2' }]})
356
+ expect(inserted2).toEqual([
357
+ {
358
+ _id: expect.any(Object),
359
+ name: 'Martin Luther1',
360
+ }, {
361
+ _id: expect.any(Object),
362
+ name: 'Martin Luther2',
363
+ },
364
+ ])
365
+
366
+ // Update
367
+ await expect(user.update({ query: inserted._id, data: { name: 'Martin Luther2' }}))
368
+ .resolves.toEqual({ name: 'Martin Luther2' })
369
+
370
+ // Update (no/empty data object)
371
+ await expect(user.update({ query: inserted._id, data: {}}))
372
+ .rejects.toThrow('No valid data passed to user.update({ data: .. })')
373
+
374
+ await expect(user.update({ query: inserted._id }))
375
+ .rejects.toThrow('Please pass an update operator to user.update(), e.g. data, $unset, etc')
376
+
377
+ // Update multiple
378
+ await user.update({
379
+ query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }},
380
+ data: { name: 'Martin Luther3' },
381
+ multi: true,
382
+ })
383
+ let findUpdated2 = await user.find({
384
+ query: { _id: { $in: [inserted2[0]._id, inserted2[1]._id] }},
385
+ })
386
+ expect(findUpdated2).toEqual([
387
+ {
388
+ _id: expect.any(Object),
389
+ name: 'Martin Luther3',
390
+ }, {
391
+ _id: expect.any(Object),
392
+ name: 'Martin Luther3',
393
+ },
394
+ ])
395
+
396
+ // Upsert
397
+ let newId = db.id()
398
+ await expect(user.update({ query: newId, data: { name: 'Martin Luther3' }, upsert: true }))
399
+ .resolves.toEqual({ _id: newId, name: 'Martin Luther3' }) // inserted
400
+
401
+ await expect(user.update({ query: inserted._id, data: { name: 'Martin Luther4' }, upsert: true }))
402
+ .resolves.toEqual({ name: 'Martin Luther4' }) // updated
403
+ })
404
+
405
+ test('update defaults', async () => {
406
+ const db2 = monastery('127.0.0.1/monastery', { useMilliseconds: true })
407
+ let user = db2.model('user', {
408
+ fields: {
409
+ name: { type: 'string' },
410
+ },
411
+ })
412
+ let inserted = await user.insert({
413
+ data: {},
414
+ })
415
+ expect(inserted).toEqual({
416
+ _id: inserted._id,
417
+ createdAt: expect.any(Number),
418
+ updatedAt: expect.any(Number),
419
+ })
420
+ // Default field
421
+ // await util.wait(1000)
422
+ let updated = await user.update({
423
+ query: inserted._id,
424
+ data: { name: 'Bruce' },
425
+ })
426
+ expect(updated).toEqual({
427
+ name: 'Bruce',
428
+ updatedAt: expect.any(Number),
429
+ })
430
+ expect(updated.updatedAt && updated.updatedAt != inserted.updatedAt).toEqual(true)
244
431
 
245
- expect(updatedUser2).toEqual({ n: 1, nModified: 1, ok: 1 })
432
+ // Empty data (still contains updatedAt)
433
+ let updated2 = await user.update({
434
+ query: inserted._id,
435
+ data: {},
436
+ })
437
+ expect(updated2).toEqual({
438
+ updatedAt: expect.any(Number),
439
+ })
246
440
 
247
- // Mongo connected?
248
- // Try native updates
441
+ // Empty data (with no timestamps)
442
+ await expect(user.update({
443
+ query: inserted._id,
444
+ data: {},
445
+ timestamps: false,
446
+ })).rejects.toThrow('No valid data passed to user.update({ data: .. })')
447
+
448
+ // UpdatedAt override (wont work)
449
+ let updated4 = await user.update({
450
+ query: inserted._id,
451
+ data: { updatedAt: 1 },
452
+ })
453
+ expect(updated4.updatedAt > 1).toEqual(true)
249
454
 
250
- db.close()
455
+ // UpdatedAt override
456
+ let updated5 = await user.update({
457
+ query: inserted._id,
458
+ data: { updatedAt: 1 },
459
+ timestamps: false,
460
+ })
461
+ expect(updated5.updatedAt).toEqual(1)
462
+ db2.close()
463
+ })
464
+
465
+ test('update operators', async () => {
466
+ let user = db.model('userOperators', {
467
+ fields: {
468
+ name: { type: 'string', minLength: 5 },
469
+ age: { type: 'number' },
470
+ },
471
+ beforeValidate: [(data, next) => { beforeValidateHookCalled = true; next() }],
251
472
  })
252
473
 
253
- test('update defaults', async () => {
254
- let db = (await opendb(null, { useMilliseconds: true, serverSelectionTimeoutMS: 2000 })).db
255
- let user = db.model('user', {
256
- fields: {
257
- name: { type: 'string' }
258
- }
259
- })
260
- let inserted = await user.insert({
261
- data: {}
262
- })
263
- expect(inserted).toEqual({
264
- _id: inserted._id,
265
- createdAt: expect.any(Number),
266
- updatedAt: expect.any(Number)
267
- })
268
-
269
- // Default field
270
- let updated = await user.update({
271
- query: inserted._id,
272
- data: { name: 'Bruce' }
273
- })
274
- expect(updated).toEqual({
275
- name: 'Bruce',
276
- updatedAt: expect.any(Number)
277
- })
278
- expect(updated.updatedAt && updated.updatedAt != inserted.updatedAt).toEqual(true)
279
-
280
- // Empty data (still contains updatedAt)
281
- let updated2 = await user.update({
282
- query: inserted._id,
283
- data: {}
284
- })
285
- expect(updated2).toEqual({
286
- updatedAt: expect.any(Number)
287
- })
288
-
289
- // Empty data (with no timestamps)
290
- await expect(user.update({
291
- query: inserted._id,
292
- data: {},
293
- timestamps: false
294
- })).rejects.toThrow('No valid data passed to user.update({ data: .. })')
295
-
296
- // UpdatedAt override (wont work)
297
- let updated4 = await user.update({
298
- query: inserted._id,
299
- data: { updatedAt: 1 }
300
- })
301
- expect(updated4.updatedAt > 1).toEqual(true)
302
-
303
- // UpdatedAt override
304
- let updated5 = await user.update({
305
- query: inserted._id,
306
- data: { updatedAt: 1 },
307
- timestamps: false
308
- })
309
- expect(updated5.updatedAt).toEqual(1)
310
-
311
- db.close()
312
- })
313
-
314
- test('update operators', async () => {
315
- let db = (await opendb(null)).db
316
- let user = db.model('userOperators', {
317
- fields: {
318
- name: { type: 'string', minLength: 5 },
319
- age: { type: 'number' },
320
- },
321
- beforeValidate: [(data, next) => { beforeValidateHookCalled = true; next() }]
322
- })
474
+ let inserted = await user.insert({
475
+ data: { name: 'Bruce', age: 12 },
476
+ })
323
477
 
324
- let inserted = await user.insert({
325
- data: { name: 'Bruce', age: 12 }
326
- })
478
+ // No data object, but has another update operators
479
+ await expect(user.update({ query: inserted._id, $set: { name: 'bruce' }}))
480
+ .resolves.toEqual({ name: 'bruce' })
327
481
 
328
- // No data object, but has another update operators
329
- await expect(user.update({ query: inserted._id, $set: { name: 'bruce' }}))
330
- .resolves.toEqual({ name: 'bruce' })
482
+ // Mixing data and $set, and $set skips validation (minLength)
483
+ await expect(user.update({ query: inserted._id, data: { name: 'bruce2', age: 12 }, $set: { name: 'john' }}))
484
+ .resolves.toEqual({ age: 12, name: 'john' })
331
485
 
332
- // Mixing data and $set, and $set skips validation (minLength)
333
- await expect(user.update({ query: inserted._id, data: { name: 'bruce2', age: 12 }, $set: { name: 'john' }}))
334
- .resolves.toEqual({ age: 12, name: 'john' })
486
+ // Two operators
487
+ await user.update({ query: inserted._id, $set: { name: 'john' }, $unset: { age: 1 }})
488
+ await expect(user.findOne({ query: inserted._id })).resolves.toEqual({
489
+ _id: expect.any(Object),
490
+ name: 'john',
491
+ })
335
492
 
336
- // Two operators
337
- await user.update({ query: inserted._id, $set: { name: 'john' }, $unset: { age: 1 }})
338
- await expect(user.findOne({ query: inserted._id })).resolves.toEqual({
339
- _id: expect.any(Object),
340
- name: 'john',
341
- })
342
-
343
- // $pull on a non array (also gets passed no valid data check)
344
- await expect(user.update({ query: inserted._id, $pull: { name: 'bruce' }}))
345
- .rejects.toThrow('Cannot apply $pull to a non-array value')
346
-
347
- // Non-data operators don't call beforeValidate
348
- var beforeValidateHookCalled = false
349
- await user.update({ query: inserted._id, data: { name: 'bruce' }})
350
- expect(beforeValidateHookCalled).toEqual(true)
351
- beforeValidateHookCalled = false
352
- await user.update({ query: inserted._id, $set: { name: 'bruce' }})
353
- expect(beforeValidateHookCalled).toEqual(false)
354
-
355
- db.close()
356
- })
357
-
358
- test('update mixing formData', async() => {
359
- // Mixing data
360
- let db = (await opendb(null)).db
361
- let consignment = db.model('consignment', {
362
- fields: {
363
- specialInstructions: [{
364
- text: { type: 'string' },
365
- createdAt: { type: 'date' },
366
- updatedByName: { type: 'string' },
367
- importance: { type: 'string' },
368
- }],
369
- },
370
- })
371
- let inserted = await consignment.insert({
372
- data: {
373
- specialInstructions: [{
374
- text: 'filler',
375
- createdAt: 1653601752472,
376
- updatedByName: 'Paul',
377
- importance: 'low'
378
- }]
379
- }
380
- })
381
- let specialInstructions = [
382
- {
383
- text: 'POD added by driver',
384
- createdAt: 1653603212886,
385
- updatedByName: 'Paul Driver 3',
386
- importance: 'low'
387
- }, {
493
+ // $pull on a non array (also gets passed no valid data check)
494
+ await expect(user.update({ query: inserted._id, $pull: { name: 'bruce' }}))
495
+ .rejects.toThrow('Cannot apply $pull to a non-array value')
496
+
497
+ // Non-data operators don't call beforeValidate
498
+ var beforeValidateHookCalled = false
499
+ await user.update({ query: inserted._id, data: { name: 'bruce' }})
500
+ expect(beforeValidateHookCalled).toEqual(true)
501
+ beforeValidateHookCalled = false
502
+ await user.update({ query: inserted._id, $set: { name: 'bruce' }})
503
+ expect(beforeValidateHookCalled).toEqual(false)
504
+ })
505
+
506
+ test('update mixing formData', async() => {
507
+ // Mixing data
508
+ let consignment = db.model('consignment', {
509
+ fields: {
510
+ specialInstructions: [{
511
+ text: { type: 'string' },
512
+ createdAt: { type: 'date' },
513
+ updatedByName: { type: 'string' },
514
+ importance: { type: 'string' },
515
+ }],
516
+ },
517
+ })
518
+ let inserted = await consignment.insert({
519
+ data: {
520
+ specialInstructions: [{
388
521
  text: 'filler',
389
522
  createdAt: 1653601752472,
390
523
  updatedByName: 'Paul',
391
- importance: 'low'
392
- }
393
- ]
394
- // Key order maintained (not always guaranteed in browsers)
395
- await consignment.update({
396
- query: inserted._id,
397
- data: {
398
- 'specialInstructions[0][text]': 'filler',
399
- 'specialInstructions[0][createdAt]': 1653601752472,
400
- 'specialInstructions[0][updatedByName]': 'Paul',
401
- 'specialInstructions[0][importance]': 'low',
402
- specialInstructions: specialInstructions.map(o => ({ ...o })),
403
- }
404
- })
405
- await expect(consignment.findOne({ query: inserted._id })).resolves.toEqual({
406
- _id: expect.any(Object),
407
- specialInstructions: specialInstructions,
408
- })
409
-
410
- // Key order maintained (not always guaranteed in browsers)
411
- await consignment.update({
412
- query: inserted._id,
413
- data: {
414
- specialInstructions: specialInstructions.map(o => ({ ...o })),
415
- 'specialInstructions[0][text]': 'filler',
416
- 'specialInstructions[0][createdAt]': 1653601752472,
417
- 'specialInstructions[0][updatedByName]': 'Paul',
418
- 'specialInstructions[0][importance]': 'low',
419
- }
420
- })
421
- await expect(consignment.findOne({ query: inserted._id })).resolves.toEqual({
422
- _id: expect.any(Object),
423
- specialInstructions: [specialInstructions[1], specialInstructions[1]],
424
- })
425
-
426
- db.close()
427
- })
428
-
429
- test('insert with id casting', async () => {
430
- let db = (await opendb(null)).db
431
- db.model('company', { fields: {
432
- name: { type: 'string' }
433
- }})
434
- let user = db.model('user', { fields: {
435
- randomId: { type: 'id' },
436
- company: { model: 'company' },
437
- companies: [{ model: 'company' }]
438
- }})
439
-
440
- let id = '5edf17ff7e2d5020913f98cc'
441
- let inserted = await user.insert({ data: { randomId: id, company: id, companies: [id] } })
442
-
443
- expect(inserted).toEqual({
444
- _id: inserted._id,
445
- randomId: db.id(id),
446
- company: db.id(id),
447
- companies: [db.id(id)]
448
- })
449
-
450
- db.close()
451
- })
452
-
453
- test('find default field population', async () => {
454
- let db = (await opendb(null)).db
455
- db.model('user', {
456
- fields: {
457
- name: { type: 'string', default: 'Martin Luther' },
458
- addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
459
- address: { country: { type: 'string', default: 'Germany' }},
460
- pet: { dog: { model: 'dog' }},
461
- pets: { dog: [{ model: 'dog' }]},
462
- dogs: [{ model: 'dog' }], // virtual association
463
- }
464
- })
465
- db.model('dog', {
466
- fields: {
467
- name: { type: 'string', default: 'Scruff' },
468
- user: { model: 'user' }
469
- }
470
- })
471
-
472
- // Default field doesn't override null
473
- let nulldoc1 = await db.dog.insert({ data: { name: null }})
474
- let nullfind1 = await db.dog.findOne({ query: nulldoc1._id })
475
- expect(nullfind1).toEqual({ _id: nulldoc1._id, name: null })
476
-
477
- // Default field doesn't override empty string
478
- let nulldoc2 = await db.dog.insert({ data: { name: '' }})
479
- let nullfind2 = await db.dog.findOne({ query: nulldoc2._id })
480
- expect(nullfind2).toEqual({ _id: nulldoc2._id, name: '' })
481
-
482
- // Default field overrides undefined
483
- let nulldoc3 = await db.dog.insert({ data: { name: undefined }})
484
- let nullfind3 = await db.dog.findOne({ query: nulldoc3._id })
485
- expect(nullfind3).toEqual({ _id: nullfind3._id, name: 'Scruff' })
486
-
487
- // Default field population test
488
- // Note that addresses.1.country shouldn't be overridden
489
- // Insert documents (without defaults)
490
- let dog1 = await db.dog._insert({})
491
- let dog2 = await db.dog._insert({})
492
- let user1 = await db.user._insert({
493
- addresses: [
494
- { city: 'Frankfurt' },
495
- { city: 'Christchurch', country: 'New Zealand' }
496
- ],
497
- pet: { dog: dog1._id },
498
- pets: { dog: [dog1._id, dog2._id]},
499
- })
500
- await db.dog._update(dog1._id, { $set: { user: user1._id }})
501
-
502
- let find1 = await db.user.findOne({
503
- query: user1._id,
504
- populate: ['pet.dog', 'pets.dog', {
505
- from: 'dog',
506
- localField: '_id',
507
- foreignField: 'user',
508
- as: 'dogs'
509
- }]
510
- })
511
- expect(find1).toEqual({
512
- _id: user1._id,
513
- name: 'Martin Luther',
514
- addresses: [
515
- { city: 'Frankfurt', country: 'Germany' },
516
- { city: 'Christchurch', country: 'New Zealand' }
517
- ],
518
- address: { country: 'Germany' },
519
- pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
520
- pets: {
521
- dog: [
522
- { _id: dog1._id, name: 'Scruff', user: user1._id },
523
- { _id: dog2._id, name: 'Scruff' },
524
- ]
525
- },
526
- dogs: [{ _id: dog1._id, name: 'Scruff', user: user1._id }]
527
- })
528
-
529
- db.close()
530
- })
531
-
532
- test('find default field blacklisted', async () => {
533
- let db = (await opendb(null)).db
534
- db.model('user', {
535
- fields: {
536
- name: { type: 'string', default: 'Martin Luther' },
537
- addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
538
- address: { country: { type: 'string', default: 'Germany' }},
539
- pet: { dog: { model: 'dog' }},
540
- pets: { dog: [{ model: 'dog' }]},
541
- dogs: [{ model: 'dog' }], // virtual association
542
- }
543
- })
544
- db.model('dog', {
545
- fields: {
546
- age: { type: 'number', default: 12 },
547
- name: { type: 'string', default: 'Scruff' },
548
- user: { model: 'user' }
549
- },
550
- findBL: ['age']
551
- })
552
- let dog1 = await db.dog._insert({})
553
- let dog2 = await db.dog._insert({})
554
- let user1 = await db.user._insert({
555
- addresses: [
556
- { city: 'Frankfurt' },
557
- { city: 'Christchurch', country: 'New Zealand' }
558
- ],
559
- pet: { dog: dog1._id },
560
- pets: { dog: [dog1._id, dog2._id]},
561
- })
562
- await db.dog._update(dog1._id, { $set: { user: user1._id }})
563
-
564
- // Blacklisted direct/populated default fields (should be removed)
565
- let find2 = await db.user.findOne({
566
- query: user1._id,
567
- populate: [
568
- 'pet.dog',
569
- 'pets.dog',
570
- {
571
- from: 'dog',
572
- localField: '_id',
573
- foreignField: 'user',
574
- as: 'dogs',
575
- }
576
- ],
577
- blacklist: ['address', 'addresses.country', 'pets.dog.name', 'dogs.name'],
578
- // ^ great test (address should cancel addresses if not stopping at the .)
579
- })
580
- expect(find2).toEqual({
581
- _id: user1._id,
582
- name: 'Martin Luther',
583
- addresses: [{ city: 'Frankfurt' }, { city: 'Christchurch' }],
584
- pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
585
- dogs: [{ _id: dog1._id, user: user1._id }],
586
- pets: {
587
- dog: [
588
- { _id: dog1._id, user: user1._id, /*age, name*/ },
589
- { _id: dog2._id, /*age, name*/ },
590
- ]
591
- },
592
- })
593
-
594
- db.close()
524
+ importance: 'low',
525
+ }],
526
+ },
527
+ })
528
+ let specialInstructions = [
529
+ {
530
+ text: 'POD added by driver',
531
+ createdAt: 1653603212886,
532
+ updatedByName: 'Paul Driver 3',
533
+ importance: 'low',
534
+ }, {
535
+ text: 'filler',
536
+ createdAt: 1653601752472,
537
+ updatedByName: 'Paul',
538
+ importance: 'low',
539
+ },
540
+ ]
541
+ // Key order maintained (not always guaranteed in browsers)
542
+ await consignment.update({
543
+ query: inserted._id,
544
+ data: {
545
+ 'specialInstructions[0][text]': 'filler',
546
+ 'specialInstructions[0][createdAt]': 1653601752472,
547
+ 'specialInstructions[0][updatedByName]': 'Paul',
548
+ 'specialInstructions[0][importance]': 'low',
549
+ specialInstructions: specialInstructions.map(o => ({ ...o })),
550
+ },
551
+ })
552
+ await expect(consignment.findOne({ query: inserted._id })).resolves.toEqual({
553
+ _id: expect.any(Object),
554
+ specialInstructions: specialInstructions,
595
555
  })
596
556
 
597
- test('findOneAndUpdate general', async () => {
598
- // todo: test all findOneAndUpdate options (e.g. array population)
599
- // todo: test find & update hooks
600
- let db = (await opendb(null)).db
601
- let dog = db.model('dog', {
602
- fields: {
603
- name: { type: 'string', default: 'Scruff' },
604
- }
605
- })
606
- let user = db.model('user', {
607
- fields: {
608
- name: { type: 'string', default: 'Martin' },
609
- dog: { model: 'dog' },
610
- }
611
- })
612
-
613
- // Returns omitted field after update, i.e. dog
614
- let dog1 = await dog.insert({ data: {} })
615
- let user1 = await user.insert({ data: { dog: dog1._id }})
616
- expect(await user.findOneAndUpdate({ query: { _id: user1._id }, data: { name: 'Martin2' }})).toEqual({
617
- _id: user1._id,
618
- name: 'Martin2',
619
- dog: dog1._id,
620
- })
621
-
622
- // Returns omitted field requiring population after update, i.e. dog
623
- expect(await user.findOneAndUpdate({
624
- query: { _id: user1._id },
625
- data: { name: 'Martin2' },
626
- populate: ['dog'],
627
- })).toEqual({
628
- _id: user1._id,
629
- name: 'Martin2',
630
- dog: {
631
- _id: dog1._id,
632
- name: 'Scruff'
633
- },
634
- })
635
-
636
- // Error finding document to update
637
- expect(await user.findOneAndUpdate({
638
- query: { _id: db.id() },
639
- data: { name: 'Martin2' },
640
- })).toEqual(null)
557
+ // Key order maintained (not always guaranteed in browsers)
558
+ await consignment.update({
559
+ query: inserted._id,
560
+ data: {
561
+ specialInstructions: specialInstructions.map(o => ({ ...o })),
562
+ 'specialInstructions[0][text]': 'filler',
563
+ 'specialInstructions[0][createdAt]': 1653601752472,
564
+ 'specialInstructions[0][updatedByName]': 'Paul',
565
+ 'specialInstructions[0][importance]': 'low',
566
+ },
567
+ })
568
+ await expect(consignment.findOne({ query: inserted._id })).resolves.toEqual({
569
+ _id: expect.any(Object),
570
+ specialInstructions: [specialInstructions[1], specialInstructions[1]],
571
+ })
572
+ })
573
+
574
+ test('findOneAndUpdate general', async () => {
575
+ // todo: test all findOneAndUpdate options (e.g. array population)
576
+ // todo: test find & update hooks
577
+ let dog = db.model('dog', {
578
+ fields: {
579
+ name: { type: 'string', default: 'Scruff' },
580
+ },
581
+ })
582
+ let user = db.model('user', {
583
+ fields: {
584
+ name: { type: 'string', default: 'Martin' },
585
+ dog: { model: 'dog' },
586
+ },
587
+ })
641
588
 
642
- // Error finding document to update (populate)
643
- expect(await user.findOneAndUpdate({
644
- query: { _id: db.id() },
645
- data: { name: 'Martin2' },
646
- populate: ['dog'],
647
- })).toEqual(null)
589
+ // Returns omitted field after update, i.e. dog
590
+ let dog1 = await dog.insert({ data: {} })
591
+ let user1 = await user.insert({ data: { dog: dog1._id }})
592
+ expect(await user.findOneAndUpdate({ query: { _id: user1._id }, data: { name: 'Martin2' }})).toEqual({
593
+ _id: user1._id,
594
+ name: 'Martin2',
595
+ dog: dog1._id,
596
+ })
648
597
 
649
- db.close()
598
+ // Returns omitted field requiring population after update, i.e. dog
599
+ expect(await user.findOneAndUpdate({
600
+ query: { _id: user1._id },
601
+ data: { name: 'Martin2' },
602
+ populate: ['dog'],
603
+ })).toEqual({
604
+ _id: user1._id,
605
+ name: 'Martin2',
606
+ dog: {
607
+ _id: dog1._id,
608
+ name: 'Scruff',
609
+ },
650
610
  })
651
611
 
652
- test('remove general', async () => {
653
- let db = (await opendb(null)).db
654
- let user = db.model('userRemove', {
655
- fields: {
656
- name: { type: 'string' },
657
- },
658
- })
612
+ // Error finding document to update
613
+ expect(await user.findOneAndUpdate({
614
+ query: { _id: db.id() },
615
+ data: { name: 'Martin2' },
616
+ })).toEqual(null)
617
+
618
+ // Error finding document to update (populate)
619
+ expect(await user.findOneAndUpdate({
620
+ query: { _id: db.id() },
621
+ data: { name: 'Martin2' },
622
+ populate: ['dog'],
623
+ })).toEqual(null)
624
+ })
625
+
626
+ test('remove defaults', async () => {
627
+ let user = db.model('userRemove', {
628
+ fields: {
629
+ name: { type: 'string' },
630
+ },
631
+ })
659
632
 
660
- // Clear (incase of failed a test)
661
- user._remove({}, { multi: true })
633
+ // Clear (incase of failed a test)
634
+ user._remove({}, { multi: true })
635
+
636
+ // Insert multiple
637
+ let inserted = await user.insert({ data: [
638
+ { name: 'Martin' },
639
+ { name: 'Martin' },
640
+ { name: 'Martin' },
641
+ { name: 'Martin' },
642
+ ]})
643
+ expect(inserted).toEqual([
644
+ { _id: expect.any(Object), name: 'Martin' },
645
+ { _id: expect.any(Object), name: 'Martin' },
646
+ { _id: expect.any(Object), name: 'Martin' },
647
+ { _id: expect.any(Object), name: 'Martin' },
648
+ ])
649
+
650
+ // Remove one by id
651
+ await expect(user.remove({ query: inserted[0]._id }))
652
+ .resolves.toEqual({ acknowledged: true, deletedCount: 1 })
653
+
654
+ // Remove one
655
+ await expect(user.remove({ query: { name: 'Martin' }, multi: false }))
656
+ .resolves.toEqual({ acknowledged: true, deletedCount: 1 })
657
+
658
+ // Remove many (default)
659
+ await expect(user.remove({ query: { name: 'Martin' } }))
660
+ .resolves.toEqual({ acknowledged: true, deletedCount: 2 })
661
+ })
662
+
663
+ test('count defaults', async () => {
664
+ let user = db.model('userCount', {
665
+ fields: {
666
+ name: { type: 'string' },
667
+ },
668
+ })
662
669
 
663
- // Insert multiple
664
- let inserted2 = await user.insert({ data: [{ name: 'Martin' }, { name: 'Martin' }, { name: 'Martin' }]})
665
- expect(inserted2).toEqual([
666
- {
667
- _id: expect.any(Object),
668
- name: 'Martin'
669
- }, {
670
- _id: expect.any(Object),
671
- name: 'Martin'
672
- }, {
673
- _id: expect.any(Object),
674
- name: 'Martin'
670
+ // Clear
671
+ await user._remove({}, { multi: true })
672
+
673
+ // Insert multiple
674
+ let inserted = await user.insert({ data: [
675
+ { name: 'Martin' },
676
+ { name: 'Martin' },
677
+ { name: 'Martin2' },
678
+ { name: 'Martin2' },
679
+ ]})
680
+
681
+ // Count one by id
682
+ await expect(user.count({ query: inserted[0]._id }))
683
+ .resolves.toEqual(1)
684
+
685
+ // Count many (default)
686
+ await expect(user.count({ query: { name: 'Martin' } }))
687
+ .resolves.toEqual(2)
688
+ })
689
+
690
+ test('hooks', async () => {
691
+ let user = db.model('user', {
692
+ fields: {
693
+ first: { type: 'string'},
694
+ last: { type: 'string'},
695
+ },
696
+ beforeInsert: [(data, next) => {
697
+ if (!data.first) {
698
+ next(new Error('beforeInsert error 1..'))
699
+ } else if (!data.last) {
700
+ setTimeout(function() {
701
+ next(new Error('beforeInsert error 2..'))
702
+ }, 100)
703
+ } else {
704
+ next()
705
+ }
706
+ }],
707
+ beforeUpdate: [(data, next) => {
708
+ if (!data.first) {
709
+ next(new Error('beforeUpdate error 1..'))
710
+ } else if (!data.last) {
711
+ setTimeout(function() {
712
+ next(new Error('beforeUpdate error 2..'))
713
+ }, 100)
714
+ } else {
715
+ next()
675
716
  }
676
- ])
717
+ }],
718
+ beforeRemove: [(next) => {
719
+ next(new Error('beforeRemove error..'))
720
+ }],
721
+ afterFind: [(data, next) => {
722
+ next()
723
+ }],
724
+ })
725
+ let userDoc = await user.insert({ data: { first: 'Martin', last: 'Luther' }})
726
+
727
+ // Catch insert (a)synchronous errors thrown in function or through `next(err)`
728
+ await expect(user.insert({ data: { first: '' } })).rejects.toThrow('beforeInsert error 1..')
729
+ await expect(user.insert({ data: { first: 'Martin' } })).rejects.toThrow('beforeInsert error 2..')
730
+ await expect(user.insert({ data: { first: 'Martin', last: 'Luther' } })).resolves.toEqual({
731
+ _id: expect.any(Object),
732
+ first: 'Martin',
733
+ last: 'Luther',
734
+ })
677
735
 
678
- // Remove one
679
- await expect(user.remove({ query: { name: 'Martin' }, multi: false }))
680
- .resolves.toMatchObject({ deletedCount: 1, result: { n: 1, ok: 1 }})
736
+ // Catch update (a)synchronous errors thrown in function or through `next(err)`
737
+ await expect(user.update({ query: userDoc._id, data: { first: '' } }))
738
+ .rejects.toThrow('beforeUpdate error 1..')
739
+ await expect(user.update({ query: userDoc._id, data: { first: 'Martin' } }))
740
+ .rejects.toThrow('beforeUpdate error 2..')
741
+ await expect(user.update({ query: userDoc._id, data: { first: 'Martin', last: 'Luther' } })).resolves.toEqual({
742
+ first: 'Martin',
743
+ last: 'Luther',
744
+ })
681
745
 
682
- // Remove many (default)
683
- await expect(user.remove({ query: { name: 'Martin' } }))
684
- .resolves.toMatchObject({ deletedCount: 2, result: { n: 2, ok: 1 }})
746
+ // Catch remove synchronous errors through `next(err)`
747
+ await expect(user.remove({ query: userDoc._id })).rejects.toThrow('beforeRemove error..')
685
748
 
686
- db.close()
749
+ // After find continues series
750
+ await expect(user.find({ query: userDoc._id })).resolves.toEqual({
751
+ _id: expect.any(Object),
752
+ first: 'Martin',
753
+ last: 'Luther',
687
754
  })
688
755
 
689
- test('hooks', async () => {
690
- let db = (await opendb(null)).db
691
- let user = db.model('user', {
692
- fields: {
693
- first: { type: 'string'},
694
- last: { type: 'string'}
756
+ // beforeUpdate/beforeInsert should have access to the original non-validated data
757
+ let user2 = db.model('user2', {
758
+ fields: {
759
+ first: { type: 'string' },
760
+ },
761
+ beforeInsert: [function (data, next) {
762
+ if (this.data.bad === true && !data.bad) next(new Error('error1'))
763
+ else next()
764
+ }],
765
+ beforeUpdate: [function (data, next) {
766
+ if (this.data.bad === true && !data.bad) next(new Error('error2'))
767
+ else next()
768
+ }],
769
+ })
770
+ let userDoc2 = await user2._insert({ first: 'M' })
771
+ await expect(user2.insert({ data: { first: 'M' } })).resolves.toEqual({ _id: expect.any(Object), first: 'M' })
772
+ await expect(user2.insert({ data: { first: 'M', bad: true } })).rejects.toThrow('error1')
773
+ await expect(user2.update({ query: userDoc2._id, data: { first: 'MM' } })).resolves.toEqual({ first: 'MM' })
774
+ await expect(user2.update({ query: userDoc2._id, data: { first: 'M', bad: true } })).rejects.toThrow('error2')
775
+ })
776
+
777
+ test('hooks > async', async () => {
778
+ let user = db.model('user', {
779
+ fields: {
780
+ first: { type: 'string'},
781
+ },
782
+ afterFind: [
783
+ async (data) => {
784
+ return new Promise((resolve, reject) => {
785
+ if (data.first === 'Martin1') {
786
+ setTimeout(() => {
787
+ data.first = 'Martin1 delayed'
788
+ resolve(data)
789
+ }, 100)
790
+ } else {
791
+ resolve(data)
792
+ }
793
+ })
695
794
  },
696
- beforeInsert: [(data, next) => {
697
- if (!data.first) {
698
- next(new Error('beforeInsert error 1..'))
699
- } else if (!data.last) {
700
- setTimeout(function() {
701
- next(new Error('beforeInsert error 2..'))
702
- }, 100)
703
- } else {
704
- next()
705
- }
706
- }],
707
- beforeUpdate: [(data, next) => {
708
- if (!data.first) {
709
- next(new Error('beforeUpdate error 1..'))
710
- } else if (!data.last) {
711
- setTimeout(function() {
712
- next(new Error('beforeUpdate error 2..'))
795
+ async (data) => {
796
+ return new Promise((resolve, reject) => {
797
+ if (data.first === 'Martin2') {
798
+ setTimeout(() => {
799
+ data.first = 'Martin2 delayed'
800
+ resolve(data)
801
+ }, 100)
802
+ } else {
803
+ resolve(data)
804
+ }
805
+ })
806
+ },
807
+ async (data) => {
808
+ return new Promise((resolve, reject) => {
809
+ setTimeout(() => {
810
+ if (data.first === 'Martin3') {
811
+ reject(new Error('An async error occurred with Martin3'))
812
+ } else {
813
+ resolve(data)
814
+ }
713
815
  }, 100)
714
- } else {
715
- next()
716
- }
717
- }],
718
- beforeRemove: [(next) => {
719
- next(new Error('beforeRemove error..'))
720
- }],
721
- afterFind: [(data, next) => {
722
- next()
723
- }],
724
- })
725
- let userDoc = await user.insert({ data: { first: 'Martin', last: 'Luther' }})
726
-
727
- // Catch insert (a)synchronous errors thrown in function or through `next(err)`
728
- await expect(user.insert({ data: { first: '' } })).rejects.toThrow('beforeInsert error 1..')
729
- await expect(user.insert({ data: { first: 'Martin' } })).rejects.toThrow('beforeInsert error 2..')
730
- await expect(user.insert({ data: { first: 'Martin', last: 'Luther' } })).resolves.toEqual({
731
- _id: expect.any(Object),
732
- first: 'Martin',
733
- last: 'Luther'
734
- })
735
-
736
- // Catch update (a)synchronous errors thrown in function or through `next(err)`
737
- await expect(user.update({ query: userDoc._id, data: { first: '' } }))
738
- .rejects.toThrow('beforeUpdate error 1..')
739
- await expect(user.update({ query: userDoc._id, data: { first: 'Martin' } }))
740
- .rejects.toThrow('beforeUpdate error 2..')
741
- await expect(user.update({ query: userDoc._id, data: { first: 'Martin', last: 'Luther' } })).resolves.toEqual({
742
- first: 'Martin',
743
- last: 'Luther'
744
- })
745
-
746
- // Catch remove synchronous errors through `next(err)`
747
- await expect(user.remove({ query: userDoc._id })).rejects.toThrow('beforeRemove error..')
748
-
749
- // After find continues series
750
- await expect(user.find({ query: userDoc._id })).resolves.toEqual({
751
- _id: expect.any(Object),
752
- first: 'Martin',
753
- last: 'Luther'
754
- })
755
-
756
- // beforeUpdate/beforeInsert should have access to the original non-validated data
757
- let user2 = db.model('user2', {
758
- fields: {
759
- first: { type: 'string' },
816
+ })
760
817
  },
761
- beforeInsert: [function (data, next) {
762
- if (this.data.bad === true && !data.bad) next(new Error('error1'))
763
- else next()
764
- }],
765
- beforeUpdate: [function (data, next) {
766
- if (this.data.bad === true && !data.bad) next(new Error('error2'))
767
- else next()
768
- }],
769
- })
770
- let userDoc2 = await user2._insert({ first: 'M' })
771
- await expect(user2.insert({ data: { first: 'M' } })).resolves.toMatchObject({ first: 'M' })
772
- await expect(user2.insert({ data: { first: 'M', bad: true } })).rejects.toThrow('error1')
773
- await expect(user2.update({ query: userDoc2._id, data: { first: 'M', } })).resolves.toEqual({ first: 'M' })
774
- await expect(user2.update({ query: userDoc2._id, data: { first: 'M', bad: true } })).rejects.toThrow('error2')
775
-
776
- db.close()
818
+ async (data, next) => { // next is ignored, no error
819
+ return new Promise((resolve, reject) => {
820
+ data.last = 'Luther'
821
+ resolve(data)
822
+ })
823
+ },
824
+ (data, next) => { // normal next() callbacks can be mixed with async
825
+ setTimeout(() => {
826
+ data.age = 32
827
+ next()
828
+ }, 100)
829
+ },
830
+ ],
831
+ })
832
+ let user1Doc = await user.insert({
833
+ data: { first: 'Martin1' },
834
+ })
835
+ let user2Doc = await user.insert({
836
+ data: { first: 'Martin2' },
837
+ })
838
+ let user3Doc = await user.insert({
839
+ data: { first: 'Martin3' },
777
840
  })
778
841
 
779
- }
842
+ // First async hook is delayed
843
+ await expect(user.find({ query: user1Doc._id })).resolves.toEqual({
844
+ _id: expect.any(Object),
845
+ first: 'Martin1 delayed',
846
+ last: 'Luther',
847
+ age: 32,
848
+ })
849
+ // Second async hook is delayed
850
+ await expect(user.find({ query: user2Doc._id })).resolves.toEqual({
851
+ _id: expect.any(Object),
852
+ first: 'Martin2 delayed',
853
+ last: 'Luther',
854
+ age: 32,
855
+ })
856
+ // Third async hook throws an error
857
+ await expect(user.find({ query: user3Doc._id }))
858
+ .rejects.toThrow('An async error occurred with Martin3')
859
+ })