@squiz/db-lib 1.71.3 → 1.73.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.
@@ -193,13 +193,11 @@ describe('AbstractRepository', () => {
193
193
  },
194
194
  ConditionExpression: `attribute_exists(pk)`,
195
195
  };
196
- const partialItemWithKeyFields = {
197
- name: 'foo',
198
- };
199
196
  const updateItem = {
197
+ name: 'foo',
200
198
  country: 'au-updated',
201
199
  };
202
- const result = await repository.updateItem(partialItemWithKeyFields, updateItem);
200
+ const result = await repository.updateItem(updateItem);
203
201
  expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.UpdateCommand, input);
204
202
  expect(result).toEqual(new TestItem({
205
203
  name: 'foo',
@@ -208,19 +206,43 @@ describe('AbstractRepository', () => {
208
206
  data: {},
209
207
  }));
210
208
  });
211
- it('should undefined if item does does not exist', async () => {
209
+ it('should not trigger update request if the input attributes are same as in the existing item', async () => {
212
210
  ddbClientMock.on(lib_dynamodb_1.GetCommand).resolves({
213
211
  $metadata: {
214
212
  httpStatusCode: 200,
215
213
  },
214
+ Item: {
215
+ name: 'foo',
216
+ age: 99,
217
+ country: 'au',
218
+ data: {},
219
+ },
216
220
  });
217
- const partialItemWithKeyFields = {
221
+ ddbClientMock.on(lib_dynamodb_1.UpdateCommand).rejects(new Error('updateItem() called when not expected'));
222
+ // update input attributes are same as in the existing item
223
+ const updateItem = {
218
224
  name: 'foo',
225
+ country: 'au',
219
226
  };
227
+ const result = await repository.updateItem(updateItem);
228
+ expect(result).toEqual(new TestItem({
229
+ name: 'foo',
230
+ age: 99,
231
+ country: 'au',
232
+ data: {},
233
+ }));
234
+ });
235
+ it('should return undefined if item does does not exist', async () => {
236
+ ddbClientMock.on(lib_dynamodb_1.GetCommand).resolves({
237
+ $metadata: {
238
+ httpStatusCode: 200,
239
+ },
240
+ });
220
241
  const updateItem = {
242
+ name: 'foo',
221
243
  country: 'au-updated',
222
244
  };
223
- const result = await repository.updateItem(partialItemWithKeyFields, updateItem);
245
+ const result = await repository.updateItem(updateItem);
224
246
  expect(result).toEqual(undefined);
225
247
  });
226
248
  it('should return undefined if update cmd conditional check fails', async () => {
@@ -239,13 +261,11 @@ describe('AbstractRepository', () => {
239
261
  $metadata: {},
240
262
  message: 'not found',
241
263
  }));
242
- const partialItemWithKeyFields = {
243
- name: 'foo',
244
- };
245
264
  const updateItem = {
265
+ name: 'foo',
246
266
  country: 'au-updated',
247
267
  };
248
- const result = await repository.updateItem(partialItemWithKeyFields, updateItem);
268
+ const result = await repository.updateItem(updateItem);
249
269
  expect(result).toEqual(undefined);
250
270
  });
251
271
  it('should throw error update data has invalid data', async () => {
@@ -260,13 +280,11 @@ describe('AbstractRepository', () => {
260
280
  data: {},
261
281
  },
262
282
  });
263
- const partialItemWithKeyFields = {
264
- name: 'foo',
265
- };
266
283
  const updateItem = {
284
+ name: 'foo',
267
285
  country: 61, // should be "string" type
268
286
  };
269
- await expect(repository.updateItem(partialItemWithKeyFields, updateItem)).rejects.toEqual(new Error('Invalid "country"'));
287
+ await expect(repository.updateItem(updateItem)).rejects.toEqual(new Error('Invalid "country"'));
270
288
  });
271
289
  it('should throw error if excess column in input', async () => {
272
290
  ddbClientMock.on(lib_dynamodb_1.GetCommand).resolves({
@@ -280,23 +298,19 @@ describe('AbstractRepository', () => {
280
298
  data: {},
281
299
  },
282
300
  });
283
- const partialItemWithKeyFields = {
284
- name: 'foo',
285
- };
286
301
  const updateItem = {
302
+ name: 'foo',
287
303
  country: 'au-updated',
288
304
  extra: '',
289
305
  };
290
- await expect(repository.updateItem(partialItemWithKeyFields, updateItem)).rejects.toEqual(new __1.InvalidDbSchemaError('Excess properties in entity test-item-entity: extra'));
306
+ await expect(repository.updateItem(updateItem)).rejects.toEqual(new __1.InvalidDbSchemaError('Excess properties in entity test-item-entity: extra'));
291
307
  });
292
308
  it('should throw error if input does not includes key field(s)', async () => {
293
- const partialItemWithKeyFields = {
294
- age: 99,
295
- };
296
309
  const updateItem = {
310
+ age: 99,
297
311
  country: 'au-updated', // should be "string" type
298
312
  };
299
- await expect(repository.updateItem(partialItemWithKeyFields, updateItem)).rejects.toEqual(new __1.MissingKeyValuesError('Key field "name" must be specified in the input item in entity test-item-entity'));
313
+ await expect(repository.updateItem(updateItem)).rejects.toEqual(new __1.MissingKeyValuesError('Key field "name" must be specified in the input item in entity test-item-entity'));
300
314
  });
301
315
  });
302
316
  describe('getItem()', () => {
@@ -385,6 +399,435 @@ describe('AbstractRepository', () => {
385
399
  await expect(repository.getItem(partialItem)).rejects.toEqual(new InvalidDataFormatError_1.InvalidDataFormatError(`Field 'data2' defined as JSON String has a non-string data`));
386
400
  });
387
401
  });
402
+ describe('getItems()', () => {
403
+ it('should use BatchGetItem to get result', async () => {
404
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand).resolves({
405
+ $metadata: {
406
+ httpStatusCode: 200,
407
+ },
408
+ Responses: {
409
+ [TABLE_NAME]: [
410
+ {
411
+ name: 'foo',
412
+ age: 99,
413
+ country: 'au',
414
+ data: {},
415
+ data2: '{"foo":"bar","num":123}',
416
+ },
417
+ {
418
+ name: 'foo2',
419
+ age: 999,
420
+ country: 'au',
421
+ data: {},
422
+ data2: '{"foo":"bar","num":123}',
423
+ },
424
+ ],
425
+ },
426
+ });
427
+ const input = {
428
+ RequestItems: {
429
+ [TABLE_NAME]: {
430
+ Keys: [
431
+ { pk: 'test_item#foo', sk: '#meta' },
432
+ { pk: 'test_item#foo2', sk: '#meta' },
433
+ ],
434
+ },
435
+ },
436
+ };
437
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
438
+ const result = await repository.getItems(requestItems);
439
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.BatchGetCommand, input);
440
+ expect(result).toEqual([
441
+ new TestItem({
442
+ name: 'foo',
443
+ age: 99,
444
+ country: 'au',
445
+ data: {},
446
+ data2: {
447
+ foo: 'bar',
448
+ num: 123,
449
+ },
450
+ }),
451
+ new TestItem({
452
+ name: 'foo2',
453
+ age: 999,
454
+ country: 'au',
455
+ data: {},
456
+ data2: {
457
+ foo: 'bar',
458
+ num: 123,
459
+ },
460
+ }),
461
+ ]);
462
+ });
463
+ it('should retry if unprocessed keys returned', async () => {
464
+ const input1 = {
465
+ RequestItems: {
466
+ [TABLE_NAME]: {
467
+ Keys: [
468
+ { pk: 'test_item#foo', sk: '#meta' },
469
+ { pk: 'test_item#foo2', sk: '#meta' },
470
+ ],
471
+ },
472
+ },
473
+ };
474
+ const input2 = {
475
+ RequestItems: {
476
+ [TABLE_NAME]: {
477
+ Keys: [{ pk: 'test_item#foo2', sk: '#meta' }],
478
+ },
479
+ },
480
+ };
481
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand, input1).resolves({
482
+ $metadata: {
483
+ httpStatusCode: 200,
484
+ },
485
+ Responses: {
486
+ [TABLE_NAME]: [
487
+ {
488
+ name: 'foo',
489
+ age: 99,
490
+ country: 'au',
491
+ data: {},
492
+ data2: '{"foo":"bar","num":123}',
493
+ },
494
+ ],
495
+ },
496
+ UnprocessedKeys: {
497
+ [TABLE_NAME]: {
498
+ Keys: [{ pk: 'test_item#foo2', sk: '#meta' }],
499
+ },
500
+ },
501
+ });
502
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand, input2).resolves({
503
+ $metadata: {
504
+ httpStatusCode: 200,
505
+ },
506
+ Responses: {
507
+ [TABLE_NAME]: [
508
+ {
509
+ name: 'foo2',
510
+ age: 999,
511
+ country: 'au',
512
+ data: {},
513
+ data2: '{"foo":"bar","num":123}',
514
+ },
515
+ ],
516
+ },
517
+ UnprocessedKeys: {},
518
+ });
519
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
520
+ const result = await repository.getItems(requestItems);
521
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchGetCommand, input1);
522
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchGetCommand, input2);
523
+ expect(result).toEqual([
524
+ new TestItem({
525
+ name: 'foo',
526
+ age: 99,
527
+ country: 'au',
528
+ data: {},
529
+ data2: {
530
+ foo: 'bar',
531
+ num: 123,
532
+ },
533
+ }),
534
+ new TestItem({
535
+ name: 'foo2',
536
+ age: 999,
537
+ country: 'au',
538
+ data: {},
539
+ data2: {
540
+ foo: 'bar',
541
+ num: 123,
542
+ },
543
+ }),
544
+ ]);
545
+ });
546
+ it('should fail after max retries for unprocessed keys', async () => {
547
+ const input1 = {
548
+ RequestItems: {
549
+ [TABLE_NAME]: {
550
+ Keys: [
551
+ { pk: 'test_item#foo', sk: '#meta' },
552
+ { pk: 'test_item#foo2', sk: '#meta' },
553
+ ],
554
+ },
555
+ },
556
+ };
557
+ const input2 = {
558
+ RequestItems: {
559
+ [TABLE_NAME]: {
560
+ Keys: [{ pk: 'test_item#foo2', sk: '#meta' }],
561
+ },
562
+ },
563
+ };
564
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand, input1).resolves({
565
+ $metadata: {
566
+ httpStatusCode: 200,
567
+ },
568
+ Responses: {
569
+ [TABLE_NAME]: [
570
+ {
571
+ name: 'foo',
572
+ age: 99,
573
+ country: 'au',
574
+ data: {},
575
+ data2: '{"foo":"bar","num":123}',
576
+ },
577
+ ],
578
+ },
579
+ UnprocessedKeys: {
580
+ [TABLE_NAME]: {
581
+ Keys: [{ pk: 'test_item#foo2', sk: '#meta' }],
582
+ },
583
+ },
584
+ });
585
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand, input2).resolves({
586
+ $metadata: {
587
+ httpStatusCode: 200,
588
+ },
589
+ Responses: {},
590
+ UnprocessedKeys: {
591
+ [TABLE_NAME]: {
592
+ Keys: [{ pk: 'test_item#foo2', sk: '#meta' }],
593
+ },
594
+ },
595
+ });
596
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
597
+ await expect(repository.getItems(requestItems)).rejects.toEqual(new Error('Maximum allowed retries exceeded for unprocessed items'));
598
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchGetCommand, input1);
599
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchGetCommand, input2);
600
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(3, lib_dynamodb_1.BatchGetCommand, input2);
601
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(4, lib_dynamodb_1.BatchGetCommand, input2);
602
+ });
603
+ it('should request BatchGetItem in batch of 100 items to get result', async () => {
604
+ ddbClientMock.on(lib_dynamodb_1.BatchGetCommand).resolves({
605
+ $metadata: {
606
+ httpStatusCode: 200,
607
+ },
608
+ });
609
+ const requestItems = [];
610
+ for (let i = 0; i < 120; i++) {
611
+ requestItems.push({ name: `foo${i}` });
612
+ }
613
+ // keys for first batch request
614
+ const keys1 = [];
615
+ for (let i = 0; i < 100; i++) {
616
+ keys1.push({ pk: `test_item#foo${i}`, sk: '#meta' });
617
+ }
618
+ // keys for second batch request
619
+ const keys2 = [];
620
+ for (let i = 100; i < 120; i++) {
621
+ keys2.push({ pk: `test_item#foo${i}`, sk: '#meta' });
622
+ }
623
+ const input1 = {
624
+ RequestItems: {
625
+ [TABLE_NAME]: {
626
+ Keys: keys1,
627
+ },
628
+ },
629
+ };
630
+ const input2 = {
631
+ RequestItems: {
632
+ [TABLE_NAME]: {
633
+ Keys: keys2,
634
+ },
635
+ },
636
+ };
637
+ await repository.getItems(requestItems);
638
+ expect(ddbClientMock).toHaveReceivedCommandTimes(lib_dynamodb_1.BatchGetCommand, 2);
639
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchGetCommand, input1);
640
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchGetCommand, input2);
641
+ });
642
+ it('should throw error if any input item does not includes key field(s)', async () => {
643
+ const requestItems = [{ name: 'foo' }, { age: 22 }];
644
+ await expect(repository.getItems(requestItems)).rejects.toEqual(new __1.MissingKeyValuesError('Key field "name" must be specified in the input item in entity test-item-entity'));
645
+ });
646
+ });
647
+ describe('deleteItems()', () => {
648
+ it('should use batchWrite() to get result', async () => {
649
+ ddbClientMock.on(lib_dynamodb_1.BatchWriteCommand).resolves({
650
+ $metadata: {
651
+ httpStatusCode: 200,
652
+ },
653
+ ItemCollectionMetrics: {
654
+ [TABLE_NAME]: [{}],
655
+ },
656
+ });
657
+ const input = {
658
+ RequestItems: {
659
+ [TABLE_NAME]: [
660
+ {
661
+ DeleteRequest: {
662
+ Key: { pk: 'test_item#foo', sk: '#meta' },
663
+ },
664
+ },
665
+ {
666
+ DeleteRequest: {
667
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
668
+ },
669
+ },
670
+ ],
671
+ },
672
+ };
673
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
674
+ await repository.deleteItems(requestItems);
675
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.BatchWriteCommand, input);
676
+ });
677
+ it('should use re-try if unprocessed items returned', async () => {
678
+ const input1 = {
679
+ RequestItems: {
680
+ [TABLE_NAME]: [
681
+ {
682
+ DeleteRequest: {
683
+ Key: { pk: 'test_item#foo', sk: '#meta' },
684
+ },
685
+ },
686
+ {
687
+ DeleteRequest: {
688
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
689
+ },
690
+ },
691
+ ],
692
+ },
693
+ };
694
+ const input2 = {
695
+ RequestItems: {
696
+ [TABLE_NAME]: [
697
+ {
698
+ DeleteRequest: {
699
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
700
+ },
701
+ },
702
+ ],
703
+ },
704
+ };
705
+ ddbClientMock.on(lib_dynamodb_1.BatchWriteCommand, input1).resolves({
706
+ $metadata: {
707
+ httpStatusCode: 200,
708
+ },
709
+ UnprocessedItems: {
710
+ [TABLE_NAME]: [
711
+ {
712
+ DeleteRequest: {
713
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
714
+ },
715
+ },
716
+ ],
717
+ },
718
+ });
719
+ ddbClientMock.on(lib_dynamodb_1.BatchWriteCommand, input2).resolves({
720
+ $metadata: {
721
+ httpStatusCode: 200,
722
+ },
723
+ UnprocessedItems: {},
724
+ });
725
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
726
+ await repository.deleteItems(requestItems);
727
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchWriteCommand, input1);
728
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchWriteCommand, input2);
729
+ });
730
+ it('should fail after max number of retries', async () => {
731
+ const input1 = {
732
+ RequestItems: {
733
+ [TABLE_NAME]: [
734
+ {
735
+ DeleteRequest: {
736
+ Key: { pk: 'test_item#foo', sk: '#meta' },
737
+ },
738
+ },
739
+ {
740
+ DeleteRequest: {
741
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
742
+ },
743
+ },
744
+ ],
745
+ },
746
+ };
747
+ const input2 = {
748
+ RequestItems: {
749
+ [TABLE_NAME]: [
750
+ {
751
+ DeleteRequest: {
752
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
753
+ },
754
+ },
755
+ ],
756
+ },
757
+ };
758
+ ddbClientMock.on(lib_dynamodb_1.BatchWriteCommand).resolves({
759
+ $metadata: {
760
+ httpStatusCode: 200,
761
+ },
762
+ UnprocessedItems: {
763
+ [TABLE_NAME]: [
764
+ {
765
+ DeleteRequest: {
766
+ Key: { pk: 'test_item#foo2', sk: '#meta' },
767
+ },
768
+ },
769
+ ],
770
+ },
771
+ });
772
+ const requestItems = [{ name: 'foo' }, { name: 'foo2' }];
773
+ await expect(repository.deleteItems(requestItems)).rejects.toEqual(new Error('Maximum allowed retries exceeded for unprocessed items'));
774
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchWriteCommand, input1);
775
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchWriteCommand, input2);
776
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(3, lib_dynamodb_1.BatchWriteCommand, input2);
777
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(4, lib_dynamodb_1.BatchWriteCommand, input2);
778
+ });
779
+ it('should request batchWrite in batch of 25 items to get result', async () => {
780
+ ddbClientMock.on(lib_dynamodb_1.BatchWriteCommand).resolves({
781
+ $metadata: {
782
+ httpStatusCode: 200,
783
+ },
784
+ });
785
+ const requestItems = [];
786
+ for (let i = 0; i < 30; i++) {
787
+ requestItems.push({ name: `foo${i}` });
788
+ }
789
+ // keys for first batch request
790
+ const keys1 = [];
791
+ for (let i = 0; i < 25; i++) {
792
+ keys1.push({ pk: `test_item#foo${i}`, sk: '#meta' });
793
+ }
794
+ // keys for second batch request
795
+ const keys2 = [];
796
+ for (let i = 25; i < 30; i++) {
797
+ keys2.push({ pk: `test_item#foo${i}`, sk: '#meta' });
798
+ }
799
+ const input1 = {
800
+ RequestItems: {
801
+ [TABLE_NAME]: keys1.map((key) => {
802
+ return {
803
+ DeleteRequest: {
804
+ Key: key,
805
+ },
806
+ };
807
+ }),
808
+ },
809
+ };
810
+ const input2 = {
811
+ RequestItems: {
812
+ [TABLE_NAME]: keys2.map((key) => {
813
+ return {
814
+ DeleteRequest: {
815
+ Key: key,
816
+ },
817
+ };
818
+ }),
819
+ },
820
+ };
821
+ await repository.deleteItems(requestItems);
822
+ expect(ddbClientMock).toHaveReceivedCommandTimes(lib_dynamodb_1.BatchWriteCommand, 2);
823
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(1, lib_dynamodb_1.BatchWriteCommand, input1);
824
+ expect(ddbClientMock).toHaveReceivedNthCommandWith(2, lib_dynamodb_1.BatchWriteCommand, input2);
825
+ });
826
+ it('should throw error if any input item does not includes key field(s)', async () => {
827
+ const requestItems = [{ name: 'foo' }, { age: 22 }];
828
+ await expect(repository.deleteItems(requestItems)).rejects.toEqual(new __1.MissingKeyValuesError('Key field "name" must be specified in the input item in entity test-item-entity'));
829
+ });
830
+ });
388
831
  describe('queryItems()', () => {
389
832
  it('should return the items if found', async () => {
390
833
  ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
@@ -462,8 +905,7 @@ describe('AbstractRepository', () => {
462
905
  },
463
906
  };
464
907
  const partialItem = { name: 'foo' };
465
- const useSortKey = true;
466
- const _result = await repository.queryItems(partialItem, useSortKey);
908
+ const _result = await repository.queryItems(partialItem, { useSortKey: true });
467
909
  expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
468
910
  });
469
911
  it('should return the items if found when using gsi index', async () => {
@@ -500,7 +942,7 @@ describe('AbstractRepository', () => {
500
942
  };
501
943
  const partialItem = { country: 'au' };
502
944
  const useSortKey = false;
503
- const result = await repository.queryItems(partialItem, useSortKey, index);
945
+ const result = await repository.queryItems(partialItem, { useSortKey, index });
504
946
  expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
505
947
  expect(result).toEqual([
506
948
  new TestItem({
@@ -539,13 +981,122 @@ describe('AbstractRepository', () => {
539
981
  };
540
982
  const partialItem = { age: 99, country: 'au' };
541
983
  const useSortKey = true;
542
- const _result = await repository.queryItems(partialItem, useSortKey, index);
984
+ const _result = await repository.queryItems(partialItem, { useSortKey, index });
985
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
986
+ });
987
+ it('should set input query correctly when "filter - begins_with" query option is set', async () => {
988
+ ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
989
+ $metadata: {
990
+ httpStatusCode: 200,
991
+ },
992
+ });
993
+ const input = {
994
+ TableName: TABLE_NAME,
995
+ KeyConditionExpression: '#pkName = :pkValue AND begins_with(#skName, :skValue)',
996
+ ExpressionAttributeNames: {
997
+ '#pkName': 'pk',
998
+ '#skName': 'sk',
999
+ },
1000
+ ExpressionAttributeValues: {
1001
+ ':pkValue': 'test_item#foo',
1002
+ ':skValue': 'keyword-x',
1003
+ },
1004
+ };
1005
+ const partialItem = { name: 'foo' };
1006
+ const queryOptions = {
1007
+ filter: {
1008
+ type: 'begins_with',
1009
+ keyword: 'keyword-x',
1010
+ },
1011
+ };
1012
+ await repository.queryItems(partialItem, queryOptions);
1013
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
1014
+ });
1015
+ it('should throw error invalid "filter" query option is set', async () => {
1016
+ ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
1017
+ $metadata: {
1018
+ httpStatusCode: 200,
1019
+ },
1020
+ });
1021
+ const partialItem = { name: 'foo' };
1022
+ const queryOptions = {
1023
+ filter: {
1024
+ type: 'invalid-type',
1025
+ keyword: 'keyword-x',
1026
+ },
1027
+ };
1028
+ await expect(repository.queryItems(partialItem, queryOptions)).rejects.toEqual(new Error(`Invalid query filter type: invalid-type`));
1029
+ });
1030
+ it('should set input query correctly when "limit" query option is set', async () => {
1031
+ ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
1032
+ $metadata: {
1033
+ httpStatusCode: 200,
1034
+ },
1035
+ });
1036
+ const input = {
1037
+ TableName: TABLE_NAME,
1038
+ KeyConditionExpression: '#pkName = :pkValue',
1039
+ ExpressionAttributeNames: {
1040
+ '#pkName': 'pk',
1041
+ },
1042
+ ExpressionAttributeValues: {
1043
+ ':pkValue': 'test_item#foo',
1044
+ },
1045
+ Limit: 33,
1046
+ };
1047
+ const partialItem = { name: 'foo' };
1048
+ const queryOptions = { limit: 33 };
1049
+ await repository.queryItems(partialItem, queryOptions);
1050
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
1051
+ });
1052
+ it('should set input query correctly when "order asc" query option is set', async () => {
1053
+ ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
1054
+ $metadata: {
1055
+ httpStatusCode: 200,
1056
+ },
1057
+ });
1058
+ const input = {
1059
+ TableName: TABLE_NAME,
1060
+ KeyConditionExpression: '#pkName = :pkValue',
1061
+ ExpressionAttributeNames: {
1062
+ '#pkName': 'pk',
1063
+ },
1064
+ ExpressionAttributeValues: {
1065
+ ':pkValue': 'test_item#foo',
1066
+ },
1067
+ ScanIndexForward: true,
1068
+ };
1069
+ const partialItem = { name: 'foo' };
1070
+ const queryOptions = { order: 'asc' };
1071
+ await repository.queryItems(partialItem, queryOptions);
1072
+ expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
1073
+ });
1074
+ it('should set input query correctly when "order desc" query option is set', async () => {
1075
+ ddbClientMock.on(lib_dynamodb_1.QueryCommand).resolves({
1076
+ $metadata: {
1077
+ httpStatusCode: 200,
1078
+ },
1079
+ });
1080
+ const input = {
1081
+ TableName: TABLE_NAME,
1082
+ KeyConditionExpression: '#pkName = :pkValue',
1083
+ ExpressionAttributeNames: {
1084
+ '#pkName': 'pk',
1085
+ },
1086
+ ExpressionAttributeValues: {
1087
+ ':pkValue': 'test_item#foo',
1088
+ },
1089
+ ScanIndexForward: false,
1090
+ };
1091
+ const partialItem = { name: 'foo' };
1092
+ const queryOptions = { order: 'desc' };
1093
+ await repository.queryItems(partialItem, queryOptions);
543
1094
  expect(ddbClientMock).toHaveReceivedCommandWith(lib_dynamodb_1.QueryCommand, input);
544
1095
  });
545
1096
  it('should throw error for invalid index query', async () => {
546
1097
  const index = 'undefined-index';
547
1098
  const partialItem = { age: 99, country: 'au' };
548
- await expect(repository.queryItems(partialItem, false, index)).rejects.toEqual(new __1.MissingKeyValuesError(`Table index '${index}' not defined on entity test-item-entity`));
1099
+ await expect(repository.queryItems(partialItem, { index })).rejects.toEqual(new __1.MissingKeyValuesError(`Table index '${index}' not defined on entity test-item-entity`));
549
1100
  });
550
1101
  it('should throw error for missing key fields', async () => {
551
1102
  const partialItem = { age: 99, country: 'au' };
@@ -555,13 +1106,13 @@ describe('AbstractRepository', () => {
555
1106
  const partialItem = { name: 'foo' };
556
1107
  const useSortKey = false;
557
1108
  const index = 'gsi1_pk-gsi1_sk-index';
558
- await expect(repository.queryItems(partialItem, useSortKey, index)).rejects.toEqual(new __1.MissingKeyValuesError(`Key field "country" must be specified in the input item in entity test-item-entity`));
1109
+ await expect(repository.queryItems(partialItem, { useSortKey, index })).rejects.toEqual(new __1.MissingKeyValuesError(`Key field "country" must be specified in the input item in entity test-item-entity`));
559
1110
  });
560
1111
  it('should throw error for missing key fields with "useSortKey" param true when using index', async () => {
561
1112
  const partialItem = { country: 'au' };
562
1113
  const useSortKey = true;
563
1114
  const index = 'gsi1_pk-gsi1_sk-index';
564
- await expect(repository.queryItems(partialItem, useSortKey, index)).rejects.toEqual(new __1.MissingKeyValuesError(`Key field "age" must be specified in the input item in entity test-item-entity`));
1115
+ await expect(repository.queryItems(partialItem, { useSortKey, index })).rejects.toEqual(new __1.MissingKeyValuesError(`Key field "age" must be specified in the input item in entity test-item-entity`));
565
1116
  });
566
1117
  });
567
1118
  describe('deleteItem()', () => {
@@ -628,7 +1179,6 @@ describe('AbstractRepository', () => {
628
1179
  await repository.deleteItem({ name: 'foo' }, transaction);
629
1180
  await repository.updateItem({
630
1181
  name: 'foo2',
631
- }, {
632
1182
  age: 55,
633
1183
  }, transaction);
634
1184
  return await repository.createItem({