emberflow 1.4.30 → 1.4.32

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.
Files changed (66) hide show
  1. package/README.md +4 -4
  2. package/lib/index-utils.d.ts +12 -10
  3. package/lib/index-utils.js +92 -25
  4. package/lib/index-utils.js.map +1 -1
  5. package/lib/index.d.ts +10 -7
  6. package/lib/index.js +59 -60
  7. package/lib/index.js.map +1 -1
  8. package/lib/init-db-structure.js +24 -32
  9. package/lib/init-db-structure.js.map +1 -1
  10. package/lib/logics/patch-logics.d.ts +9 -0
  11. package/lib/logics/patch-logics.js +126 -0
  12. package/lib/logics/patch-logics.js.map +1 -0
  13. package/lib/logics/view-logics.d.ts +1 -1
  14. package/lib/logics/view-logics.js +6 -5
  15. package/lib/logics/view-logics.js.map +1 -1
  16. package/lib/sample-custom/business-logics.js +1 -0
  17. package/lib/sample-custom/business-logics.js.map +1 -1
  18. package/lib/sample-custom/patch-logics.d.ts +2 -0
  19. package/lib/sample-custom/patch-logics.js +57 -0
  20. package/lib/sample-custom/patch-logics.js.map +1 -0
  21. package/lib/sample-custom/security.d.ts +1 -1
  22. package/lib/sample-custom/security.js +18 -7
  23. package/lib/sample-custom/security.js.map +1 -1
  24. package/lib/sample-custom/validators.d.ts +1 -2
  25. package/lib/sample-custom/validators.js +28 -7
  26. package/lib/sample-custom/validators.js.map +1 -1
  27. package/lib/tests/index-utils.test.js +312 -70
  28. package/lib/tests/index-utils.test.js.map +1 -1
  29. package/lib/tests/index.test.js +109 -55
  30. package/lib/tests/index.test.js.map +1 -1
  31. package/lib/tests/init-db-structure.test.js +32 -16
  32. package/lib/tests/init-db-structure.test.js.map +1 -1
  33. package/lib/tests/logics/patch-logis.test.d.ts +1 -0
  34. package/lib/tests/logics/patch-logis.test.js +347 -0
  35. package/lib/tests/logics/patch-logis.test.js.map +1 -0
  36. package/lib/tests/logics/view-logics.test.js +18 -5
  37. package/lib/tests/logics/view-logics.test.js.map +1 -1
  38. package/lib/tests/utils/db-structure.test.js +23 -25
  39. package/lib/tests/utils/db-structure.test.js.map +1 -1
  40. package/lib/tests/utils/distribution.test.js +28 -10
  41. package/lib/tests/utils/distribution.test.js.map +1 -1
  42. package/lib/tests/utils/forms.test.js +4 -3
  43. package/lib/tests/utils/forms.test.js.map +1 -1
  44. package/lib/tests/utils/misc.test.js +2 -1
  45. package/lib/tests/utils/misc.test.js.map +1 -1
  46. package/lib/tests/utils/paths.test.js +1 -1
  47. package/lib/tests/utils/paths.test.js.map +1 -1
  48. package/lib/tests/utils/pubsub.test.js +1 -1
  49. package/lib/tests/utils/pubsub.test.js.map +1 -1
  50. package/lib/types.d.ts +21 -2
  51. package/lib/utils/db-structure.d.ts +4 -2
  52. package/lib/utils/db-structure.js +14 -4
  53. package/lib/utils/db-structure.js.map +1 -1
  54. package/lib/utils/distribution.d.ts +1 -1
  55. package/lib/utils/distribution.js +9 -6
  56. package/lib/utils/distribution.js.map +1 -1
  57. package/lib/utils/forms.js +3 -1
  58. package/lib/utils/forms.js.map +1 -1
  59. package/lib/utils/misc.d.ts +0 -3
  60. package/lib/utils/misc.js +1 -48
  61. package/lib/utils/misc.js.map +1 -1
  62. package/package.json +2 -2
  63. package/src/sample-custom/business-logics.ts +1 -0
  64. package/src/sample-custom/patch-logics.ts +36 -0
  65. package/src/sample-custom/security.ts +17 -6
  66. package/src/sample-custom/validators.ts +27 -6
@@ -38,6 +38,7 @@ const forms = __importStar(require("../utils/forms"));
38
38
  const misc = __importStar(require("../utils/misc"));
39
39
  const index_utils_1 = require("../index-utils");
40
40
  const viewLogics = __importStar(require("../logics/view-logics"));
41
+ const patch_logics_1 = require("../sample-custom/patch-logics");
41
42
  // should mock when using initializeEmberFlow and testing db.doc() calls count
42
43
  jest.spyOn(indexUtils, "createMetricLogicDoc").mockResolvedValue();
43
44
  jest.spyOn(console, "log").mockImplementation();
@@ -479,7 +480,7 @@ describe("distribute", () => {
479
480
  dstPath: "/users/test-user-id/documents/test-doc-id",
480
481
  }],
481
482
  ]]);
482
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, []);
483
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, [], patch_logics_1.patchLogicConfigs);
483
484
  await indexUtils.distributeFnNonTransactional(userDocsByDstPath);
484
485
  expect(admin.firestore().doc).toHaveBeenCalledTimes(1);
485
486
  expect(admin.firestore().doc).toHaveBeenCalledWith("/users/test-user-id/documents/test-doc-id");
@@ -516,7 +517,7 @@ describe("distribute", () => {
516
517
  describe("distributeLater", () => {
517
518
  let queueForDistributionLaterSpy;
518
519
  beforeEach(() => {
519
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, []);
520
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, [], patch_logics_1.patchLogicConfigs);
520
521
  queueForDistributionLaterSpy = jest.spyOn(distribution, "queueForDistributionLater").mockResolvedValue();
521
522
  });
522
523
  afterEach(() => {
@@ -539,38 +540,128 @@ describe("distributeLater", () => {
539
540
  ["/users/test-user-id/documents/doc1", [doc1]],
540
541
  ["/users/test-user-id/documents/doc2", [doc2]],
541
542
  ]);
542
- await indexUtils.distributeLater(usersDocsByDstPath);
543
+ const targetVersion = "1.0.0";
544
+ await indexUtils.distributeLater(usersDocsByDstPath, targetVersion);
543
545
  expect(queueForDistributionLaterSpy).toHaveBeenCalledTimes(1);
544
- expect(queueForDistributionLaterSpy).toHaveBeenCalledWith(doc1, doc2);
546
+ expect(queueForDistributionLaterSpy).toHaveBeenCalledWith(targetVersion, doc1, doc2);
545
547
  });
546
548
  });
547
549
  describe("validateForm", () => {
548
550
  beforeEach(() => {
549
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, []);
551
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, [], patch_logics_1.patchLogicConfigs);
552
+ });
553
+ const targetVersion = "2.5";
554
+ const entity = "user";
555
+ it("should call the appropriate version of validator", async () => {
556
+ const userValidation = jest.fn().mockResolvedValue({});
557
+ const userValidationV2 = jest.fn().mockResolvedValue({});
558
+ const userValidationV3 = jest.fn().mockResolvedValue({});
559
+ const feedValidation = jest.fn().mockResolvedValue({});
560
+ const feedValidationV2 = jest.fn().mockResolvedValue({});
561
+ const validatorConfigs = [
562
+ {
563
+ entity: db_structure_1.Entity.User,
564
+ validatorFn: userValidation,
565
+ version: "01",
566
+ },
567
+ {
568
+ entity: db_structure_1.Entity.User,
569
+ validatorFn: userValidationV2,
570
+ version: "02.04.06",
571
+ },
572
+ {
573
+ entity: db_structure_1.Entity.User,
574
+ validatorFn: userValidationV3,
575
+ version: "03",
576
+ },
577
+ {
578
+ entity: db_structure_1.Entity.Feed,
579
+ validatorFn: feedValidation,
580
+ version: "01",
581
+ },
582
+ {
583
+ entity: db_structure_1.Entity.Feed,
584
+ validatorFn: feedValidationV2,
585
+ version: "02.04.06",
586
+ },
587
+ ];
588
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validatorConfigs, [], patch_logics_1.patchLogicConfigs);
589
+ const document = {
590
+ name: "John Doe",
591
+ email: "johndoe@example.com",
592
+ password: "abc123",
593
+ };
594
+ await indexUtils.validateForm(entity, document, targetVersion);
595
+ expect(userValidation).not.toHaveBeenCalled();
596
+ expect(userValidationV2).toHaveBeenCalledTimes(1);
597
+ expect(userValidationV3).not.toHaveBeenCalled();
598
+ expect(feedValidation).not.toHaveBeenCalled();
599
+ expect(feedValidationV2).not.toHaveBeenCalled();
550
600
  });
551
601
  it("returns an object with empty validationResult when document is valid", async () => {
552
- const entity = "user";
553
602
  const document = {
554
603
  name: "John Doe",
555
604
  email: "johndoe@example.com",
556
605
  password: "abc123",
557
606
  };
558
- const [hasValidationError, validationResult] = await indexUtils.validateForm(entity, document);
607
+ const [hasValidationError, validationResult] = await indexUtils.validateForm(entity, document, targetVersion);
559
608
  expect(hasValidationError).toBe(false);
560
609
  expect(validationResult).toEqual({});
561
610
  });
562
611
  it("returns an object with validation errors when document is invalid", async () => {
563
- const entity = "user";
564
612
  const document = {
565
613
  name: "",
566
614
  email: "johndoe@example.com",
567
615
  password: "abc",
568
616
  };
569
- const [hasValidationError, validationResult] = await indexUtils.validateForm(entity, document);
617
+ const [hasValidationError, validationResult] = await indexUtils.validateForm(entity, document, targetVersion);
570
618
  expect(hasValidationError).toBe(true);
571
619
  expect(validationResult).toEqual({ name: ["Name is required"] });
572
620
  });
573
621
  });
622
+ describe("getSecurityFn", () => {
623
+ it("should return the appropriate version of security function", async () => {
624
+ const userSecurityFn = jest.fn().mockResolvedValue({});
625
+ const userSecurityFnV2 = jest.fn().mockResolvedValue({
626
+ status: "allowed",
627
+ });
628
+ const userSecurityFnV3 = jest.fn().mockResolvedValue({});
629
+ const feedSecurityFn = jest.fn().mockResolvedValue({});
630
+ const feedSecurityFnV2 = jest.fn().mockResolvedValue({});
631
+ const targetVersion = "2.5";
632
+ const entity = "user";
633
+ const securityConfigs = [
634
+ {
635
+ entity: db_structure_1.Entity.User,
636
+ securityFn: userSecurityFn,
637
+ version: "01",
638
+ },
639
+ {
640
+ entity: db_structure_1.Entity.User,
641
+ securityFn: userSecurityFnV2,
642
+ version: "02.04.06",
643
+ },
644
+ {
645
+ entity: db_structure_1.Entity.User,
646
+ securityFn: userSecurityFnV3,
647
+ version: "03",
648
+ },
649
+ {
650
+ entity: db_structure_1.Entity.Feed,
651
+ securityFn: feedSecurityFn,
652
+ version: "01",
653
+ },
654
+ {
655
+ entity: db_structure_1.Entity.Feed,
656
+ securityFn: feedSecurityFnV2,
657
+ version: "02.04.06",
658
+ },
659
+ ];
660
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, securityConfigs, validators_1.validatorConfigs, [], patch_logics_1.patchLogicConfigs);
661
+ const result = await indexUtils.getSecurityFn(entity, targetVersion);
662
+ expect(result).toEqual(userSecurityFnV2);
663
+ });
664
+ });
574
665
  describe("getFormModifiedFields", () => {
575
666
  it("should return an empty object when there are no form fields", () => {
576
667
  const document = { name: "John Doe", age: 30 };
@@ -622,6 +713,34 @@ describe("delayFormSubmissionAndCheckIfCancelled", () => {
622
713
  expect(formResponseRef.get).toHaveBeenCalledWith();
623
714
  });
624
715
  });
716
+ describe("groupDocsByTargetDocPath", () => {
717
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, [], [], [], []);
718
+ const docsByDstPath = new Map([
719
+ ["users/user123/document1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1", doc: { field1: "value1", field2: "value2" } }]],
720
+ ["users/user123/document1/threads/thread1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/threads/thread1", doc: { field3: "value3", field6: "value6" } }]],
721
+ ["users/user123/document1/messages/message1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/messages/message1", doc: { field4: "value4" } }]],
722
+ ["users/user123/document1/images/image1", [{ action: "merge", priority: "low", dstPath: "users/user123/document1/images/image1", doc: { field7: "value7" } }]],
723
+ ["othercollection/document2", [{ action: "merge", priority: "normal", dstPath: "othercollection/document2", doc: { field5: "value5" } }]],
724
+ ["othercollection/document3", [{ action: "delete", priority: "normal", dstPath: "othercollection/document3" }]],
725
+ ]);
726
+ it("should group documents by docPath", () => {
727
+ const docPath = "users/user123/document1";
728
+ const expectedResults = {
729
+ docsByDocPath: new Map([
730
+ ["users/user123/document1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1", doc: { field1: "value1", field2: "value2" } }]],
731
+ ["users/user123/document1/threads/thread1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/threads/thread1", doc: { field3: "value3", field6: "value6" } }]],
732
+ ["users/user123/document1/messages/message1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/messages/message1", doc: { field4: "value4" } }]],
733
+ ["users/user123/document1/images/image1", [{ action: "merge", priority: "low", dstPath: "users/user123/document1/images/image1", doc: { field7: "value7" } }]],
734
+ ]),
735
+ otherDocsByDocPath: new Map([
736
+ ["othercollection/document2", [{ action: "merge", priority: "normal", dstPath: "othercollection/document2", doc: { field5: "value5" } }]],
737
+ ["othercollection/document3", [{ action: "delete", priority: "normal", dstPath: "othercollection/document3" }]],
738
+ ]),
739
+ };
740
+ const results = indexUtils.groupDocsByTargetDocPath(docsByDstPath, docPath);
741
+ expect(results).toEqual(expectedResults);
742
+ });
743
+ });
625
744
  describe("runBusinessLogics", () => {
626
745
  const actionType = "create";
627
746
  const formModifiedFields = { field1: "value1", field2: "value2" };
@@ -630,7 +749,6 @@ describe("runBusinessLogics", () => {
630
749
  id: "user123",
631
750
  name: "John Doe",
632
751
  };
633
- const metadata = { version: "1.0" };
634
752
  const action = {
635
753
  user,
636
754
  eventContext: {
@@ -650,7 +768,8 @@ describe("runBusinessLogics", () => {
650
768
  status: "processing",
651
769
  timeCreated: firebase_admin_1.firestore.Timestamp.now(),
652
770
  modifiedFields: formModifiedFields,
653
- metadata,
771
+ metadata: {},
772
+ appVersion: "1.0.0",
654
773
  };
655
774
  let distributeFn;
656
775
  let logicFn1;
@@ -699,7 +818,7 @@ describe("runBusinessLogics", () => {
699
818
  distributeFn.mockRestore();
700
819
  dbSpy.mockRestore();
701
820
  });
702
- it("should call all matching logics and pass their results to distributeFn", async () => {
821
+ it("should call all matching logics then pass their results to distributeFn", async () => {
703
822
  const logics = [
704
823
  {
705
824
  name: "Logic 1",
@@ -707,6 +826,7 @@ describe("runBusinessLogics", () => {
707
826
  modifiedFields: ["field1"],
708
827
  entities: ["user"],
709
828
  logicFn: logicFn1,
829
+ version: "1",
710
830
  },
711
831
  {
712
832
  name: "Logic 2",
@@ -714,6 +834,7 @@ describe("runBusinessLogics", () => {
714
834
  modifiedFields: ["field2"],
715
835
  entities: ["user"],
716
836
  logicFn: logicFn2,
837
+ version: "1",
717
838
  },
718
839
  {
719
840
  name: "Logic 3",
@@ -721,57 +842,173 @@ describe("runBusinessLogics", () => {
721
842
  modifiedFields: ["field3"],
722
843
  entities: ["user"],
723
844
  logicFn: logicFn3,
845
+ version: "1",
724
846
  },
847
+ ];
848
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, logics, patch_logics_1.patchLogicConfigs);
849
+ const runStatus = await indexUtils.runBusinessLogics(txnGet, action, "2");
850
+ expect(logicFn1).toHaveBeenCalledWith(txnGet, action, new Map());
851
+ expect(logicFn2).toHaveBeenCalledWith(txnGet, action, new Map());
852
+ expect(logicFn3).not.toHaveBeenCalled();
853
+ expect(runStatus).toEqual({
854
+ status: "done",
855
+ logicResults: [{
856
+ status: "finished",
857
+ execTime: expect.any(Number),
858
+ timeFinished: expect.any(Timestamp),
859
+ }, {
860
+ status: "finished",
861
+ execTime: expect.any(Number),
862
+ timeFinished: expect.any(Timestamp),
863
+ }],
864
+ });
865
+ });
866
+ it("should call all matching logics with passing addtnlFilters then pass their results " +
867
+ "to distributeFn", async () => {
868
+ const logics = [
725
869
  {
726
870
  name: "Logic 4",
727
871
  actionTypes: ["create"],
728
- modifiedFields: ["field1"],
872
+ modifiedFields: ["shouldRun"],
729
873
  entities: ["user"],
730
874
  logicFn: logicFn4,
731
- addtlFilterFn(actionType) {
732
- return actionType !== "create";
875
+ addtlFilterFn(_, modifiedFields) {
876
+ return modifiedFields.shouldRun;
733
877
  },
878
+ version: "1",
734
879
  },
735
880
  {
736
881
  name: "Logic 5",
737
882
  actionTypes: ["create"],
738
- modifiedFields: ["field2"],
883
+ modifiedFields: ["shouldRun"],
739
884
  entities: ["user"],
740
885
  logicFn: logicFn5,
741
- addtlFilterFn(actionType, modifiedFields) {
742
- return !Object.prototype.hasOwnProperty.call(modifiedFields, "field1");
886
+ addtlFilterFn(_, modifiedFields) {
887
+ return !modifiedFields.shouldRun;
743
888
  },
889
+ version: "1",
744
890
  },
745
891
  {
746
892
  name: "Logic 6",
747
- actionTypes: ["create"],
748
- modifiedFields: ["field2"],
893
+ actionTypes: ["update"],
894
+ modifiedFields: ["shouldRun"],
749
895
  entities: ["user"],
750
896
  logicFn: logicFn6,
751
- addtlFilterFn(actionType, modifiedFields, document) {
752
- return !Object.prototype.hasOwnProperty.call(document, "field3");
897
+ addtlFilterFn(_, modifiedFields) {
898
+ return modifiedFields.shouldRun;
753
899
  },
900
+ version: "1",
754
901
  },
755
902
  {
756
903
  name: "Logic 7",
757
904
  actionTypes: ["create"],
758
- modifiedFields: ["field2"],
905
+ modifiedFields: ["all"],
759
906
  entities: ["user"],
760
907
  logicFn: logicFn7,
761
908
  addtlFilterFn(actionType, modifiedFields, document, entity, metadata) {
762
909
  return metadata.version === "2.0";
763
910
  },
911
+ version: "1",
764
912
  },
765
913
  ];
766
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, logics);
767
- const runStatus = await indexUtils.runBusinessLogics(txnGet, action);
768
- expect(logicFn1).toHaveBeenCalledWith(txnGet, action, new Map());
769
- expect(logicFn2).toHaveBeenCalledWith(txnGet, action, new Map());
770
- expect(logicFn3).not.toHaveBeenCalled();
771
- expect(logicFn4).not.toHaveBeenCalled();
914
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, logics, []);
915
+ const newAction = Object.assign(Object.assign({}, action), { modifiedFields: {
916
+ shouldRun: true,
917
+ } });
918
+ const runStatus = await indexUtils.runBusinessLogics(txnGet, newAction, "1");
919
+ expect(logicFn4).toHaveBeenCalledWith(txnGet, newAction, new Map());
772
920
  expect(logicFn5).not.toHaveBeenCalled();
773
921
  expect(logicFn6).not.toHaveBeenCalled();
774
922
  expect(logicFn7).not.toHaveBeenCalled();
923
+ expect(runStatus).toEqual({
924
+ status: "done",
925
+ logicResults: [{
926
+ status: "finished",
927
+ execTime: expect.any(Number),
928
+ timeFinished: expect.any(Timestamp),
929
+ }],
930
+ });
931
+ });
932
+ it("should call all matching logics nearest to the target version then pass their results " +
933
+ "to distributeFn", async () => {
934
+ const logicFn1 = jest.fn().mockResolvedValue({ status: "finished" });
935
+ const logicFn1V2 = jest.fn().mockResolvedValue({ status: "finished" });
936
+ const logicFn1V3 = jest.fn().mockResolvedValue({ status: "finished" });
937
+ const logicFn2 = jest.fn().mockResolvedValue({ status: "finished" });
938
+ const logicFn2V2 = jest.fn().mockResolvedValue({ status: "finished" });
939
+ const logicFn3 = jest.fn().mockResolvedValue({ status: "finished" });
940
+ const logicFn3V2 = jest.fn().mockResolvedValue({ status: "error", message: "Error message" });
941
+ const logics = [
942
+ {
943
+ name: "Logic1",
944
+ actionTypes: ["create"],
945
+ modifiedFields: "all",
946
+ entities: ["user"],
947
+ logicFn: logicFn1,
948
+ version: "1.2.3",
949
+ },
950
+ {
951
+ name: "Logic1",
952
+ actionTypes: ["create"],
953
+ modifiedFields: "all",
954
+ entities: ["user"],
955
+ logicFn: logicFn1V2,
956
+ version: "2.4.6",
957
+ },
958
+ {
959
+ name: "Logic1",
960
+ actionTypes: ["update"],
961
+ modifiedFields: "all",
962
+ entities: ["user"],
963
+ logicFn: logicFn1V3,
964
+ version: "3.0.0",
965
+ },
966
+ {
967
+ name: "Logic2",
968
+ actionTypes: ["create"],
969
+ modifiedFields: ["field1"],
970
+ entities: ["user"],
971
+ logicFn: logicFn2,
972
+ version: "1.2.3",
973
+ },
974
+ {
975
+ name: "Logic2",
976
+ actionTypes: ["create"],
977
+ modifiedFields: ["field1"],
978
+ entities: ["user"],
979
+ logicFn: logicFn2V2,
980
+ version: "2.4.6",
981
+ },
982
+ {
983
+ name: "Logic3",
984
+ actionTypes: ["update"],
985
+ modifiedFields: ["field2"],
986
+ entities: ["user"],
987
+ logicFn: logicFn3,
988
+ version: "1.2.3",
989
+ },
990
+ {
991
+ name: "Logic3",
992
+ actionTypes: ["update"],
993
+ modifiedFields: ["field2"],
994
+ entities: ["user"],
995
+ logicFn: logicFn3V2,
996
+ version: "2.4.6",
997
+ },
998
+ ];
999
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, logics, []);
1000
+ const newAction = Object.assign(Object.assign({}, action), { modifiedFields: {
1001
+ field1: true,
1002
+ } });
1003
+ const targetVersion = "2.5";
1004
+ const runStatus = await indexUtils.runBusinessLogics(txnGet, newAction, targetVersion);
1005
+ expect(logicFn1).not.toHaveBeenCalled();
1006
+ expect(logicFn1V2).toHaveBeenCalledWith(txnGet, newAction, new Map());
1007
+ expect(logicFn1V3).not.toHaveBeenCalled();
1008
+ expect(logicFn2).not.toHaveBeenCalled();
1009
+ expect(logicFn2V2).toHaveBeenCalledWith(txnGet, newAction, new Map());
1010
+ expect(logicFn3).not.toHaveBeenCalled();
1011
+ expect(logicFn3V2).not.toHaveBeenCalled();
775
1012
  expect(runStatus).toEqual({
776
1013
  status: "done",
777
1014
  logicResults: [{
@@ -794,6 +1031,7 @@ describe("runBusinessLogics", () => {
794
1031
  modifiedFields: ["field1"],
795
1032
  entities: ["customentity"],
796
1033
  logicFn: logicFn1,
1034
+ version: "1",
797
1035
  },
798
1036
  {
799
1037
  name: "Logic 2",
@@ -801,6 +1039,7 @@ describe("runBusinessLogics", () => {
801
1039
  modifiedFields: ["field2"],
802
1040
  entities: ["customentity"],
803
1041
  logicFn: logicFn2,
1042
+ version: "1",
804
1043
  },
805
1044
  {
806
1045
  name: "Logic 3",
@@ -808,10 +1047,11 @@ describe("runBusinessLogics", () => {
808
1047
  modifiedFields: ["field3"],
809
1048
  entities: ["customentity"],
810
1049
  logicFn: logicFn3,
1050
+ version: "1",
811
1051
  },
812
1052
  ];
813
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, logics);
814
- const runStatus = await indexUtils.runBusinessLogics(txnGet, action);
1053
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, logics, []);
1054
+ const runStatus = await indexUtils.runBusinessLogics(txnGet, action, "1");
815
1055
  expect(logicFn1).not.toHaveBeenCalled();
816
1056
  expect(logicFn2).not.toHaveBeenCalled();
817
1057
  expect(logicFn3).not.toHaveBeenCalled();
@@ -845,6 +1085,7 @@ describe("runBusinessLogics", () => {
845
1085
  modifiedFields: ["field1"],
846
1086
  entities: ["user"],
847
1087
  logicFn: logicFn1,
1088
+ version: "1",
848
1089
  },
849
1090
  {
850
1091
  name: "Logic 2",
@@ -852,6 +1093,7 @@ describe("runBusinessLogics", () => {
852
1093
  modifiedFields: ["field2"],
853
1094
  entities: ["user"],
854
1095
  logicFn: logicFn2,
1096
+ version: "1",
855
1097
  },
856
1098
  {
857
1099
  name: "Logic 3",
@@ -859,10 +1101,11 @@ describe("runBusinessLogics", () => {
859
1101
  modifiedFields: ["field2"],
860
1102
  entities: ["user"],
861
1103
  logicFn: logicFn3,
1104
+ version: "1",
862
1105
  },
863
1106
  ];
864
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfig, validators_1.validatorConfig, logics);
865
- const runStatus = await indexUtils.runBusinessLogics(txnGet, action);
1107
+ (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, security_1.securityConfigs, validators_1.validatorConfigs, logics, []);
1108
+ const runStatus = await indexUtils.runBusinessLogics(txnGet, action, "1");
866
1109
  expect(logicFn1).toHaveBeenCalledWith(txnGet, action, expectedSharedMap);
867
1110
  expect(logicFn2).toHaveBeenCalledWith(txnGet, action, expectedSharedMap);
868
1111
  expect(logicFn3).toHaveBeenCalledWith(txnGet, action, expectedSharedMap);
@@ -874,34 +1117,6 @@ describe("runBusinessLogics", () => {
874
1117
  expect(logicResults[2].status).toEqual("finished");
875
1118
  });
876
1119
  });
877
- describe("groupDocsByTargetDocPath", () => {
878
- (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, {}, {}, []);
879
- const docsByDstPath = new Map([
880
- ["users/user123/document1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1", doc: { field1: "value1", field2: "value2" } }]],
881
- ["users/user123/document1/threads/thread1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/threads/thread1", doc: { field3: "value3", field6: "value6" } }]],
882
- ["users/user123/document1/messages/message1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/messages/message1", doc: { field4: "value4" } }]],
883
- ["users/user123/document1/images/image1", [{ action: "merge", priority: "low", dstPath: "users/user123/document1/images/image1", doc: { field7: "value7" } }]],
884
- ["othercollection/document2", [{ action: "merge", priority: "normal", dstPath: "othercollection/document2", doc: { field5: "value5" } }]],
885
- ["othercollection/document3", [{ action: "delete", priority: "normal", dstPath: "othercollection/document3" }]],
886
- ]);
887
- it("should group documents by docPath", () => {
888
- const docPath = "users/user123/document1";
889
- const expectedResults = {
890
- docsByDocPath: new Map([
891
- ["users/user123/document1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1", doc: { field1: "value1", field2: "value2" } }]],
892
- ["users/user123/document1/threads/thread1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/threads/thread1", doc: { field3: "value3", field6: "value6" } }]],
893
- ["users/user123/document1/messages/message1", [{ action: "merge", priority: "normal", dstPath: "users/user123/document1/messages/message1", doc: { field4: "value4" } }]],
894
- ["users/user123/document1/images/image1", [{ action: "merge", priority: "low", dstPath: "users/user123/document1/images/image1", doc: { field7: "value7" } }]],
895
- ]),
896
- otherDocsByDocPath: new Map([
897
- ["othercollection/document2", [{ action: "merge", priority: "normal", dstPath: "othercollection/document2", doc: { field5: "value5" } }]],
898
- ["othercollection/document3", [{ action: "delete", priority: "normal", dstPath: "othercollection/document3" }]],
899
- ]),
900
- };
901
- const results = indexUtils.groupDocsByTargetDocPath(docsByDstPath, docPath);
902
- expect(results).toEqual(expectedResults);
903
- });
904
- });
905
1120
  describe("expandConsolidateAndGroupByDstPath", () => {
906
1121
  let dbSpy;
907
1122
  let consoleWarnSpy;
@@ -1209,15 +1424,40 @@ describe("expandConsolidateAndGroupByDstPath", () => {
1209
1424
  });
1210
1425
  describe("runViewLogics", () => {
1211
1426
  // Define mock functions
1212
- const viewLogicFn1 = jest.fn();
1213
1427
  const viewLogicFn2 = jest.fn();
1428
+ const viewLogicFn1V2Point5 = jest.fn();
1214
1429
  const customViewLogicsConfig = [
1215
1430
  {
1216
1431
  name: "logic 1",
1217
1432
  entity: "user",
1218
1433
  actionTypes: ["merge", "delete"],
1219
1434
  modifiedFields: ["sampleField1", "sampleField2"],
1220
- viewLogicFn: viewLogicFn1,
1435
+ viewLogicFn: jest.fn(),
1436
+ version: "1.0.0",
1437
+ },
1438
+ {
1439
+ name: "logic 1",
1440
+ entity: "user",
1441
+ actionTypes: ["merge", "delete"],
1442
+ modifiedFields: ["sampleField1", "sampleField2"],
1443
+ viewLogicFn: jest.fn(),
1444
+ version: "2.0.0",
1445
+ },
1446
+ {
1447
+ name: "logic 1",
1448
+ entity: "user",
1449
+ actionTypes: ["merge", "delete"],
1450
+ modifiedFields: ["sampleField1", "sampleField2"],
1451
+ viewLogicFn: viewLogicFn1V2Point5,
1452
+ version: "2.5.0",
1453
+ },
1454
+ {
1455
+ name: "logic 1",
1456
+ entity: "user",
1457
+ actionTypes: ["merge", "delete"],
1458
+ modifiedFields: ["sampleField1", "sampleField2"],
1459
+ viewLogicFn: jest.fn(),
1460
+ version: "3.0.0",
1221
1461
  },
1222
1462
  {
1223
1463
  name: "logic 2",
@@ -1225,12 +1465,14 @@ describe("runViewLogics", () => {
1225
1465
  actionTypes: ["merge", "delete"],
1226
1466
  modifiedFields: ["sampleField3"],
1227
1467
  viewLogicFn: viewLogicFn2,
1468
+ version: "1.0.0",
1228
1469
  },
1229
1470
  ];
1230
1471
  beforeEach(() => {
1231
- jest.spyOn(indexUtils._mockable, "getViewLogicsConfig").mockReturnValue(customViewLogicsConfig);
1472
+ jest.spyOn(indexUtils._mockable, "getViewLogicConfigs").mockReturnValue(customViewLogicsConfig);
1232
1473
  });
1233
1474
  it("should run view logics properly", async () => {
1475
+ const targetVersion = "2.9.0";
1234
1476
  const logicResult1 = {
1235
1477
  action: "merge",
1236
1478
  priority: "normal",
@@ -1242,14 +1484,14 @@ describe("runViewLogics", () => {
1242
1484
  priority: "normal",
1243
1485
  dstPath: "users/user124",
1244
1486
  };
1245
- viewLogicFn1.mockResolvedValue({});
1487
+ viewLogicFn1V2Point5.mockResolvedValue({});
1246
1488
  viewLogicFn2.mockResolvedValue({});
1247
- const results1 = await indexUtils.runViewLogics(logicResult1);
1248
- const results2 = await indexUtils.runViewLogics(logicResult2);
1489
+ const results1 = await indexUtils.runViewLogics(logicResult1, targetVersion);
1490
+ const results2 = await indexUtils.runViewLogics(logicResult2, targetVersion);
1249
1491
  const results = [...results1, ...results2];
1250
- expect(viewLogicFn1).toHaveBeenCalledTimes(2);
1251
- expect(viewLogicFn1.mock.calls[0][0]).toBe(logicResult1);
1252
- expect(viewLogicFn1.mock.calls[1][0]).toBe(logicResult2);
1492
+ expect(viewLogicFn1V2Point5).toHaveBeenCalledTimes(2);
1493
+ expect(viewLogicFn1V2Point5.mock.calls[0][0]).toBe(logicResult1);
1494
+ expect(viewLogicFn1V2Point5.mock.calls[1][0]).toBe(logicResult2);
1253
1495
  expect(viewLogicFn2).toHaveBeenCalledTimes(1);
1254
1496
  expect(viewLogicFn2).toHaveBeenCalledWith(logicResult2);
1255
1497
  expect(results).toHaveLength(3);