monastery 3.2.1 → 3.4.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/test/crud.js CHANGED
@@ -337,41 +337,112 @@ test('find default field blacklisted', async () => {
337
337
  })
338
338
  })
339
339
 
340
- test('find default field population with noDefaults', async () => {
341
- // similar to "find default field population"
342
- db.model('user', {
343
- fields: {
344
- name: { type: 'string', default: 'Martin Luther' },
345
- addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
346
- address: { country: { type: 'string', default: 'Germany' }},
347
- pet: { dog: { model: 'dog' }},
348
- pets: { dog: [{ model: 'dog' }]},
349
- dogs: [{ model: 'dog' }], // virtual association
350
- },
340
+ test('find default field population with option noDefaults', async () => {
341
+ async function setup(noDefaults) {
342
+ /**
343
+ * Setup
344
+ * @returns {Object} {dog, user, dog1Doc, dog2Doc, user1Doc}
345
+ */
346
+ // similar to "find default field population"
347
+ const db = monastery('127.0.0.1/monastery', { noDefaults: noDefaults, timestamps: false })
348
+ const userDefinition = {
349
+ fields: {
350
+ name: { type: 'string', default: 'Martin Luther' },
351
+ addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
352
+ address: { country: { type: 'string', default: 'Germany' }},
353
+ pet: { dog: { model: 'dog' }},
354
+ pets: { dog: [{ model: 'dog' }]},
355
+ dogs: [{ model: 'dog' }], // virtual association
356
+ },
357
+ }
358
+ const dogDefinition = {
359
+ fields: {
360
+ name: { type: 'string', default: 'Scruff' },
361
+ user: { model: 'user' },
362
+ },
363
+ }
364
+ const user = db.model('user', userDefinition)
365
+ const dog = db.model('dog', dogDefinition)
366
+
367
+ // Default field population test
368
+ // Insert documents (without defaults)
369
+ let dog1Doc = await dog._insert({})
370
+ let dog2Doc = await dog._insert({})
371
+ let user1Doc = await user._insert({
372
+ addresses: [
373
+ { city: 'Frankfurt' },
374
+ { city: 'Christchurch', country: 'New Zealand' },
375
+ ],
376
+ pet: { dog: dog1Doc._id },
377
+ pets: { dog: [dog1Doc._id, dog2Doc._id]},
378
+ })
379
+ await dog._update(dog1Doc._id, { $set: { user: user1Doc._id }})
380
+ return { db, dog, user, dog1Doc, dog2Doc, user1Doc }
381
+ }
382
+
383
+ const s1 = await setup()
384
+
385
+ // Test noDefaults = true
386
+ const find1 = await s1.db.user.findOne({
387
+ query: s1.user1Doc._id,
388
+ populate: ['pet.dog', 'pets.dog', {
389
+ from: 'dog',
390
+ localField: '_id',
391
+ foreignField: 'user',
392
+ as: 'dogs',
393
+ }],
394
+ noDefaults: true,
351
395
  })
352
- db.model('dog', {
353
- fields: {
354
- name: { type: 'string', default: 'Scruff' },
355
- user: { model: 'user' },
396
+ expect(find1).toEqual({
397
+ _id: s1.user1Doc._id,
398
+ addresses: [
399
+ { city: 'Frankfurt' },
400
+ { city: 'Christchurch', country: 'New Zealand' },
401
+ ],
402
+ pet: { dog: { _id: s1.dog1Doc._id, user: s1.user1Doc._id }},
403
+ pets: {
404
+ dog: [
405
+ { _id: s1.dog1Doc._id, user: s1.user1Doc._id },
406
+ { _id: s1.dog2Doc._id },
407
+ ],
356
408
  },
409
+ dogs: [{ _id: s1.dog1Doc._id, user: s1.user1Doc._id }],
357
410
  })
358
411
 
359
- // Default field population test
360
- // Insert documents (without defaults)
361
- let dog1 = await db.dog._insert({})
362
- let dog2 = await db.dog._insert({})
363
- let user1 = await db.user._insert({
412
+ // Test noDefaults = ['dogs', 'pet.dog']
413
+ const find2 = await s1.db.user.findOne({
414
+ query: s1.user1Doc._id,
415
+ populate: ['pet.dog', 'pets.dog', {
416
+ from: 'dog',
417
+ localField: '_id',
418
+ foreignField: 'user',
419
+ as: 'dogs',
420
+ }],
421
+ noDefaults: ['dogs', 'pet.dog'],
422
+ })
423
+ expect(find2).toEqual({
424
+ _id: s1.user1Doc._id,
425
+ name: 'Martin Luther',
364
426
  addresses: [
365
- { city: 'Frankfurt' },
427
+ { city: 'Frankfurt', country: 'Germany' },
366
428
  { city: 'Christchurch', country: 'New Zealand' },
367
429
  ],
368
- pet: { dog: dog1._id },
369
- pets: { dog: [dog1._id, dog2._id]},
430
+ address: { country: 'Germany' },
431
+ pet: { dog: { _id: s1.dog1Doc._id, user: s1.user1Doc._id }}, // should not have a default name
432
+ pets: {
433
+ dog: [
434
+ { _id: s1.dog1Doc._id, name: 'Scruff', user: s1.user1Doc._id },
435
+ { _id: s1.dog2Doc._id, name: 'Scruff' },
436
+ ],
437
+ },
438
+ dogs: [{ _id: s1.dog1Doc._id, user: s1.user1Doc._id }], // should not have a default name
370
439
  })
371
- await db.dog._update(dog1._id, { $set: { user: user1._id }})
372
440
 
373
- let find1 = await db.user.findOne({
374
- query: user1._id,
441
+ const s2 = await setup(['dogs'])
442
+
443
+ // Test noDefaults = true overrides manager option noDefaults = ['dogs']
444
+ const find3 = await s2.db.user.findOne({
445
+ query: s2.user1Doc._id,
375
446
  populate: ['pet.dog', 'pets.dog', {
376
447
  from: 'dog',
377
448
  localField: '_id',
@@ -380,50 +451,48 @@ test('find default field population with noDefaults', async () => {
380
451
  }],
381
452
  noDefaults: true,
382
453
  })
383
-
384
- expect(find1).toEqual({
385
- _id: user1._id,
454
+ expect(find3).toEqual({
455
+ _id: s2.user1Doc._id,
386
456
  addresses: [
387
457
  { city: 'Frankfurt' },
388
458
  { city: 'Christchurch', country: 'New Zealand' },
389
459
  ],
390
- pet: { dog: { _id: dog1._id, user: user1._id }},
460
+ pet: { dog: { _id: s2.dog1Doc._id, user: s2.user1Doc._id }},
391
461
  pets: {
392
462
  dog: [
393
- { _id: dog1._id, user: user1._id },
394
- { _id: dog2._id },
463
+ { _id: s2.dog1Doc._id, user: s2.user1Doc._id },
464
+ { _id: s2.dog2Doc._id },
395
465
  ],
396
466
  },
397
- dogs: [{ _id: dog1._id, user: user1._id }],
467
+ dogs: [{ _id: s2.dog1Doc._id, user: s2.user1Doc._id }],
398
468
  })
399
469
 
400
- let find2 = await db.user.findOne({
401
- query: user1._id,
470
+ // Test manager option noDefaults = ['dogs']
471
+ const find4 = await s2.db.user.findOne({
472
+ query: s2.user1Doc._id,
402
473
  populate: ['pet.dog', 'pets.dog', {
403
474
  from: 'dog',
404
475
  localField: '_id',
405
476
  foreignField: 'user',
406
477
  as: 'dogs',
407
478
  }],
408
- noDefaults: ['dogs', 'pet.dog'],
409
479
  })
410
-
411
- expect(find2).toEqual({
412
- _id: user1._id,
480
+ expect(find4).toEqual({
481
+ _id: s2.user1Doc._id,
413
482
  name: 'Martin Luther',
414
483
  addresses: [
415
484
  { city: 'Frankfurt', country: 'Germany' },
416
485
  { city: 'Christchurch', country: 'New Zealand' },
417
486
  ],
418
487
  address: { country: 'Germany' },
419
- pet: { dog: { _id: dog1._id, user: user1._id }},
488
+ pet: { dog: { _id: s2.dog1Doc._id, user: s2.user1Doc._id, name: 'Scruff' }},
420
489
  pets: {
421
490
  dog: [
422
- { _id: dog1._id, name: 'Scruff', user: user1._id },
423
- { _id: dog2._id, name: 'Scruff' },
491
+ { _id: s2.dog1Doc._id, name: 'Scruff', user: s2.user1Doc._id },
492
+ { _id: s2.dog2Doc._id, name: 'Scruff' },
424
493
  ],
425
494
  },
426
- dogs: [{ _id: dog1._id, user: user1._id }],
495
+ dogs: [{ _id: s2.dog1Doc._id, user: s2.user1Doc._id }], // should not have a default name
427
496
  })
428
497
  })
429
498
 
@@ -594,7 +663,7 @@ test('update operators', async () => {
594
663
  expect(beforeValidateHookCalled).toEqual(false)
595
664
  })
596
665
 
597
- test('update mixing formData', async() => {
666
+ test('update mixing data structures (bracket notation and objects)', async() => {
598
667
  // Mixing data
599
668
  let consignment = db.model('consignment', {
600
669
  fields: {
@@ -1304,4 +1373,131 @@ test('hooks > async and next conflict', async () => {
1304
1373
  expect(logSpy).toHaveBeenCalledWith('Monastery user.afterFind error: you cannot return a promise AND call next()')
1305
1374
 
1306
1375
  db2.close()
1376
+ })
1377
+
1378
+ test('hooks > option skipHooks', async () => {
1379
+ let user = db.model('user_crud_skiphooks', {
1380
+ fields: {
1381
+ name: { type: 'string' },
1382
+ },
1383
+ beforeInsert: [async (data) => {
1384
+ data.name = 'Hooked ' + data.name
1385
+ return data
1386
+ }],
1387
+ beforeUpdate: [async (data) => {
1388
+ data.name = 'Hooked ' + data.name
1389
+ return data
1390
+ }],
1391
+ })
1392
+
1393
+ // Insert with hooks
1394
+ let inserted = await user.insert({ data: { name: 'Martin Luther' } })
1395
+ expect(inserted).toEqual({
1396
+ _id: expect.any(Object),
1397
+ name: 'Hooked Martin Luther',
1398
+ })
1399
+
1400
+ // Update with hooks (use $set in this case)
1401
+ let updated = await user.update({
1402
+ query: inserted._id,
1403
+ $set: { name: 'Updated Name' },
1404
+ })
1405
+ expect(updated).toEqual({
1406
+ name: 'Hooked Updated Name',
1407
+ })
1408
+
1409
+ // Insert with skipHooks option
1410
+ let insertedSkipHooks = await user.insert({
1411
+ data: { name: 'Skipped Hooks Name' },
1412
+ skipHooks: true,
1413
+ })
1414
+ expect(insertedSkipHooks).toEqual({
1415
+ _id: expect.any(Object),
1416
+ name: 'Skipped Hooks Name',
1417
+ })
1418
+
1419
+ // Update with skipHooks option
1420
+ let updatedSkipHooks = await user.update({
1421
+ query: inserted._id,
1422
+ $set: { name: 'Skipped Hooks Name Updated' },
1423
+ skipHooks: true,
1424
+ })
1425
+ expect(updatedSkipHooks).toEqual({
1426
+ name: 'Skipped Hooks Name Updated',
1427
+ })
1428
+ })
1429
+
1430
+ test('update set and unset with option skipValidation', async () => {
1431
+ const db2 = monastery('127.0.0.1/monastery', { timestamps: false })
1432
+ let user = db2.model('user_set_and_unset', {
1433
+ fields: {
1434
+ profile: {
1435
+ name: { type: 'string', required: true },
1436
+ age: { type: 'number' },
1437
+ },
1438
+ },
1439
+ })
1440
+
1441
+ // Insert a document to update
1442
+ let inserted = await user.insert({ data: { profile: { name: 'John Doe', age: 30 } } })
1443
+ let userId = inserted._id
1444
+ let error = (detail, title) => [{
1445
+ detail: detail,
1446
+ title: title || expect.any(String),
1447
+ meta: expect.any(Object),
1448
+ status: '400',
1449
+ }]
1450
+
1451
+ // --- $set/data ---
1452
+
1453
+ // $set with skipValidation: undefined (true)
1454
+ const u1 = { query: userId, $set: { 'profile.age': 'not a number' } }
1455
+ await expect(user.update(u1)).resolves.toEqual({ 'profile.age': 'not a number' })
1456
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: { name: 'John Doe', age: 'not a number' } })
1457
+
1458
+ // data with skipValidation: undefined (false)
1459
+ const u11 = { query: userId, data: { 'profile.age': 'not a number' } }
1460
+ await expect(user.update(u11)).rejects.toEqual(error('Value was not a number.', 'profile.age'))
1461
+
1462
+ for (let key of ['$set', 'data']) {
1463
+ // $set with skipValidation: true
1464
+ const u2 = { query: userId, [key]: { 'profile.age': 'not a number2' }, skipValidation: true }
1465
+ await expect(user.update(u2)).resolves.toEqual({ 'profile.age': 'not a number2' })
1466
+
1467
+ // $set with skipValidation: false
1468
+ const u3 = { query: userId, [key]: { 'profile.age': '8' }, skipValidation: false }
1469
+ await expect(user.update(u3)).resolves.toEqual({ 'profile.age': 8 })
1470
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: { name: 'John Doe', age: 8 } })
1471
+
1472
+ // $set error with skipValidation: false
1473
+ const u4 = { query: userId, [key]: { 'profile.age': 'not a number' }, skipValidation: false }
1474
+ await expect(user.update(u4)).rejects.toEqual(error('Value was not a number.', 'profile.age'))
1475
+
1476
+ // $set error with skipValidation: ['profile']
1477
+ const u6 = { query: userId, [key]: { 'profile.age': 'not a number4' }, skipValidation: ['profile'] }
1478
+ await expect(user.update(u6)).resolves.toEqual({ 'profile.age': 'not a number4' })
1479
+ }
1480
+
1481
+ // --- $unset ---
1482
+
1483
+ // $unset with skipValidation: undefined
1484
+ const u7 = { query: userId, $unset: { 'profile.age': '' } }
1485
+ await expect(user.update(u7)).resolves.toEqual({}) // returns empty object
1486
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: { name: 'John Doe' } })
1487
+
1488
+ // $unset error with skipValidation: false
1489
+ const u9 = { query: userId, $unset: { 'profile.name': '' }, skipValidation: false }
1490
+ await expect(user.update(u9)).rejects.toEqual(error('This field is required.', 'profile.name'))
1491
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: { name: 'John Doe' } })
1492
+
1493
+ // $unset error with skipValidation: ['profile.name']
1494
+ const u10 = { query: userId, $unset: { 'profile.name': '' }, skipValidation: ['profile.name'] }
1495
+ await expect(user.update(u10)).resolves.toEqual({}) // returns empty object
1496
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: {} }) /////////unseeeet
1497
+
1498
+ // $unset with skipValidation: true
1499
+ await expect(user.update({ query: userId, $set: { 'profile.name': 'John Doe2' } })) // add age back
1500
+ const u8 = { query: userId, $unset: { 'profile.name': '' }, skipValidation: true }
1501
+ await expect(user.update(u8)).resolves.toEqual({})
1502
+ await expect(user.findOne(userId)).resolves.toEqual({ _id: userId, profile: {} })
1307
1503
  })
package/test/util.js CHANGED
@@ -1,32 +1,247 @@
1
1
  const util = require('../lib/util.js')
2
2
  const monastery = require('../lib/index.js')
3
3
 
4
- test('util > formdata', async () => {
5
- expect(await util.parseFormData({
4
+ test('util > parseDotNotation', async () => {
5
+ const input = {
6
6
  'name': 'Martin',
7
- 'pets[]': '',
8
- 'deep[companyLogo]': 'a',
9
- 'deep[companyLogos][0]': 'b',
10
- 'deep[companyLogos2][0][logo]':'c',
11
- 'deep[companyLogos2][1][logo]': '',
12
- 'users[0][first]': 'Martin',
13
- 'users[0][last]': 'Luther',
14
- 'users[1][first]': 'Bruce',
15
- 'users[1][last]': 'Lee',
16
- })).toEqual({
7
+ 'deep.companyLogo1': 'a',
8
+ // not dot notation
9
+ 'specialInstructions': [
10
+ {
11
+ text: 'POD added by driver',
12
+ createdAt: 1653603212886,
13
+ updatedByName: 'Paul Driver 3',
14
+ importance: 'low',
15
+ }, {
16
+ text: 'filler',
17
+ createdAt: 1653601752472,
18
+ updatedByName: 'Paul',
19
+ importance: 'low',
20
+ },
21
+ ],
22
+ // Fields below are not dot notation, but should still be kept, in order.
23
+ 'specialInstructions[0][text]': 'filler',
24
+ 'specialInstructions[0][createdAt]': 1653601752472,
25
+ 'specialInstructions[0][updatedByName]': 'Paul',
26
+ 'specialInstructions[0][importance]': 'low',
27
+ // should override above
28
+ 'deep': {
29
+ companyLogo2: 'b',
30
+ companyLogo3: 'b',
31
+ },
32
+ // should be added into above
33
+ 'deep.companyLogo3': 'c',
34
+ 'deep.companyLogos.0.logo': 'd',
35
+ 'deep.companyLogos.1.logo': 'e',
36
+ 'deep.companyLogos.2': 'f',
37
+ }
38
+ const output = {
17
39
  name: 'Martin',
18
- pets: expect.any(Array),
19
- deep: {
20
- companyLogo: 'a',
21
- companyLogos: ['b'],
22
- companyLogos2: [{ logo: 'c' }, { logo: '' }],
40
+ deep: { // object first seen here
41
+ companyLogo2: 'b',
42
+ companyLogo3: 'c',
43
+ companyLogos: [{ logo: 'd' }, { logo: 'e' }, 'f'],
23
44
  },
24
- users: [
25
- { 'first': 'Martin', 'last': 'Luther' },
26
- { 'first': 'Bruce', 'last': 'Lee' },
45
+ specialInstructions: [
46
+ {
47
+ text: 'POD added by driver',
48
+ createdAt: 1653603212886,
49
+ updatedByName: 'Paul Driver 3',
50
+ importance: 'low',
51
+ }, {
52
+ text: 'filler',
53
+ createdAt: 1653601752472,
54
+ updatedByName: 'Paul',
55
+ importance: 'low',
56
+ },
27
57
  ],
28
- })
29
- expect(() => util.parseFormData({ 'users[][\'name\']': 'Martin' })).toThrow(
58
+ 'specialInstructions[0][text]': 'filler',
59
+ 'specialInstructions[0][createdAt]': 1653601752472,
60
+ 'specialInstructions[0][updatedByName]': 'Paul',
61
+ 'specialInstructions[0][importance]': 'low',
62
+ }
63
+
64
+ // parseDotNotation output
65
+ expect(util.parseDotNotation(input)).toEqual(output)
66
+
67
+ // expected order of keys
68
+ expect(Object.keys(output)).toEqual([
69
+ 'name',
70
+ 'deep',
71
+ 'specialInstructions',
72
+ 'specialInstructions[0][text]',
73
+ 'specialInstructions[0][createdAt]',
74
+ 'specialInstructions[0][updatedByName]',
75
+ 'specialInstructions[0][importance]',
76
+ ])
77
+
78
+ })
79
+
80
+ test('util > parseBracketNotation', async () => {
81
+ const input = {
82
+ 'name': 'Martin',
83
+ // 'pets[]': '', // <-- no longer supported
84
+ 'deep[companyLogo1]': 'a',
85
+ // not dot notation
86
+ 'specialInstructions': [
87
+ {
88
+ text: 'POD added by driver',
89
+ createdAt: 1653603212886,
90
+ updatedByName: 'Paul Driver 3',
91
+ importance: 'low',
92
+ }, {
93
+ text: 'filler',
94
+ createdAt: 1653601752472,
95
+ updatedByName: 'Paul',
96
+ importance: 'low',
97
+ },
98
+ ],
99
+ // Fields below are not bracket notation, but should still be kept, in order.
100
+ 'specialInstructions.0.text': 'filler',
101
+ 'specialInstructions.0.createdAt': 1653601752472,
102
+ 'specialInstructions.0.updatedByName': 'Paul',
103
+ 'specialInstructions.0.importance': 'low',
104
+ // should override above
105
+ 'deep': {
106
+ companyLogo2: 'b',
107
+ companyLogo3: 'b',
108
+ },
109
+ // should be added into above
110
+ 'deep[companyLogo3]': 'c',
111
+ 'deep[companyLogos][0][logo]': 'd',
112
+ 'deep[companyLogos][1][logo]': 'e',
113
+ 'deep[companyLogos][2]': 'f',
114
+ }
115
+ const output = {
116
+ name: 'Martin',
117
+ // pets: expect.any(Array),
118
+ deep: { // object first seen here
119
+ companyLogo2: 'b',
120
+ companyLogo3: 'c',
121
+ companyLogos: [{ logo: 'd' }, { logo: 'e' }, 'f'],
122
+ },
123
+ specialInstructions: [
124
+ {
125
+ text: 'POD added by driver',
126
+ createdAt: 1653603212886,
127
+ updatedByName: 'Paul Driver 3',
128
+ importance: 'low',
129
+ }, {
130
+ text: 'filler',
131
+ createdAt: 1653601752472,
132
+ updatedByName: 'Paul',
133
+ importance: 'low',
134
+ },
135
+ ],
136
+ 'specialInstructions.0.text': 'filler',
137
+ 'specialInstructions.0.createdAt': 1653601752472,
138
+ 'specialInstructions.0.updatedByName': 'Paul',
139
+ 'specialInstructions.0.importance': 'low',
140
+ }
141
+
142
+ // parseBracketNotation output
143
+ expect(util.parseBracketNotation(input)).toEqual(output)
144
+
145
+ // expected order of keys
146
+ expect(Object.keys(output)).toEqual([
147
+ 'name',
148
+ 'deep',
149
+ 'specialInstructions',
150
+ 'specialInstructions.0.text',
151
+ 'specialInstructions.0.createdAt',
152
+ 'specialInstructions.0.updatedByName',
153
+ 'specialInstructions.0.importance',
154
+ ])
155
+
156
+ expect(() => util.parseBracketNotation({ 'users[][\'name\']': 'Martin' })).toThrow(
157
+ 'Monastery: Array items in bracket notation need array indexes "users[][\'name\']", e.g. users[0][name]'
158
+ )
159
+ })
160
+
161
+ test('util > parseBracketToDotNotation', async () => {
162
+ const input = {
163
+ 'name': 'Martin',
164
+ 'deep[companyLogo1]': 'a',
165
+ // not dot notation
166
+ 'specialInstructions': [
167
+ {
168
+ text: 'POD added by driver',
169
+ createdAt: 1653603212886,
170
+ updatedByName: 'Paul Driver 3',
171
+ importance: 'low',
172
+ }, {
173
+ text: 'filler',
174
+ createdAt: 1653601752472,
175
+ updatedByName: 'Paul',
176
+ importance: 'low',
177
+ },
178
+ ],
179
+ // Fields below are not bracket notation, but should still be kept, in order.
180
+ 'specialInstructions.0.text': 'filler',
181
+ 'specialInstructions.0.createdAt': 1653601752472,
182
+ 'specialInstructions.0.updatedByName': 'Paul',
183
+ 'specialInstructions.0.importance': 'low',
184
+ // should NOT override above
185
+ 'deep': {
186
+ companyLogo2: 'b',
187
+ companyLogo3: 'b',
188
+ },
189
+ // should NOT be added into above
190
+ 'deep[companyLogo3]': 'c',
191
+ 'deep[companyLogos][0][logo]': 'd',
192
+ 'deep[companyLogos][1][logo]': 'e',
193
+ 'deep[companyLogos][2]': 'f',
194
+ }
195
+ const output = {
196
+ name: 'Martin',
197
+ 'deep.companyLogo1': 'a',
198
+ specialInstructions: [
199
+ {
200
+ text: 'POD added by driver',
201
+ createdAt: 1653603212886,
202
+ updatedByName: 'Paul Driver 3',
203
+ importance: 'low',
204
+ }, {
205
+ text: 'filler',
206
+ createdAt: 1653601752472,
207
+ updatedByName: 'Paul',
208
+ importance: 'low',
209
+ },
210
+ ],
211
+ 'specialInstructions.0.text': 'filler',
212
+ 'specialInstructions.0.createdAt': 1653601752472,
213
+ 'specialInstructions.0.updatedByName': 'Paul',
214
+ 'specialInstructions.0.importance': 'low',
215
+ 'deep': {
216
+ companyLogo2: 'b',
217
+ companyLogo3: 'b',
218
+ },
219
+ 'deep.companyLogo3': 'c',
220
+ 'deep.companyLogos.0.logo': 'd',
221
+ 'deep.companyLogos.1.logo': 'e',
222
+ 'deep.companyLogos.2': 'f',
223
+ }
224
+
225
+ // parseBracketToDotNotation output
226
+ expect(util.parseBracketToDotNotation(input)).toEqual(output)
227
+
228
+ // expected order of keys
229
+ expect(Object.keys(output)).toEqual([
230
+ 'name',
231
+ 'deep.companyLogo1',
232
+ 'specialInstructions',
233
+ 'specialInstructions.0.text',
234
+ 'specialInstructions.0.createdAt',
235
+ 'specialInstructions.0.updatedByName',
236
+ 'specialInstructions.0.importance',
237
+ 'deep',
238
+ 'deep.companyLogo3',
239
+ 'deep.companyLogos.0.logo',
240
+ 'deep.companyLogos.1.logo',
241
+ 'deep.companyLogos.2',
242
+ ])
243
+
244
+ expect(() => util.parseBracketToDotNotation({ 'users[][\'name\']': 'Martin' })).toThrow(
30
245
  'Monastery: Array items in bracket notation need array indexes "users[][\'name\']", e.g. users[0][name]'
31
246
  )
32
247
  })