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/model.js CHANGED
@@ -1,615 +1,654 @@
1
- module.exports = function(monastery, opendb) {
2
-
3
- test('model setup', async () => {
4
- // Setup
5
- let db = (await opendb(false)).db
6
- let user = db.model('user', { fields: {
7
- name: { type: 'string' },
8
- pets: [{ type: 'string' }],
9
- colors: { red: { type: 'string' } },
10
- points: [[{ type: 'number' }]],
11
- points2: [[{ x: { type: 'number' } }]],
12
- logo: { type: 'image' }
13
- }})
14
-
15
- // no fields defined
16
- expect(db.model('user2', { fields: {} }).fields).toEqual({
17
- _id: {
18
- insertOnly: true,
19
- isId: true,
20
- type: 'id',
21
- },
22
- createdAt: {
23
- default: expect.any(Function),
24
- insertOnly: true,
25
- isInteger: true,
26
- timestampField: true,
27
- type: 'integer',
28
- },
29
- updatedAt: {
30
- default: expect.any(Function),
31
- isInteger: true,
32
- timestampField: true,
33
- type: 'integer',
34
- },
35
- })
36
-
37
- // Has model name
38
- expect(user.name).toEqual('user')
39
-
40
- // Basic field
41
- expect(user.fields.name).toEqual({ type: 'string', isString: true })
42
-
43
- // Image field
44
- expect(user.fields.logo).toEqual({ type: 'any', isAny: true, image: true })
45
-
46
- // Array field
47
- expect(user.fields.pets).toContainEqual({ type: 'string', isString: true })
48
-
49
- // Array schema
50
- expect(user.fields.pets.schema).toEqual({ type: 'array', isArray: true })
51
-
52
- // Subdocument field and schema
53
- expect(user.fields.colors).toEqual({
54
- red: { isString: true, type: 'string' },
55
- schema: { isObject: true, type: 'object' }
56
- })
57
-
58
- // Array array field (no array properties)
59
- expect(JSON.stringify(user.fields.points)).toEqual(JSON.stringify(
60
- [[{ type: 'number', isNumber: true }]]
61
- ))
62
-
63
- // Array array schema
64
- expect(user.fields.points.schema).toEqual({ type: 'array', isArray: true })
65
- expect(user.fields.points[0].schema).toEqual({ type: 'array', isArray: true })
66
-
67
- // Array array subdocument field (no array properties)
68
- expect(JSON.stringify(user.fields.points2)).toEqual(JSON.stringify(
69
- [[{
70
- x: { type: 'number', isNumber: true },
71
- schema: { type: 'object', isObject: true }
72
- }]]
73
- ))
74
- })
75
-
76
- test('model setup with default fields', async () => {
77
- // Setup
78
- let db = (await opendb(false, { defaultObjects: true })).db
79
-
80
- // Default fields
81
- expect(db.model('user2', { fields: {} }).fields).toEqual({
82
- _id: {
1
+ // timestamps = false here and test for true??? OR test timestamps = false
2
+ const Model = require('../lib/model.js')
3
+ const monastery = require('../lib/index.js')
4
+
5
+ let db
6
+ beforeAll(async () => { db = monastery('127.0.0.1/monastery') })
7
+ afterAll(async () => { db.close() })
8
+
9
+ test('model > model on manager', async () => {
10
+ db.model('user', { fields: {} })
11
+ let modelNamedConflict = db.model('open', { fields: {} })
12
+
13
+ // Model added to manager[model]
14
+ expect(db.user).toEqual(expect.any(Object))
15
+ expect(db.models.user).toEqual(expect.any(Object))
16
+
17
+ // Model with a name conflict is only added to manager.models[name]
18
+ expect(db.open).toEqual(expect.any(Function))
19
+ expect(db.models.open).toEqual(modelNamedConflict)
20
+ })
21
+
22
+ test('model setup', async () => {
23
+ // Setup
24
+ let user = db.model('user', { fields: {
25
+ name: { type: 'string' },
26
+ pets: [{ type: 'string' }],
27
+ colors: { red: { type: 'string' } },
28
+ points: [[{ type: 'number' }]],
29
+ points2: [[{ x: { type: 'number' } }]],
30
+ logo: { type: 'image' },
31
+ }})
32
+
33
+ // no fields defined
34
+ expect(db.model('user2', { fields: {} }).fields).toEqual({
35
+ _id: {
83
36
  insertOnly: true,
84
37
  isId: true,
85
38
  type: 'id',
86
39
  },
87
- createdAt: {
40
+ createdAt: {
88
41
  default: expect.any(Function),
89
42
  insertOnly: true,
90
43
  isInteger: true,
91
44
  timestampField: true,
92
- type: 'integer'
45
+ type: 'integer',
93
46
  },
94
47
  updatedAt: {
95
48
  default: expect.any(Function),
96
49
  isInteger: true,
97
50
  timestampField: true,
98
- type: 'integer'
99
- }
100
- })
51
+ type: 'integer',
52
+ },
101
53
  })
102
54
 
103
- test('model setup with default objects', async () => {
104
- // Setup
105
- let db = (await opendb(false, { defaultObjects: true })).db
106
- let user = db.model('user', { fields: {
107
- name: { type: 'string' },
108
- pets: [{ type: 'string' }],
109
- colors: { red: { type: 'string' } },
110
- points: [[{ type: 'number' }]],
111
- points2: [[{ x: { type: 'number' } }]]
112
- }})
113
-
114
- // Array schema
115
- expect(user.fields.pets.schema).toEqual({
116
- type: 'array',
117
- isArray: true,
118
- default: expect.any(Function)
119
- })
120
-
121
- // Subdocument field and schema
122
- expect(user.fields.colors).toEqual({
123
- red: { isString: true, type: 'string' },
124
- schema: { isObject: true, type: 'object', default: expect.any(Function) }
125
- })
126
- })
127
-
128
- test('model setup with schema', async () => {
129
- // Setup
130
- let db = (await opendb(false)).db
131
- let objectSchemaTypeRef = { name: { type: 'string', minLength: 5 } }
132
- let user = db.model('user', {
133
- fields: {
134
- pet: { ...objectSchemaTypeRef, schema: { virtual: true }},
135
- pets: db.arrayWithSchema(
136
- [objectSchemaTypeRef],
137
- { virtual: true },
138
- ),
139
- }
140
- })
141
- // Object with schema
142
- expect(user.fields.pet).toEqual({
143
- name: {
144
- type: 'string',
145
- isString: true,
146
- minLength: 5,
147
- },
148
- schema: {
149
- type: 'object',
150
- isObject: true,
151
- virtual: true,
152
- },
153
- })
154
- // Array with schema
155
- expect(user.fields.pets[0]).toEqual({
156
- name: {
157
- type: 'string',
158
- isString: true,
159
- minLength: 5,
160
- },
161
- schema: {
162
- type: 'object',
163
- isObject: true,
164
- },
165
- })
166
- expect(user.fields.pets.schema).toEqual({
167
- type: 'array',
168
- isArray: true,
55
+ // Has model name
56
+ expect(user.name).toEqual('user')
57
+
58
+ // Basic field
59
+ expect(user.fields.name).toEqual({ type: 'string', isString: true })
60
+
61
+ // Image field
62
+ expect(user.fields.logo).toEqual({ type: 'any', isAny: true, image: true })
63
+
64
+ // Array field
65
+ expect(user.fields.pets).toContainEqual({ type: 'string', isString: true })
66
+
67
+ // Array schema
68
+ expect(user.fields.pets.schema).toEqual({ type: 'array', isArray: true })
69
+
70
+ // Subdocument field and schema
71
+ expect(user.fields.colors).toEqual({
72
+ red: { isString: true, type: 'string' },
73
+ schema: { isObject: true, type: 'object' },
74
+ })
75
+
76
+ // Array array field (no array properties)
77
+ expect(JSON.stringify(user.fields.points)).toEqual(JSON.stringify(
78
+ [[{ type: 'number', isNumber: true }]]
79
+ ))
80
+
81
+ // Array array schema
82
+ expect(user.fields.points.schema).toEqual({ type: 'array', isArray: true })
83
+ expect(user.fields.points[0].schema).toEqual({ type: 'array', isArray: true })
84
+
85
+ // Array array subdocument field (no array properties)
86
+ expect(JSON.stringify(user.fields.points2)).toEqual(JSON.stringify(
87
+ [[{
88
+ x: { type: 'number', isNumber: true },
89
+ schema: { type: 'object', isObject: true },
90
+ }]]
91
+ ))
92
+ })
93
+
94
+ test('model setup with default fields', async () => {
95
+ // Default fields
96
+ expect(db.model('user2', { fields: {} }).fields).toEqual({
97
+ _id: {
98
+ insertOnly: true,
99
+ isId: true,
100
+ type: 'id',
101
+ },
102
+ createdAt: {
103
+ default: expect.any(Function),
104
+ insertOnly: true,
105
+ isInteger: true,
106
+ timestampField: true,
107
+ type: 'integer',
108
+ },
109
+ updatedAt: {
110
+ default: expect.any(Function),
111
+ isInteger: true,
112
+ timestampField: true,
113
+ type: 'integer',
114
+ },
115
+ })
116
+ })
117
+
118
+ test('model setup with default objects', async () => {
119
+ const db2 = monastery('127.0.0.1/monastery', { defaultObjects: true })
120
+ let user = db2.model('user', { fields: {
121
+ name: { type: 'string' },
122
+ pets: [{ type: 'string' }],
123
+ colors: { red: { type: 'string' } },
124
+ points: [[{ type: 'number' }]],
125
+ points2: [[{ x: { type: 'number' } }]],
126
+ }})
127
+
128
+ // Array schema
129
+ expect(user.fields.pets.schema).toEqual({
130
+ type: 'array',
131
+ isArray: true,
132
+ default: expect.any(Function),
133
+ })
134
+
135
+ // Subdocument field and schema
136
+ expect(user.fields.colors).toEqual({
137
+ red: { isString: true, type: 'string' },
138
+ schema: { isObject: true, type: 'object', default: expect.any(Function) },
139
+ })
140
+ db2.close()
141
+ })
142
+
143
+ test('model setup with schema', async () => {
144
+ // Setup
145
+ let objectSchemaTypeRef = { name: { type: 'string', minLength: 5 } }
146
+ let user = db.model('user', {
147
+ fields: {
148
+ pet: { ...objectSchemaTypeRef, schema: { virtual: true }},
149
+ pets: db.arrayWithSchema(
150
+ [objectSchemaTypeRef],
151
+ { virtual: true }
152
+ ),
153
+ },
154
+ })
155
+ // Object with schema
156
+ expect(user.fields.pet).toEqual({
157
+ name: {
158
+ type: 'string',
159
+ isString: true,
160
+ minLength: 5,
161
+ },
162
+ schema: {
163
+ type: 'object',
164
+ isObject: true,
169
165
  virtual: true,
170
- })
166
+ },
167
+ })
168
+ // Array with schema
169
+ expect(user.fields.pets[0]).toEqual({
170
+ name: {
171
+ type: 'string',
172
+ isString: true,
173
+ minLength: 5,
174
+ },
175
+ schema: {
176
+ type: 'object',
177
+ isObject: true,
178
+ },
171
179
  })
180
+ expect(user.fields.pets.schema).toEqual({
181
+ type: 'array',
182
+ isArray: true,
183
+ virtual: true,
184
+ })
185
+ })
172
186
 
173
- test('model setup with messages', async () => {
174
- // Setup
175
- let db = (await opendb(false)).db
176
- let user = db.model('user', {
177
- fields: {
178
- name: { type: 'string' },
179
- },
180
- messages: {
181
- // these are sorted when trhe model's initialised
182
- 'cats.name': {},
183
-
184
- 'dogs.name': {},
185
- 'dogs.$.name': {},
186
- 'dogs.1.name': {},
187
- 'dogs.$': {},
188
- 'dogs.1': {},
189
-
190
- 'pigs.name': {},
191
- 'pigs.$.name': {},
192
- 'pigs.1.name': {},
193
- 'pigs.2.name': {},
194
-
195
- 'gulls.$.1.$': {},
196
- 'gulls.1.$.1': {},
197
- 'gulls.$': {},
198
- 'gulls.$.$': {},
199
- 'gulls.$.$.1': {},
200
- 'gulls.$.1': {},
201
- 'gulls.1.$': {},
202
- 'gulls.1.1': {},
203
- 'gulls.1.1.$': {},
204
- 'gulls.name': {},
205
- 'gulls.$.name': {},
206
- },
207
- })
208
- // Object with schema
209
- // console.log(user.messages)
210
- expect(Object.keys(user.messages)).toEqual([
211
- 'cats.name',
212
- 'dogs.name',
213
- 'dogs.1.name',
214
- 'dogs.1',
215
- 'pigs.name',
216
- 'pigs.1.name',
217
- 'pigs.2.name',
218
- 'gulls.1.1',
219
- 'gulls.name',
220
- 'gulls.1.1.$',
221
- 'gulls.1.$.1',
222
- 'gulls.1.$',
223
- 'dogs.$.name',
224
- 'dogs.$',
225
- 'pigs.$.name',
226
- 'gulls.$',
227
- 'gulls.$.1',
228
- 'gulls.$.name',
229
- 'gulls.$.1.$',
230
- 'gulls.$.$',
231
- 'gulls.$.$.1',
232
- ])
233
-
234
- expect(user.messages).toEqual({
235
- // these are sorted in model initialisation
236
- 'cats.name': {
237
- 'regex': /^cats\.name$/,
238
- },
239
- 'dogs.$': {
240
- 'regex': /^dogs\.[0-9]+$/,
241
- },
242
- 'dogs.$.name': {
243
- 'regex': /^dogs\.[0-9]+\.name$/,
244
- },
245
- 'dogs.1': {
246
- 'regex': /^dogs\.1$/,
247
- },
248
- 'dogs.1.name': {
249
- 'regex': /^dogs\.1\.name$/,
250
- },
251
- 'dogs.name': {
252
- 'regex': /^dogs\.name$/,
253
- },
254
- 'gulls.$': {
255
- 'regex': /^gulls\.[0-9]+$/,
256
- },
257
- 'gulls.$.$': {
258
- 'regex': /^gulls\.[0-9]+\.[0-9]+$/,
259
- },
260
- 'gulls.$.$.1': {
261
- 'regex': /^gulls\.[0-9]+\.[0-9]+\.1$/,
262
- },
263
- 'gulls.$.1': {
264
- 'regex': /^gulls\.[0-9]+\.1$/,
265
- },
266
- 'gulls.$.1.$': {
267
- 'regex': /^gulls\.[0-9]+\.1\.[0-9]+$/,
268
- },
269
- 'gulls.$.name': {
270
- 'regex': /^gulls\.[0-9]+\.name$/,
271
- },
272
- 'gulls.1.$': {
273
- 'regex': /^gulls\.1\.[0-9]+$/,
274
- },
275
- 'gulls.1.$.1': {
276
- 'regex': /^gulls\.1\.[0-9]+\.1$/,
277
- },
278
- 'gulls.1.1': {
279
- 'regex': /^gulls\.1\.1$/,
280
- },
281
- 'gulls.1.1.$': {
282
- 'regex': /^gulls\.1\.1\.[0-9]+$/,
283
- },
284
- 'gulls.name': {
285
- 'regex': /^gulls\.name$/,
286
- },
287
- 'pigs.$.name': {
288
- 'regex': /^pigs\.[0-9]+\.name$/,
289
- },
290
- 'pigs.1.name': {
291
- 'regex': /^pigs\.1\.name$/,
292
- },
293
- 'pigs.2.name': {
294
- 'regex': /^pigs\.2\.name$/,
295
- },
296
- 'pigs.name': {
297
- 'regex': /^pigs\.name$/,
187
+ test('model setup with messages', async () => {
188
+ let user = db.model('user', {
189
+ fields: {
190
+ name: { type: 'string' },
191
+ },
192
+ messages: {
193
+ // these are sorted when trhe model's initialised
194
+ 'cats.name': {},
195
+
196
+ 'dogs.name': {},
197
+ 'dogs.$.name': {},
198
+ 'dogs.1.name': {},
199
+ 'dogs.$': {},
200
+ 'dogs.1': {},
201
+
202
+ 'pigs.name': {},
203
+ 'pigs.$.name': {},
204
+ 'pigs.1.name': {},
205
+ 'pigs.2.name': {},
206
+
207
+ 'gulls.$.1.$': {},
208
+ 'gulls.1.$.1': {},
209
+ 'gulls.$': {},
210
+ 'gulls.$.$': {},
211
+ 'gulls.$.$.1': {},
212
+ 'gulls.$.1': {},
213
+ 'gulls.1.$': {},
214
+ 'gulls.1.1': {},
215
+ 'gulls.1.1.$': {},
216
+ 'gulls.name': {},
217
+ 'gulls.$.name': {},
218
+ },
219
+ })
220
+ // Object with schema
221
+ // console.log(user.messages)
222
+ expect(Object.keys(user.messages)).toEqual([
223
+ 'cats.name',
224
+ 'dogs.name',
225
+ 'dogs.1.name',
226
+ 'dogs.1',
227
+ 'pigs.name',
228
+ 'pigs.1.name',
229
+ 'pigs.2.name',
230
+ 'gulls.1.1',
231
+ 'gulls.name',
232
+ 'gulls.1.1.$',
233
+ 'gulls.1.$.1',
234
+ 'gulls.1.$',
235
+ 'dogs.$.name',
236
+ 'dogs.$',
237
+ 'pigs.$.name',
238
+ 'gulls.$',
239
+ 'gulls.$.1',
240
+ 'gulls.$.name',
241
+ 'gulls.$.1.$',
242
+ 'gulls.$.$',
243
+ 'gulls.$.$.1',
244
+ ])
245
+
246
+ expect(user.messages).toEqual({
247
+ // these are sorted in model initialisation
248
+ 'cats.name': {
249
+ 'regex': /^cats\.name$/,
250
+ },
251
+ 'dogs.$': {
252
+ 'regex': /^dogs\.[0-9]+$/,
253
+ },
254
+ 'dogs.$.name': {
255
+ 'regex': /^dogs\.[0-9]+\.name$/,
256
+ },
257
+ 'dogs.1': {
258
+ 'regex': /^dogs\.1$/,
259
+ },
260
+ 'dogs.1.name': {
261
+ 'regex': /^dogs\.1\.name$/,
262
+ },
263
+ 'dogs.name': {
264
+ 'regex': /^dogs\.name$/,
265
+ },
266
+ 'gulls.$': {
267
+ 'regex': /^gulls\.[0-9]+$/,
268
+ },
269
+ 'gulls.$.$': {
270
+ 'regex': /^gulls\.[0-9]+\.[0-9]+$/,
271
+ },
272
+ 'gulls.$.$.1': {
273
+ 'regex': /^gulls\.[0-9]+\.[0-9]+\.1$/,
274
+ },
275
+ 'gulls.$.1': {
276
+ 'regex': /^gulls\.[0-9]+\.1$/,
277
+ },
278
+ 'gulls.$.1.$': {
279
+ 'regex': /^gulls\.[0-9]+\.1\.[0-9]+$/,
280
+ },
281
+ 'gulls.$.name': {
282
+ 'regex': /^gulls\.[0-9]+\.name$/,
283
+ },
284
+ 'gulls.1.$': {
285
+ 'regex': /^gulls\.1\.[0-9]+$/,
286
+ },
287
+ 'gulls.1.$.1': {
288
+ 'regex': /^gulls\.1\.[0-9]+\.1$/,
289
+ },
290
+ 'gulls.1.1': {
291
+ 'regex': /^gulls\.1\.1$/,
292
+ },
293
+ 'gulls.1.1.$': {
294
+ 'regex': /^gulls\.1\.1\.[0-9]+$/,
295
+ },
296
+ 'gulls.name': {
297
+ 'regex': /^gulls\.name$/,
298
+ },
299
+ 'pigs.$.name': {
300
+ 'regex': /^pigs\.[0-9]+\.name$/,
301
+ },
302
+ 'pigs.1.name': {
303
+ 'regex': /^pigs\.1\.name$/,
304
+ },
305
+ 'pigs.2.name': {
306
+ 'regex': /^pigs\.2\.name$/,
307
+ },
308
+ 'pigs.name': {
309
+ 'regex': /^pigs\.name$/,
310
+ },
311
+ })
312
+ })
313
+
314
+ test('model reserved rules', async () => {
315
+ // Setup
316
+ // let db = (await opendb(false, { hideErrors: true })).db // hide debug error
317
+ let user = db.model('user-model', {
318
+ fields: {
319
+ name: {
320
+ type: 'string',
321
+ params: {}, // reserved keyword (image plugin)
322
+ paramsUnreserved: {},
298
323
  },
299
- })
300
- }),
301
-
302
- test('model reserved rules', async () => {
303
- // Setup
304
- let db = (await opendb(false, { hideErrors: true })).db // hide debug error
305
- let user = db.model('user', {
306
- fields: {
307
- name: {
308
- type: 'string',
309
- params: {}, // reserved keyword (image plugin)
310
- paramsUnreserved: {}
311
- },
324
+ },
325
+ rules: {
326
+ params: (value) => {
327
+ return false // shouldn'r run
312
328
  },
313
- rules: {
314
- params: (value) => {
315
- return false // shouldn'r run
316
- }
317
- }
318
- })
319
- await expect(user.validate({ name: 'Martin' })).resolves.toMatchObject({
320
- name: 'Martin',
321
- })
322
- })
323
-
324
- test('model indexes', async () => {
325
- // Setup: Need to test different types of indexes
326
- let db = (await opendb(null)).db
327
- // Setup: Drop previously tested collections
328
- if ((await db._db.listCollections().toArray()).find(o => o.name == 'userIndexRaw')) {
329
- await db._db.collection('userIndexRaw').drop()
330
- }
331
- if ((await db._db.listCollections().toArray()).find(o => o.name == 'userIndex')) {
332
- await db._db.collection('userIndex').drop()
333
- }
329
+ },
330
+ })
331
+ await expect(user.validate({ name: 'Martin' })).resolves.toEqual({
332
+ name: 'Martin',
333
+ createdAt: expect.any(Number),
334
+ updatedAt: expect.any(Number),
335
+ })
336
+ })
337
+
338
+ test('model indexes', async () => {
339
+ // Setup: Need to test different types of indexes
340
+ // Setup: Drop previously tested collections
341
+ const allCollections = await db.db.listCollections().toArray()
342
+ if (allCollections.find(o => o.name == 'userIndexRaw')) {
343
+ await db.db.collection('userIndexRaw').drop()
344
+ }
345
+ if (allCollections.find(o => o.name == 'userIndex')) {
346
+ await db.db.collection('userIndex').drop()
347
+ }
348
+
349
+ // mongodb connection error
350
+ await expect(Model.prototype._setupIndexes.call(
351
+ { name: 'colnamehere', manager: null },
352
+ { name: { type: 'string', index: 'text' }}
353
+ )).rejects.toThrow('Skipping createIndex on the \'colnamehere\' model, no mongodb connection found.')
354
+
355
+ // Unique & text index (after model initialisation, in serial)
356
+ let userIndexRawModel = db.model('userIndexRaw', { fields: {} })
357
+ await userIndexRawModel._setupIndexes({ email: { type: 'string', index: 'unique' } })
358
+ await userIndexRawModel._setupIndexes({ name: { type: 'string', index: 'text' } })
359
+ let indexes = await (db.get('userIndexRaw').indexes())
360
+ expect(indexes[0]).toEqual({
361
+ v: 2,
362
+ key: { _id: 1 },
363
+ name: '_id_',
364
+ })
365
+ expect(indexes[1]).toEqual({
366
+ v: 2,
367
+ unique: true,
368
+ key: { email: 1 },
369
+ name: 'email_1',
370
+ })
371
+ expect(indexes[2]).toEqual({
372
+ v: 2,
373
+ key: { _fts: 'text', _ftsx: 1 },
374
+ name: 'text',
375
+ weights: { name: 1 },
376
+ default_language: 'english',
377
+ language_override: 'language',
378
+ textIndexVersion: 3,
379
+ })
334
380
 
335
- // Unique & text index (after model initialisation, in serial)
336
- let userIndexRawModel = db.model('userIndexRaw', {fields: {}})
337
- await userIndexRawModel._setupIndexes({
381
+ // Unique & text index
382
+ let userIndexModel = await db.model('userIndex', {
383
+ waitForIndexes: true,
384
+ fields: {
338
385
  email: { type: 'string', index: 'unique' },
339
- })
340
- await userIndexRawModel._setupIndexes({
341
- name: { type: 'string', index: 'text' },
342
- })
343
- let indexes = await db._db.collection('userIndexRaw').indexes()
344
- expect(indexes[0]).toMatchObject({ v: 2, key: { _id: 1 }, name: '_id_' })
345
- expect(indexes[1]).toMatchObject({ v: 2, unique: true, key: { email: 1 }, name: 'email_1' })
346
- expect(indexes[2]).toMatchObject({
347
- v: 2,
348
- key: { _fts: 'text', _ftsx: 1 },
349
- name: 'text',
350
- weights: { name: 1 },
351
- default_language: 'english',
352
- language_override: 'language',
353
- textIndexVersion: 3
354
- })
355
-
356
- // Unique & text index
357
- let userIndexModel = await db.model('userIndex', {
358
- waitForIndexes: true,
359
- fields: {
360
- email: { type: 'string', index: 'unique' },
361
- name: { type: 'string', index: 'text' },
362
- }
363
- })
364
-
365
- let indexes2 = await db._db.collection('userIndex').indexes()
366
- expect(indexes2[0]).toMatchObject({ v: 2, key: { _id: 1 }, name: '_id_' })
367
- expect(indexes2[1]).toMatchObject({ v: 2, unique: true, key: { email: 1 }, name: 'email_1' })
368
- expect(indexes2[2]).toMatchObject({
369
- v: 2,
370
- key: { _fts: 'text', _ftsx: 1 },
371
- name: 'text',
372
- weights: { name: 1 },
373
- default_language: 'english',
374
- language_override: 'language',
375
- textIndexVersion: 3
376
- })
377
-
378
- // No text index change error, i.e. new Error('Index with name: text already exists with different options')
379
- await expect(userIndexModel._setupIndexes({
380
386
  name: { type: 'string', index: 'text' },
381
- name2: { type: 'string', index: 'text' }
382
- })).resolves.toEqual([{
383
- 'key': { 'name': 'text', 'name2': 'text' },
384
- 'name': 'text',
385
- }])
386
-
387
- // Text index on a different model
388
- await expect(userIndexRawModel._setupIndexes({
389
- name2: { type: 'string', index: 'text' }
390
- })).resolves.toEqual([{
391
- 'key': {'name2': 'text'},
392
- 'name': 'text',
393
- }])
394
-
395
- db.close()
396
- })
397
-
398
- test('model unique indexes', async () => {
399
- let db = (await opendb(null)).db
400
- // Setup: Drop previously tested collections
401
- if ((await db._db.listCollections().toArray()).find(o => o.name == 'userUniqueIndex')) {
402
- await db._db.collection('userUniqueIndex').drop()
403
- }
404
-
405
- // Partial unique indexes (allows mulitple null values)
406
- await db.model('userUniqueIndex', {
407
- waitForIndexes: true,
408
- fields: {
409
- email: {
410
- type: 'string',
411
- index: {
412
- type: 'unique',
413
- partialFilterExpression: {
414
- email: { $type: 'string' }
415
- }
416
- }
417
- },
418
- }
419
- })
387
+ },
388
+ })
420
389
 
421
- let indexes2 = await db._db.collection('userUniqueIndex').indexes()
422
- expect(indexes2[0]).toMatchObject({ v: 2, key: { _id: 1 }, name: '_id_' })
423
- expect(indexes2[1]).toMatchObject({ v: 2, unique: true, key: { email: 1 }, name: 'email_1' })
390
+ let userIndexModelIndexes = await db.db.collection('userIndex').indexes()
391
+ expect(userIndexModelIndexes[0]).toEqual({
392
+ v: 2,
393
+ key: { _id: 1 },
394
+ name: '_id_',
395
+ })
396
+ expect(userIndexModelIndexes[1]).toEqual({
397
+ v: 2,
398
+ unique: true,
399
+ key: { email: 1 },
400
+ name: 'email_1',
401
+ })
402
+ expect(userIndexModelIndexes[2]).toEqual({
403
+ v: 2,
404
+ key: { _fts: 'text', _ftsx: 1 },
405
+ name: 'text',
406
+ weights: { name: 1 },
407
+ default_language: 'english',
408
+ language_override: 'language',
409
+ textIndexVersion: 3,
410
+ })
424
411
 
425
- await expect(db.userUniqueIndex.insert({ data: { 'email': 'ricky@orchid.co.nz' }})).resolves.toEqual({
426
- _id: expect.any(Object),
427
- email: 'ricky@orchid.co.nz'
428
- })
412
+ // No text index change error, i.e. new Error('Index with name: text already exists with different options')
413
+ await expect(userIndexModel._setupIndexes({
414
+ name: { type: 'string', index: 'text' },
415
+ name2: { type: 'string', index: 'text' },
416
+ })).resolves.toEqual([{
417
+ 'key': { 'name': 'text', 'name2': 'text' },
418
+ 'name': 'text',
419
+ }])
420
+
421
+ // Text index on a different model
422
+ await expect(userIndexRawModel._setupIndexes({
423
+ name2: { type: 'string', index: 'text' },
424
+ })).resolves.toEqual([{
425
+ 'key': {'name2': 'text'},
426
+ 'name': 'text',
427
+ }])
428
+ })
429
+
430
+ test('model unique indexes', async () => {
431
+ // Setup: Drop previously tested collections
432
+ if ((await db.db.listCollections().toArray()).find(o => o.name == 'userUniqueIndex')) {
433
+ await db.db.collection('userUniqueIndex').drop()
434
+ }
435
+
436
+ // Partial unique indexes (allows mulitple null values)
437
+ await db.model('userUniqueIndex', {
438
+ waitForIndexes: true,
439
+ fields: {
440
+ email: {
441
+ type: 'string',
442
+ index: {
443
+ type: 'unique',
444
+ partialFilterExpression: {
445
+ email: { $type: 'string' },
446
+ },
447
+ },
448
+ },
449
+ },
450
+ })
429
451
 
430
- await expect(db.userUniqueIndex.insert({ data: { 'email': 'ricky@orchid.co.nz' }})).rejects.toThrow(
431
- /E11000 duplicate key error collection: monastery.userUniqueIndex index: email_1 dup key: {/
432
- )
452
+ let indexes2 = await db.db.collection('userUniqueIndex').indexes()
453
+ expect(indexes2[0]).toEqual({
454
+ v: 2,
455
+ key: { _id: 1 },
456
+ name: '_id_',
457
+ })
458
+ expect(indexes2[1]).toEqual({
459
+ v: 2,
460
+ unique: true,
461
+ key: { email: 1 },
462
+ name: 'email_1',
463
+ partialFilterExpression: {
464
+ email: { '$type': 'string' },
465
+ },
466
+ })
433
467
 
434
- await expect(db.userUniqueIndex.insert({ data: { 'email': null }})).resolves.toEqual({
435
- _id: expect.any(Object),
436
- email: null
437
- })
468
+ await expect(db.userUniqueIndex.insert({ data: { 'email': 'email@domain.co.nz' }})).resolves.toEqual({
469
+ _id: expect.any(Object),
470
+ createdAt: expect.any(Number),
471
+ email: 'email@domain.co.nz',
472
+ updatedAt: expect.any(Number),
473
+ })
438
474
 
439
- await expect(db.userUniqueIndex.insert({ data: { 'email': null }})).resolves.toEqual({
440
- _id: expect.any(Object),
441
- email: null
442
- })
475
+ await expect(db.userUniqueIndex.insert({ data: { 'email': 'email@domain.co.nz' }})).rejects.toThrow(
476
+ /E11000 duplicate key error collection: monastery.userUniqueIndex index: email_1 dup key: {/
477
+ )
443
478
 
444
- db.close()
479
+ await expect(db.userUniqueIndex.insert({ data: { 'email': null }})).resolves.toEqual({
480
+ _id: expect.any(Object),
481
+ createdAt: expect.any(Number),
482
+ email: null,
483
+ updatedAt: expect.any(Number),
445
484
  })
446
485
 
447
- test('model subdocument indexes', async () => {
448
- // Setup: Need to test different types of indexes
449
- let db = (await opendb(null)).db
450
- // Setup: Drop previously tested collections
451
- if ((await db._db.listCollections().toArray()).find(o => o.name == 'userIndexSubdoc')) {
452
- await db._db.collection('userIndexSubdoc').drop()
453
- }
454
- // Run
455
- let userModel = await db.model('userIndexSubdoc', {
456
- fields: {}
457
- })
458
- await expect(userModel._setupIndexes(
459
- {
460
- animals: {
486
+ await expect(db.userUniqueIndex.insert({ data: { 'email': null }})).resolves.toEqual({
487
+ _id: expect.any(Object),
488
+ createdAt: expect.any(Number),
489
+ email: null,
490
+ updatedAt: expect.any(Number),
491
+ })
492
+ })
493
+
494
+ test('model subdocument indexes', async () => {
495
+ // Setup: Need to test different types of indexes
496
+ // Setup: Drop previously tested collections
497
+ if ((await db.db.listCollections().toArray()).find(o => o.name == 'userIndexSubdoc')) {
498
+ await db.db.collection('userIndexSubdoc').drop()
499
+ }
500
+ // Run
501
+ let userModel = await db.model('userIndexSubdoc', {
502
+ fields: {},
503
+ })
504
+ await expect(userModel._setupIndexes(
505
+ {
506
+ animals: {
507
+ name: { type: 'string', index: 'unique' },
508
+ },
509
+ animals2: {
510
+ names: {
461
511
  name: { type: 'string', index: 'unique' },
462
512
  },
463
- animals2: {
464
- names: {
465
- name: { type: 'string', index: 'unique' },
466
- },
467
- },
468
- animals3: {
469
- names: {
470
- name: { type: 'string', index: 'text' },
471
- },
513
+ },
514
+ animals3: {
515
+ names: {
516
+ name: { type: 'string', index: 'text' },
472
517
  },
473
- }, {
474
- dryRun: true
475
- }
476
- )).resolves.toEqual([{
477
- 'key': { 'animals.name': 1 },
478
- 'name': 'animals.name_1',
479
- 'unique': true,
480
- }, {
481
- 'key': { 'animals2.names.name': 1 },
482
- 'name': 'animals2.names.name_1',
483
- 'unique': true,
518
+ },
484
519
  }, {
485
- 'key': { 'animals3.names.name': 'text' },
486
- 'name': 'text',
487
- }])
488
-
489
- db.close()
490
- })
491
-
492
- test('model array indexes', async () => {
493
- // Setup: Need to test different types of indexes
494
- let db = (await opendb(null)).db
495
- // Setup: Drop previously tested collections
496
- if ((await db._db.listCollections().toArray()).find(o => o.name == 'userIndexArray')) {
497
- await db._db.collection('userIndexArray').drop()
520
+ dryRun: true,
498
521
  }
499
- // Run
500
- let userModel = await db.model('userIndexArray', {
501
- fields: {}
502
- })
503
- await expect(userModel._setupIndexes(
504
- {
505
- animals: [{
522
+ )).resolves.toEqual([{
523
+ 'key': { 'animals.name': 1 },
524
+ 'name': 'animals.name_1',
525
+ 'unique': true,
526
+ }, {
527
+ 'key': { 'animals2.names.name': 1 },
528
+ 'name': 'animals2.names.name_1',
529
+ 'unique': true,
530
+ }, {
531
+ 'key': { 'animals3.names.name': 'text' },
532
+ 'name': 'text',
533
+ }])
534
+ })
535
+
536
+ test('model array indexes', async () => {
537
+ // Setup: Need to test different types of indexes
538
+ // Setup: Drop previously tested collections
539
+ if ((await db.db.listCollections().toArray()).find(o => o.name == 'userIndexArray')) {
540
+ await db.db.collection('userIndexArray').drop()
541
+ }
542
+ // Run
543
+ let userModel = await db.model('userIndexArray', {
544
+ fields: {},
545
+ })
546
+ await expect(userModel._setupIndexes(
547
+ {
548
+ animals: [{
549
+ name: { type: 'string', index: 'unique' },
550
+ }],
551
+ animals2: [{ type: 'string', index: true }],
552
+ animals3: [[{ type: 'string', index: true }]],
553
+ animals4: [{
554
+ names: [{
506
555
  name: { type: 'string', index: 'unique' },
507
556
  }],
508
- animals2: [{ type: 'string', index: true }],
509
- animals3: [[{ type: 'string', index: true }]],
510
- animals4: [{
511
- names: [{
512
- name: { type: 'string', index: 'unique' },
513
- }],
514
- }],
515
- }, {
516
- dryRun: true
517
- }
518
- )).resolves.toEqual([{
519
- 'key': { 'animals.name': 1 },
520
- 'name': 'animals.name_1',
521
- 'unique': true,
557
+ }],
522
558
  }, {
523
- 'key': { 'animals2': 1 },
524
- 'name': 'animals2_1',
525
- }, {
526
- 'key': { 'animals3.0': 1 },
527
- 'name': 'animals3.0_1',
528
- }, {
529
- 'key': { 'animals4.names.name': 1 },
530
- 'name': 'animals4.names.name_1',
531
- 'unique': true,
532
- }])
533
-
534
- db.close()
535
- })
536
-
537
- test('model 2dsphere indexes', async () => {
538
- // Setup. The tested model needs to be unique as race condition issue arises when the same model
539
- // with text indexes are setup at the same time
540
- let db = (await opendb(null)).db
541
- await db.model('user3', {
542
- waitForIndexes: true,
543
- fields: {
544
- location: {
545
- index: '2dsphere',
546
- type: { type: 'string', default: 'Point' },
547
- coordinates: [{ type: 'number' }] // lat, lng
548
- },
549
- location2: {
550
- index: { type: '2dsphere' }, // opts...
551
- type: { type: 'string', default: 'Point' },
552
- coordinates: [{ type: 'number' }] // lat, lng
553
- }
554
- }
555
- })
556
-
557
- // Schema check
558
- expect(db.user3.fields.location).toEqual({
559
- type: { type: 'string', default: 'Point', isString: true },
560
- coordinates: expect.any(Array),
561
- schema: {
562
- default: undefined,
559
+ dryRun: true,
560
+ }
561
+ )).resolves.toEqual([{
562
+ 'key': { 'animals.name': 1 },
563
+ 'name': 'animals.name_1',
564
+ 'unique': true,
565
+ }, {
566
+ 'key': { 'animals2': 1 },
567
+ 'name': 'animals2_1',
568
+ }, {
569
+ 'key': { 'animals3.0': 1 },
570
+ 'name': 'animals3.0_1',
571
+ }, {
572
+ 'key': { 'animals4.names.name': 1 },
573
+ 'name': 'animals4.names.name_1',
574
+ 'unique': true,
575
+ }])
576
+ })
577
+
578
+ test('model 2dsphere indexes', async () => {
579
+ // Setup. The tested model needs to be unique as race condition issue arises when the same model
580
+ // with text indexes are setup at the same time
581
+ await db.model('user99', {
582
+ waitForIndexes: true,
583
+ fields: {
584
+ location: {
563
585
  index: '2dsphere',
564
- isObject: true,
565
- nullObject: undefined,
566
- type: 'object'
567
- }
568
- })
569
- expect(db.user3.fields.location2).toEqual({
570
- type: { type: 'string', default: 'Point', isString: true },
571
- coordinates: expect.any(Array),
572
- schema: {
573
- default: undefined,
574
- index: { type: '2dsphere' },
575
- isObject: true,
576
- nullObject: undefined,
577
- type: 'object'
578
- }
579
- })
580
-
581
- // Insert 2dsphere point data
582
- await expect(db.user3.insert({
583
- data: {
584
- location: { coordinates: [172.5880385, -43.3311608] }
585
- }
586
- })).resolves.toEqual({
587
- _id: expect.any(Object),
588
- location: {
589
- coordinates: [172.5880385, -43.3311608],
590
- type: 'Point'
591
- },
592
- })
593
- // Insert no 2dsphere point data
594
- await expect(db.user3.insert({
595
- data: {}
596
- })).resolves.toEqual({
597
- _id: expect.any(Object),
598
- })
599
- // Insert bad 2dsphere point data
600
- let MongoError = require('mongodb').MongoError
601
- let id = db.id()
602
- await expect(db.user3.insert({
603
- data: { _id: id, location: {} },
604
- blacklist: ['-_id'],
605
- })).rejects.toEqual(
606
- new MongoError(
607
- `Can't extract geo keys: { _id: ObjectId('${String(id)}'), location: { type: "Point" } }` +
608
- ' Point must be an array or object'
609
- )
610
- )
586
+ type: { type: 'string', default: 'Point' },
587
+ coordinates: [{ type: 'number' }], // lat, lng
588
+ },
589
+ location2: {
590
+ index: { type: '2dsphere' }, // opts...
591
+ type: { type: 'string', default: 'Point' },
592
+ coordinates: [{ type: 'number' }], // lat, lng
593
+ },
594
+ },
595
+ })
611
596
 
612
- db.close()
597
+ // Schema check
598
+ expect(db.user99.fields.location).toEqual({
599
+ type: { type: 'string', default: 'Point', isString: true },
600
+ coordinates: expect.any(Array),
601
+ schema: {
602
+ default: undefined,
603
+ index: '2dsphere',
604
+ isObject: true,
605
+ nullObject: undefined,
606
+ type: 'object',
607
+ },
608
+ })
609
+ expect(db.user99.fields.location2).toEqual({
610
+ type: { type: 'string', default: 'Point', isString: true },
611
+ coordinates: expect.any(Array),
612
+ schema: {
613
+ default: undefined,
614
+ index: { type: '2dsphere' },
615
+ isObject: true,
616
+ nullObject: undefined,
617
+ type: 'object',
618
+ },
613
619
  })
614
620
 
615
- }
621
+ // Insert 2dsphere point data
622
+ await expect(db.user99.insert({
623
+ data: {
624
+ location: { coordinates: [172.5880385, -43.3311608] },
625
+ },
626
+ })).resolves.toEqual({
627
+ _id: expect.any(Object),
628
+ createdAt: expect.any(Number),
629
+ location: {
630
+ coordinates: [172.5880385, -43.3311608],
631
+ type: 'Point',
632
+ },
633
+ updatedAt: expect.any(Number),
634
+ })
635
+ // Insert no 2dsphere point data
636
+ await expect(db.user99.insert({
637
+ data: {},
638
+ })).resolves.toEqual({
639
+ _id: expect.any(Object),
640
+ createdAt: expect.any(Number),
641
+ updatedAt: expect.any(Number),
642
+ })
643
+ // Insert bad 2dsphere point data
644
+ let id = db.id()
645
+ await expect(db.user99.insert({
646
+ data: { _id: id, location: {} },
647
+ blacklist: ['-_id'],
648
+ })).rejects.toThrow(
649
+ new RegExp(
650
+ `Can't extract geo keys: { _id: ObjectId\\('${String(id)}'\\), createdAt: [0-9]+, updatedAt: [0-9]+, ` +
651
+ 'location: { type: "Point" } } Point must be an array or object'
652
+ )
653
+ )
654
+ })