@teselagen/ui 0.8.6-beta.14 → 0.8.6-beta.16

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.
@@ -57,6 +57,14 @@ describe("filterLocalEntitiesToHasura", () => {
57
57
  expect(result.entitiesAcrossPages).toEqual([records[0]]);
58
58
  expect(result.entityCount).toBe(1);
59
59
  });
60
+ it("should filter num fields by _eq", () => {
61
+ const result = filterLocalEntitiesToHasura(records, {
62
+ where: { age: { _eq: 30 } }
63
+ });
64
+ expect(result.entities).toEqual([records[0]]);
65
+ expect(result.entitiesAcrossPages).toEqual([records[0]]);
66
+ expect(result.entityCount).toBe(1);
67
+ });
60
68
 
61
69
  it("should filter by _neq", () => {
62
70
  const result = filterLocalEntitiesToHasura(records, {
@@ -383,7 +391,7 @@ describe("filterLocalEntitiesToHasura", () => {
383
391
  const result = filterLocalEntitiesToHasura(
384
392
  [{ id: 111, name: "Null Age", age: null, city: "Unknown" }, ...records],
385
393
  {
386
- order_by: { age: "asc" }
394
+ order_by: { path: "age", direction: "asc" }
387
395
  }
388
396
  );
389
397
  expect(result.entities).toEqual([
@@ -402,6 +410,414 @@ describe("filterLocalEntitiesToHasura", () => {
402
410
  ]);
403
411
  expect(result.entityCount).toBe(5);
404
412
  });
413
+ it("should not reorder ents if ordering on something that doesn't exist for any of them ", () => {
414
+ const ents = [
415
+ {
416
+ name: "Tom88",
417
+ id: "3JKXdPA4KiEqSqMswYXBE",
418
+ type: "fail",
419
+ howMany: "fail",
420
+ isProtein: true,
421
+ weather: "WAY TOO HOT"
422
+ },
423
+ {
424
+ name: "Tom89 a",
425
+ id: "18zbauHCMxFlkbGfGmRBn",
426
+ type: "too old",
427
+ howMany: "15",
428
+ isProtein: true,
429
+ weather: "cloudy"
430
+ },
431
+ {
432
+ name: "Tom90 a",
433
+ id: "Nj1AFBQ-GWZ7TEvhUOsFj",
434
+ type: "new",
435
+ howMany: "3",
436
+ isProtein: true,
437
+ weather: "HOT"
438
+ },
439
+ {
440
+ name: "Tom91 a",
441
+ id: "X0a4uOF8vwofrciUfQ8Zn",
442
+ type: "old",
443
+ howMany: 2,
444
+ isProtein: true,
445
+ weather: "cloudy"
446
+ },
447
+ {
448
+ name: "Tom92 a",
449
+ id: "rbeGUYOa6u8tsQgK2MQKv",
450
+ type: "new",
451
+ howMany: 5,
452
+ isProtein: true,
453
+ weather: "HOT"
454
+ },
455
+ {
456
+ name: "Tom93",
457
+ id: "Hq_SOIylSuFnQDyXZtojT",
458
+ type: "old",
459
+ howMany: 5,
460
+ isProtein: true,
461
+ weather: "rainy"
462
+ },
463
+ {
464
+ name: "Tom94 a",
465
+ id: "XOd1GtMqr1y-dzKknfxFc",
466
+ type: "old",
467
+ howMany: "3",
468
+ isProtein: true,
469
+ weather: "HOT"
470
+ },
471
+ {
472
+ name: "Tom95 a",
473
+ id: "Bw1rASgu9XLFC7DzTFw9K",
474
+ type: "old",
475
+ howMany: 5,
476
+ isProtein: true,
477
+ weather: "rainy"
478
+ },
479
+ {
480
+ name: "Tom96 a",
481
+ id: "j8pHKMzXi1n9Ce7roXP5f",
482
+ type: "new",
483
+ howMany: 40,
484
+ isProtein: true,
485
+ weather: "cloudy"
486
+ },
487
+ {
488
+ name: "Tom97 a",
489
+ id: "pLhv2XoDSy7tmmJI61f4-",
490
+ type: "new",
491
+ howMany: 40,
492
+ isProtein: true,
493
+ weather: "HOT"
494
+ },
495
+ {
496
+ name: "Tom98",
497
+ id: "I0WqsADFT9QxZVzEDrki0",
498
+ type: "old",
499
+ howMany: "3",
500
+ isProtein: true,
501
+ weather: "cloudy"
502
+ },
503
+ {
504
+ name: "Tom99 a",
505
+ id: "oTLzlqWtuYbcicyUn3LFl",
506
+ type: "new",
507
+ howMany: 2,
508
+ isProtein: true,
509
+ weather: "rainy"
510
+ },
511
+ {
512
+ name: "Tom100 a",
513
+ id: "M4piV2ZfizeWmf6ZKNr_4",
514
+ type: "new",
515
+ howMany: 40,
516
+ isProtein: true,
517
+ weather: "cloudy"
518
+ },
519
+ {
520
+ name: "Tom101 a",
521
+ id: "E1Yr5zaY41PrmAs2uC-be",
522
+ type: "old",
523
+ howMany: 40,
524
+ isProtein: true,
525
+ weather: "cloudy"
526
+ },
527
+ {
528
+ name: "Tom102 a",
529
+ id: "usnFso9ObH8RZpDmOyOv4",
530
+ type: "new",
531
+ howMany: 40,
532
+ isProtein: true,
533
+ weather: "cloudy"
534
+ },
535
+ {
536
+ name: "Tom103",
537
+ id: "_BRQ-t0CDnlSYU3ZJ73Ca",
538
+ type: "old",
539
+ howMany: 2,
540
+ isProtein: true,
541
+ weather: "rainy"
542
+ },
543
+ {
544
+ name: "Tom104 a",
545
+ id: "-wnRraVlIkY4RoaV5foeA",
546
+ type: "old",
547
+ howMany: "3",
548
+ isProtein: true,
549
+ weather: "rainy"
550
+ },
551
+ {
552
+ name: "Tom105 a",
553
+ id: "iY3jceZSdV6OrMytaKWS2",
554
+ type: "new",
555
+ howMany: 40,
556
+ isProtein: true,
557
+ weather: "HOT"
558
+ },
559
+ {
560
+ name: "Tom106 a",
561
+ id: "ZrZ0Vo9qm5cu9Zf6sHZsd",
562
+ type: "new",
563
+ howMany: "3",
564
+ isProtein: true,
565
+ weather: "HOT"
566
+ },
567
+ {
568
+ name: "Tom107 a",
569
+ id: "wvmW-7Wy_WtCAAOK6mnwr",
570
+ type: "new",
571
+ howMany: 5,
572
+ isProtein: true,
573
+ weather: "rainy"
574
+ },
575
+ {
576
+ name: "Nancy108",
577
+ id: "c-ht1uCS44JFSHekDvbRj",
578
+ type: "new",
579
+ howMany: 2,
580
+ isProtein: true,
581
+ weather: "cloudy"
582
+ },
583
+ {
584
+ name: "Nancy109",
585
+ id: "Oi3cFzKPebr7ZzYJu68w3",
586
+ type: "new",
587
+ howMany: 40,
588
+ isProtein: true,
589
+ weather: "HOT"
590
+ },
591
+ {
592
+ name: "Nancy110",
593
+ id: "0z2Z29YBISe41V7DL1JYJ",
594
+ type: "too old",
595
+ howMany: 2,
596
+ isProtein: true,
597
+ weather: "HOT"
598
+ },
599
+ {
600
+ name: "Nancy111",
601
+ id: "kaHP6YFgq4rNVsRpjkH5D",
602
+ type: "new",
603
+ howMany: 2,
604
+ isProtein: true,
605
+ weather: "HOT"
606
+ },
607
+ {
608
+ name: "Nancy112",
609
+ id: "C-XhKDnDXmdbJ-JXnj-yn",
610
+ type: "old",
611
+ howMany: 5,
612
+ isProtein: true,
613
+ weather: "HOT"
614
+ },
615
+ {
616
+ name: "Agnes Byrd",
617
+ id: "21Jd9-PxHBoHIXJ1j-Ei0",
618
+ type: "new",
619
+ howMany: 2,
620
+ isProtein: true,
621
+ weather: "HOT"
622
+ },
623
+ {
624
+ name: "Christopher Parks",
625
+ id: "jzP3oWirGfd4_c5KH2VmJ",
626
+ type: "old",
627
+ howMany: 2,
628
+ isProtein: true,
629
+ weather: "cloudy"
630
+ },
631
+ {
632
+ name: "Emily Hicks",
633
+ id: "rV4rRcgFKOn3AhIvNgs8R",
634
+ type: "new",
635
+ howMany: "3",
636
+ isProtein: true,
637
+ weather: "cloudy"
638
+ },
639
+ {
640
+ name: "Amanda Quinn",
641
+ id: "m29qs7y5yrlF2t_byAjRn",
642
+ type: "old",
643
+ howMany: 5,
644
+ isProtein: true,
645
+ weather: "HOT"
646
+ },
647
+ {
648
+ name: "Ola Roberts",
649
+ id: "DqjIk7lzU6_8cw3EAkQMN",
650
+ type: "old",
651
+ howMany: 40,
652
+ isProtein: true,
653
+ weather: "rainy"
654
+ },
655
+ {
656
+ name: "Theresa Rogers",
657
+ id: "XsUemLHKc5RpMmYiV3UeT",
658
+ type: "new",
659
+ howMany: 2,
660
+ isProtein: true,
661
+ weather: "cloudy"
662
+ },
663
+ {
664
+ name: "Sylvia Jackson",
665
+ id: "t7RhaB3SRKqkKSwAkMjwo",
666
+ type: "old",
667
+ howMany: 2,
668
+ isProtein: true,
669
+ weather: "cloudy"
670
+ },
671
+ {
672
+ name: "Eugene Crawford",
673
+ id: "gogZgycHEYGE8pQzFfKpn",
674
+ type: "old",
675
+ howMany: 40,
676
+ isProtein: true,
677
+ weather: "rainy"
678
+ },
679
+ {
680
+ name: "Josie Rodgers",
681
+ id: "P4gDKi3su3kBT2X8Nsoj5",
682
+ type: "old",
683
+ howMany: 2,
684
+ isProtein: true,
685
+ weather: "cloudy"
686
+ },
687
+ {
688
+ name: "Dale Nelson",
689
+ id: "cxNmge4Mr3emklYh-mYKO",
690
+ type: "old",
691
+ howMany: 2,
692
+ isProtein: true,
693
+ weather: "rainy"
694
+ },
695
+ {
696
+ name: "Vera Tran",
697
+ id: "BsNyrA-qstXd66wS-Z0hC",
698
+ type: "new",
699
+ howMany: 5,
700
+ isProtein: true,
701
+ weather: "rainy"
702
+ },
703
+ {
704
+ name: "Blake Tate",
705
+ id: "pAgunZo2FNcc_zHGxCs-1",
706
+ type: "old",
707
+ howMany: 2,
708
+ isProtein: true,
709
+ weather: "rainy"
710
+ },
711
+ {
712
+ name: "Amy Harrison",
713
+ id: "xn21FFjVyMD00qUMmHQ-k",
714
+ type: "new",
715
+ howMany: 40,
716
+ isProtein: true,
717
+ weather: "rainy"
718
+ },
719
+ {
720
+ name: "Raymond Swanson",
721
+ id: "lhBo3hBJYQKnhs7BIHaW0",
722
+ type: "old",
723
+ howMany: "3",
724
+ isProtein: true,
725
+ weather: "HOT"
726
+ },
727
+ {
728
+ name: "Kevin Tate",
729
+ id: "kgCPxens2N-AqSE41_CdM",
730
+ type: "old",
731
+ howMany: 40,
732
+ isProtein: true,
733
+ weather: "cloudy"
734
+ },
735
+ {
736
+ name: "Lenora Garrett",
737
+ id: "QsaiEKpRNErq_ZjFkedc2",
738
+ type: "old",
739
+ howMany: 5,
740
+ isProtein: true,
741
+ weather: "cloudy"
742
+ },
743
+ {
744
+ name: "Erik Spencer",
745
+ id: "fDzD7BVxS0W1F2e4AUmGm",
746
+ type: "old",
747
+ howMany: "3",
748
+ isProtein: true,
749
+ weather: "rainy"
750
+ },
751
+ {
752
+ name: "Mildred Mann",
753
+ id: "n3Vis7omDyOrAVeHToRt1",
754
+ type: "old",
755
+ howMany: 40,
756
+ isProtein: true,
757
+ weather: "HOT"
758
+ },
759
+ {
760
+ name: "Glen Wilkerson",
761
+ id: "cPK9vv-JfHBmNUwn8wUZI",
762
+ type: "old",
763
+ howMany: 40,
764
+ isProtein: true,
765
+ weather: "cloudy"
766
+ },
767
+ {
768
+ name: "Ida Alvarado",
769
+ id: "EkqcC3Lxn5O4EnebszsOu",
770
+ type: "new",
771
+ howMany: "3",
772
+ isProtein: true,
773
+ weather: "rainy"
774
+ },
775
+ {
776
+ name: "Hilda Miller",
777
+ id: "PVbWALmDv9bqr6kmsMP6g",
778
+ type: "new",
779
+ howMany: 5,
780
+ isProtein: true,
781
+ weather: "cloudy"
782
+ },
783
+ {
784
+ name: "Ella Douglas",
785
+ id: "HjMy4vzzloDP9zl2EtjYv",
786
+ type: "old",
787
+ howMany: "3",
788
+ isProtein: true,
789
+ weather: "cloudy"
790
+ },
791
+ {
792
+ name: "Leonard McKenzie",
793
+ id: "ZX8GMPeZMlN6_dfANi-NN",
794
+ type: "new",
795
+ howMany: "3",
796
+ isProtein: true,
797
+ weather: "rainy"
798
+ },
799
+ {
800
+ name: "Lora Love",
801
+ id: "EydnrigpkrEERB5cygoWx",
802
+ type: "new",
803
+ howMany: "3",
804
+ isProtein: true,
805
+ weather: "cloudy"
806
+ },
807
+ {
808
+ name: "Charlotte Ford",
809
+ id: "1lM9fZSEWpFl6PiNf4XkJ",
810
+ type: "old",
811
+ howMany: 40,
812
+ isProtein: true,
813
+ weather: "cloudy"
814
+ }
815
+ ];
816
+ const result = filterLocalEntitiesToHasura([...ents], {
817
+ order_by: { path: "updatedAt", direction: "desc" }
818
+ });
819
+ expect(result.entities).toEqual(ents);
820
+ });
405
821
  it("should order by age desc and put null/undefined vals last by default", () => {
406
822
  const result = filterLocalEntitiesToHasura(
407
823
  [
@@ -410,7 +826,7 @@ describe("filterLocalEntitiesToHasura", () => {
410
826
  ...records
411
827
  ],
412
828
  {
413
- order_by: { age: "desc" }
829
+ order_by: { path: "age", direction: "desc" }
414
830
  }
415
831
  );
416
832
  expect(result.entities).toEqual([
@@ -424,7 +840,7 @@ describe("filterLocalEntitiesToHasura", () => {
424
840
  expect(result.entityCount).toBe(6);
425
841
  });
426
842
 
427
- it.only("should order by updatedAt descending, putting null/undefined vals last ", () => {
843
+ it("should order by updatedAt descending, putting null/undefined vals last ", () => {
428
844
  const result = filterLocalEntitiesToHasura(
429
845
  [
430
846
  {
@@ -465,7 +881,7 @@ describe("filterLocalEntitiesToHasura", () => {
465
881
  }
466
882
  ],
467
883
  {
468
- order_by: [{ updatedAt: "desc" }]
884
+ order_by: [{ path: "updatedAt", direction: "desc", type: "timestamp" }]
469
885
  }
470
886
  );
471
887
  expect(result.entities).toEqual([
@@ -514,7 +930,7 @@ describe("filterLocalEntitiesToHasura", () => {
514
930
  ...records
515
931
  ],
516
932
  {
517
- order_by: { age: "desc" }
933
+ order_by: { path: "age", direction: "desc" }
518
934
  }
519
935
  );
520
936
  expect(result.entities).toEqual([
@@ -529,7 +945,7 @@ describe("filterLocalEntitiesToHasura", () => {
529
945
 
530
946
  it("should order by name ascending", () => {
531
947
  const result = filterLocalEntitiesToHasura(records, {
532
- order_by: { name: "asc" }
948
+ order_by: { path: "name", direction: "asc" }
533
949
  });
534
950
  expect(result.entities).toEqual([
535
951
  records[2],
@@ -548,7 +964,7 @@ describe("filterLocalEntitiesToHasura", () => {
548
964
 
549
965
  it("should order by name descending", () => {
550
966
  const result = filterLocalEntitiesToHasura(records, {
551
- order_by: { name: "desc" }
967
+ order_by: { path: "name", direction: "desc" }
552
968
  });
553
969
  expect(result.entities).toEqual([
554
970
  records[0],
@@ -568,7 +984,7 @@ describe("filterLocalEntitiesToHasura", () => {
568
984
  it("should filter and order", () => {
569
985
  const result = filterLocalEntitiesToHasura(records, {
570
986
  where: { city: { _eq: "London" } },
571
- order_by: { age: "desc" }
987
+ order_by: { path: "age", direction: "desc" }
572
988
  });
573
989
  expect(result.entities).toEqual([records[2], records[0]]);
574
990
  expect(result.entitiesAcrossPages).toEqual([records[2], records[0]]);
@@ -586,7 +1002,7 @@ describe("filterLocalEntitiesToHasura", () => {
586
1002
 
587
1003
  it("should handle order_by with empty where", () => {
588
1004
  const result = filterLocalEntitiesToHasura(records, {
589
- order_by: { age: "asc" }
1005
+ order_by: { path: "age", direction: "asc" }
590
1006
  });
591
1007
  expect(result.entities).toEqual([
592
1008
  records[3],
@@ -654,7 +1070,7 @@ describe("filterLocalEntitiesToHasura", () => {
654
1070
  { id: 4, name: "a3" }
655
1071
  ];
656
1072
  const result = filterLocalEntitiesToHasura(recordsWithNames, {
657
- order_by: { name: "asc" }
1073
+ order_by: { path: "name", direction: "asc" }
658
1074
  });
659
1075
  expect(result.entities).toEqual([
660
1076
  recordsWithNames[0], // a1
@@ -673,7 +1089,10 @@ describe("filterLocalEntitiesToHasura", () => {
673
1089
  records[3] // Bob Williams, age 20
674
1090
  ];
675
1091
  const result = filterLocalEntitiesToHasura(modifiedRecords, {
676
- order_by: [{ age: "asc" }, { name: "desc" }]
1092
+ order_by: [
1093
+ { path: "age", direction: "asc" },
1094
+ { path: "name", direction: "desc" }
1095
+ ]
677
1096
  });
678
1097
  expect(result.entities).toEqual([
679
1098
  modifiedRecords[3], // age 20, name "Bob Williams"
@@ -686,7 +1105,7 @@ describe("filterLocalEntitiesToHasura", () => {
686
1105
  it("should apply limit and offset to filtered and ordered results", () => {
687
1106
  const result = filterLocalEntitiesToHasura(records, {
688
1107
  where: { city: { _eq: "London" } },
689
- order_by: { age: "desc" },
1108
+ order_by: { path: "age", direction: "desc" },
690
1109
  limit: 1,
691
1110
  offset: 1
692
1111
  });
@@ -730,4 +1149,206 @@ describe("filterLocalEntitiesToHasura", () => {
730
1149
  expect(result.entitiesAcrossPages).toEqual([records[0], records[2]]);
731
1150
  expect(result.entityCount).toBe(2);
732
1151
  });
1152
+ it("should order using custom sortFn", () => {
1153
+ // Create a custom sort function that sorts by the length of the name
1154
+ const sortByNameLength = record => record.name.length;
1155
+
1156
+ const result = filterLocalEntitiesToHasura(records, {
1157
+ order_by: { sortFn: sortByNameLength, direction: "asc" }
1158
+ });
1159
+
1160
+ // Expected order: "Bob Williams" (12), "John Doe" (8), "Jane Smith" (10), "Alice Johnson" (13)
1161
+ expect(result.entities).toEqual([
1162
+ records[0], // John Doe (8 chars)
1163
+ records[1], // Jane Smith (10 chars)
1164
+ records[3], // Bob Williams (12 chars)
1165
+ records[2] // Alice Johnson (13 chars)
1166
+ ]);
1167
+ expect(result.entityCount).toBe(4);
1168
+ });
1169
+
1170
+ it("should order using multiple custom sortFn functions", () => {
1171
+ // Sort first by whether the user is active, then by name length
1172
+ const sortByActive = record => (record.is_active ? 1 : 0);
1173
+ const sortByNameLength = record => record.name.length;
1174
+
1175
+ const result = filterLocalEntitiesToHasura(records, {
1176
+ order_by: { sortFn: [sortByActive, sortByNameLength], direction: "desc" }
1177
+ });
1178
+
1179
+ // First active users (John, Alice) sorted by name length DESC
1180
+ // Then inactive users (Jane, Bob) sorted by name length DESC
1181
+ expect(result.entities).toEqual([
1182
+ records[2], // Alice Johnson (active, 13 chars)
1183
+ records[0], // John Doe (active, 8 chars)
1184
+ records[3], // Bob Williams (inactive, 12 chars)
1185
+ records[1] // Jane Smith (inactive, 10 chars)
1186
+ ]);
1187
+ expect(result.entityCount).toBe(4);
1188
+ });
1189
+
1190
+ it("should handle custom sortFn with null values", () => {
1191
+ // Create test records with some null values
1192
+ const recordsWithNulls = [
1193
+ { id: 1, value: 10, name: "Item 1" },
1194
+ { id: 2, value: null, name: "Item 2" },
1195
+ { id: 3, value: 30, name: "Item 3" },
1196
+ { id: 4, value: 20, name: "Item 4" },
1197
+ { id: 5, value: null, name: "Item 5" }
1198
+ ];
1199
+
1200
+ // Sort function that handles null values
1201
+ const sortByValue = record => {
1202
+ return record.value === null ? -Infinity : record.value;
1203
+ };
1204
+
1205
+ const result = filterLocalEntitiesToHasura(recordsWithNulls, {
1206
+ order_by: { sortFn: sortByValue, direction: "desc" }
1207
+ });
1208
+
1209
+ // Nulls should appear at the end when sorting in descending order
1210
+ expect(result.entities).toEqual([
1211
+ recordsWithNulls[2], // value: 30
1212
+ recordsWithNulls[3], // value: 20
1213
+ recordsWithNulls[0], // value: 10
1214
+ recordsWithNulls[1], // value: null
1215
+ recordsWithNulls[4] // value: null
1216
+ ]);
1217
+ expect(result.entityCount).toBe(5);
1218
+ });
1219
+ it("should order using getValueToFilterOn", () => {
1220
+ // Create a function that returns a value to sort by
1221
+ const getCustomSortValue = record => {
1222
+ // Sort by the first letter of the name
1223
+ return record.name.charAt(0);
1224
+ };
1225
+
1226
+ const result = filterLocalEntitiesToHasura(records, {
1227
+ order_by: { getValueToFilterOn: getCustomSortValue, direction: "asc" }
1228
+ });
1229
+
1230
+ // Expected order based on first letter: A, B, J, J
1231
+ // Since J appears twice, their original order should be preserved
1232
+ expect(result.entities).toEqual([
1233
+ records[2], // Alice
1234
+ records[3], // Bob
1235
+ records[0], // John
1236
+ records[1] // Jane
1237
+ ]);
1238
+ expect(result.entityCount).toBe(4);
1239
+ });
1240
+
1241
+ it("should order using getValueToFilterOn with ownProps", () => {
1242
+ // Create a function that uses ownProps for customized sorting
1243
+ const getWeightedValue = (record, ownProps) => {
1244
+ // Create a weighted value based on age and a multiplier from ownProps
1245
+ return record.age * (ownProps.multiplier || 1);
1246
+ };
1247
+
1248
+ const result = filterLocalEntitiesToHasura(records, {
1249
+ order_by: {
1250
+ getValueToFilterOn: getWeightedValue,
1251
+ direction: "desc",
1252
+ ownProps: { multiplier: 2 }
1253
+ }
1254
+ });
1255
+
1256
+ // Expected order based on age * 2: 35*2, 30*2, 25*2, 20*2
1257
+ expect(result.entities).toEqual([
1258
+ records[2], // Alice Johnson (age: 35 * 2 = 70)
1259
+ records[0], // John Doe (age: 30 * 2 = 60)
1260
+ records[1], // Jane Smith (age: 25 * 2 = 50)
1261
+ records[3] // Bob Williams (age: 20 * 2 = 40)
1262
+ ]);
1263
+ expect(result.entityCount).toBe(4);
1264
+ });
1265
+
1266
+ it("should handle null/undefined values in getValueToFilterOn", () => {
1267
+ const recordsWithMissingProps = [
1268
+ { id: 1, name: "Alice", customProp: 100 },
1269
+ { id: 2, name: "Bob", customProp: null },
1270
+ { id: 3, name: "Charlie" }, // customProp is undefined
1271
+ { id: 4, name: "Dave", customProp: 200 }
1272
+ ];
1273
+
1274
+ // Function that uses a property that might be missing
1275
+ const getCustomPropValue = record => {
1276
+ return record.customProp;
1277
+ };
1278
+
1279
+ const result = filterLocalEntitiesToHasura(recordsWithMissingProps, {
1280
+ order_by: { getValueToFilterOn: getCustomPropValue, direction: "desc" }
1281
+ });
1282
+
1283
+ // Should order with valid values first, then nulls/undefined at the end
1284
+ expect(result.entities).toEqual([
1285
+ recordsWithMissingProps[3], // customProp: 200
1286
+ recordsWithMissingProps[0], // customProp: 100
1287
+ recordsWithMissingProps[2], // customProp: undefined
1288
+ recordsWithMissingProps[1] // customProp: null
1289
+ ]);
1290
+ expect(result.entityCount).toBe(4);
1291
+ });
1292
+
1293
+ it("should combine getValueToFilterOn with multiple sort criteria", () => {
1294
+ // Additional records with same category but different priority
1295
+ const extendedRecords = [
1296
+ ...records,
1297
+ {
1298
+ id: 111,
1299
+ name: "Tom Jones",
1300
+ age: 40,
1301
+ is_active: true,
1302
+ city: "London",
1303
+ tags: ["sql", "management"],
1304
+ email: "tom@example.com",
1305
+ data: { category: "A", type: "X", priority: 2 },
1306
+ username: "tom111"
1307
+ },
1308
+ {
1309
+ id: 222,
1310
+ name: "Emma Brown",
1311
+ age: 28,
1312
+ is_active: true,
1313
+ city: "London",
1314
+ tags: ["design", "javascript"],
1315
+ email: "emma@example.com",
1316
+ data: { category: "A", type: "X", priority: 1 },
1317
+ username: "emma222"
1318
+ }
1319
+ ];
1320
+
1321
+ // First sort by category
1322
+ const getCategoryValue = record => {
1323
+ return record.data.category;
1324
+ };
1325
+
1326
+ // Then sort by priority if available, putting records without priority at the end
1327
+ const getPriorityValue = record => {
1328
+ return record.data.priority !== undefined
1329
+ ? record.data.priority
1330
+ : Number.MAX_SAFE_INTEGER;
1331
+ };
1332
+
1333
+ const result = filterLocalEntitiesToHasura(extendedRecords, {
1334
+ order_by: [
1335
+ { getValueToFilterOn: getCategoryValue, direction: "asc" },
1336
+ { getValueToFilterOn: getPriorityValue, direction: "asc" }
1337
+ ]
1338
+ });
1339
+
1340
+ // All category A records, ordered by priority if available
1341
+ const categoryARecords = [
1342
+ extendedRecords[5], // Emma (category A, priority 1)
1343
+ extendedRecords[4], // Tom (category A, priority 2)
1344
+ extendedRecords[0], // John (category A, no priority)
1345
+ extendedRecords[2] // Alice (category A, no priority)
1346
+ ];
1347
+
1348
+ // Then category B, then category C
1349
+ expect(result.entities.slice(0, 4)).toEqual(categoryARecords);
1350
+ expect(result.entities[4]).toBe(extendedRecords[1]); // Jane (category B)
1351
+ expect(result.entities[5]).toBe(extendedRecords[3]); // Bob (category C)
1352
+ expect(result.entityCount).toBe(6);
1353
+ });
733
1354
  });