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/.eslintrc.json +1 -1
- package/changelog.md +4 -0
- package/docs/manager/index.md +5 -4
- package/docs/readme.md +4 -2
- package/lib/index.js +15 -3
- package/lib/model-crud.js +128 -88
- package/lib/model-validate.js +131 -97
- package/lib/model.js +15 -0
- package/lib/util.js +101 -72
- package/package.json +1 -1
- package/test/crud.js +240 -44
- package/test/util.js +237 -22
- package/test/validate.js +87 -3
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
369
|
-
|
|
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
|
-
|
|
374
|
-
|
|
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
|
-
|
|
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:
|
|
460
|
+
pet: { dog: { _id: s2.dog1Doc._id, user: s2.user1Doc._id }},
|
|
391
461
|
pets: {
|
|
392
462
|
dog: [
|
|
393
|
-
{ _id:
|
|
394
|
-
{ _id:
|
|
463
|
+
{ _id: s2.dog1Doc._id, user: s2.user1Doc._id },
|
|
464
|
+
{ _id: s2.dog2Doc._id },
|
|
395
465
|
],
|
|
396
466
|
},
|
|
397
|
-
dogs: [{ _id:
|
|
467
|
+
dogs: [{ _id: s2.dog1Doc._id, user: s2.user1Doc._id }],
|
|
398
468
|
})
|
|
399
469
|
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
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:
|
|
488
|
+
pet: { dog: { _id: s2.dog1Doc._id, user: s2.user1Doc._id, name: 'Scruff' }},
|
|
420
489
|
pets: {
|
|
421
490
|
dog: [
|
|
422
|
-
{ _id:
|
|
423
|
-
{ _id:
|
|
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:
|
|
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
|
|
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 >
|
|
5
|
-
|
|
4
|
+
test('util > parseDotNotation', async () => {
|
|
5
|
+
const input = {
|
|
6
6
|
'name': 'Martin',
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
companyLogos: ['
|
|
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
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
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
|
-
|
|
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
|
})
|