@expo/entity 0.38.0 → 0.40.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.
Files changed (206) hide show
  1. package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
  2. package/build/AuthorizationResultBasedEntityAssociationLoader.js +124 -0
  3. package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -0
  4. package/build/AuthorizationResultBasedEntityLoader.d.ts +1 -1
  5. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
  6. package/build/{EntityMutator.d.ts → AuthorizationResultBasedEntityMutator.d.ts} +5 -17
  7. package/build/{EntityMutator.js → AuthorizationResultBasedEntityMutator.js} +22 -48
  8. package/build/AuthorizationResultBasedEntityMutator.js.map +1 -0
  9. package/build/EnforcingEntityAssociationLoader.d.ts +79 -0
  10. package/build/EnforcingEntityAssociationLoader.js +62 -0
  11. package/build/EnforcingEntityAssociationLoader.js.map +1 -0
  12. package/build/EnforcingEntityCreator.d.ts +24 -0
  13. package/build/EnforcingEntityCreator.js +32 -0
  14. package/build/EnforcingEntityCreator.js.map +1 -0
  15. package/build/EnforcingEntityDeleter.d.ts +17 -0
  16. package/build/EnforcingEntityDeleter.js +22 -0
  17. package/build/EnforcingEntityDeleter.js.map +1 -0
  18. package/build/EnforcingEntityUpdater.d.ts +24 -0
  19. package/build/EnforcingEntityUpdater.js +32 -0
  20. package/build/EnforcingEntityUpdater.js.map +1 -0
  21. package/build/Entity.d.ts +8 -12
  22. package/build/Entity.js +9 -34
  23. package/build/Entity.js.map +1 -1
  24. package/build/EntityAssociationLoader.d.ts +12 -91
  25. package/build/EntityAssociationLoader.js +20 -126
  26. package/build/EntityAssociationLoader.js.map +1 -1
  27. package/build/EntityCompanionProvider.d.ts +2 -2
  28. package/build/EntityCompanionProvider.js.map +1 -1
  29. package/build/EntityCreator.d.ts +27 -0
  30. package/build/EntityCreator.js +39 -0
  31. package/build/EntityCreator.js.map +1 -0
  32. package/build/EntityDatabaseAdapter.js +2 -2
  33. package/build/EntityDatabaseAdapter.js.map +1 -1
  34. package/build/EntityDeleter.d.ts +27 -0
  35. package/build/EntityDeleter.js +40 -0
  36. package/build/EntityDeleter.js.map +1 -0
  37. package/build/EntityLoader.d.ts +4 -14
  38. package/build/EntityLoader.js +7 -20
  39. package/build/EntityLoader.js.map +1 -1
  40. package/build/EntityLoaderFactory.d.ts +2 -2
  41. package/build/EntityLoaderFactory.js +4 -2
  42. package/build/EntityLoaderFactory.js.map +1 -1
  43. package/build/EntityMutatorFactory.d.ts +4 -4
  44. package/build/EntityMutatorFactory.js +4 -4
  45. package/build/EntityMutatorFactory.js.map +1 -1
  46. package/build/EntitySecondaryCacheLoader.d.ts +3 -3
  47. package/build/EntitySecondaryCacheLoader.js +1 -3
  48. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  49. package/build/EntityUpdater.d.ts +27 -0
  50. package/build/EntityUpdater.js +40 -0
  51. package/build/EntityUpdater.js.map +1 -0
  52. package/build/ReadonlyEntity.d.ts +2 -2
  53. package/build/ReadonlyEntity.js +4 -6
  54. package/build/ReadonlyEntity.js.map +1 -1
  55. package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
  56. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  57. package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
  58. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  59. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
  60. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +273 -0
  61. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
  62. package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +11 -11
  63. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
  64. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
  65. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
  66. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
  67. package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
  68. package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
  69. package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
  70. package/build/__tests__/Entity-test.js +23 -5
  71. package/build/__tests__/Entity-test.js.map +1 -1
  72. package/build/__tests__/EntityAssociationLoader-test.js +14 -184
  73. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  74. package/build/__tests__/EntityCommonUseCases-test.js +34 -12
  75. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  76. package/build/__tests__/EntityCompanion-test.js +17 -7
  77. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  78. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  79. package/build/__tests__/EntityEdges-test.js +41 -23
  80. package/build/__tests__/EntityEdges-test.js.map +1 -1
  81. package/build/__tests__/EntityLoader-test.js +22 -386
  82. package/build/__tests__/EntityLoader-test.js.map +1 -1
  83. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +4 -3
  84. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  85. package/build/__tests__/EntityMutator-test.js +67 -70
  86. package/build/__tests__/EntityMutator-test.js.map +1 -1
  87. package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
  88. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  89. package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
  90. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  91. package/build/__tests__/EntitySelfReferentialEdges-test.js +36 -24
  92. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  93. package/build/__tests__/ReadonlyEntity-test.js +1 -1
  94. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  95. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +4 -2
  96. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  97. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +7 -4
  98. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  99. package/build/__tests__/entityUtils-test.js +8 -0
  100. package/build/__tests__/entityUtils-test.js.map +1 -1
  101. package/build/entityUtils.d.ts +7 -0
  102. package/build/entityUtils.js +20 -10
  103. package/build/entityUtils.js.map +1 -1
  104. package/build/errors/EntityCacheAdapterError.js +17 -7
  105. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  106. package/build/errors/EntityDatabaseAdapterError.js +17 -7
  107. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  108. package/build/errors/EntityInvalidFieldValueError.js +17 -7
  109. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  110. package/build/errors/EntityNotAuthorizedError.js +17 -7
  111. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  112. package/build/errors/EntityNotFoundError.js +17 -7
  113. package/build/errors/EntityNotFoundError.js.map +1 -1
  114. package/build/index.d.ts +19 -11
  115. package/build/index.js +24 -7
  116. package/build/index.js.map +1 -1
  117. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  118. package/build/internal/__tests__/EntityDataManager-test.js +42 -32
  119. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  120. package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
  121. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  122. package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
  123. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  124. package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
  125. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  126. package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
  127. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  128. package/build/utils/EntityPrivacyUtils.d.ts +32 -4
  129. package/build/utils/EntityPrivacyUtils.js +68 -24
  130. package/build/utils/EntityPrivacyUtils.js.map +1 -1
  131. package/build/utils/__tests__/EntityPrivacyUtils-test.js +148 -23
  132. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
  133. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +8 -5
  134. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
  135. package/build/utils/collections/__tests__/maps-test.js +1 -1
  136. package/build/utils/collections/__tests__/maps-test.js.map +1 -1
  137. package/build/utils/collections/maps.js +2 -2
  138. package/build/utils/collections/maps.js.map +1 -1
  139. package/build/utils/mergeEntityMutationTriggerConfigurations.js +1 -2
  140. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -1
  141. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
  142. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  143. package/build/utils/testing/StubDatabaseAdapter.js +17 -7
  144. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  145. package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
  146. package/build/utils/testing/StubQueryContextProvider.js +1 -3
  147. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  148. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
  149. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
  150. package/build/utils/testing/describeFieldTestCase.js +1 -1
  151. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  152. package/package.json +19 -3
  153. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +492 -0
  154. package/src/AuthorizationResultBasedEntityLoader.ts +2 -2
  155. package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
  156. package/src/EnforcingEntityAssociationLoader.ts +390 -0
  157. package/src/EnforcingEntityCreator.ts +55 -0
  158. package/src/EnforcingEntityDeleter.ts +44 -0
  159. package/src/EnforcingEntityUpdater.ts +55 -0
  160. package/src/Entity.ts +20 -65
  161. package/src/EntityAssociationLoader.ts +38 -495
  162. package/src/EntityCompanionProvider.ts +5 -2
  163. package/src/EntityCreator.ts +73 -0
  164. package/src/EntityDeleter.ts +73 -0
  165. package/src/EntityLoader.ts +10 -49
  166. package/src/EntityLoaderFactory.ts +20 -3
  167. package/src/EntityMutatorFactory.ts +32 -7
  168. package/src/EntitySecondaryCacheLoader.ts +5 -7
  169. package/src/EntityUpdater.ts +73 -0
  170. package/src/ReadonlyEntity.ts +14 -13
  171. package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
  172. package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
  173. package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +354 -0
  174. package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +17 -10
  175. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
  176. package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
  177. package/src/__tests__/Entity-test.ts +24 -5
  178. package/src/__tests__/EntityAssociationLoader-test.ts +16 -259
  179. package/src/__tests__/EntityCommonUseCases-test.ts +20 -8
  180. package/src/__tests__/EntityCompanion-test.ts +1 -1
  181. package/src/__tests__/EntityDatabaseAdapter-test.ts +6 -6
  182. package/src/__tests__/EntityEdges-test.ts +24 -16
  183. package/src/__tests__/EntityLoader-test.ts +25 -675
  184. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +4 -3
  185. package/src/__tests__/EntityMutator-test.ts +116 -103
  186. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  187. package/src/__tests__/EntitySelfReferentialEdges-test.ts +36 -24
  188. package/src/__tests__/ReadonlyEntity-test.ts +1 -1
  189. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +4 -2
  190. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +7 -4
  191. package/src/__tests__/entityUtils-test.ts +12 -0
  192. package/src/entityUtils.ts +24 -9
  193. package/src/index.ts +19 -11
  194. package/src/internal/EntityFieldTransformationUtils.ts +2 -2
  195. package/src/internal/__tests__/EntityDataManager-test.ts +29 -29
  196. package/src/utils/EntityPrivacyUtils.ts +188 -107
  197. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +169 -29
  198. package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +8 -5
  199. package/src/utils/collections/__tests__/maps-test.ts +1 -1
  200. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
  201. package/src/utils/testing/StubDatabaseAdapter.ts +1 -1
  202. package/src/utils/testing/StubQueryContextProvider.ts +1 -3
  203. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
  204. package/build/EntityMutator.js.map +0 -1
  205. package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
  206. /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
@@ -0,0 +1,253 @@
1
+ import { result } from '@expo/results';
2
+ import { mock, instance, when, anything } from 'ts-mockito';
3
+
4
+ import AuthorizationResultBasedEntityAssociationLoader from '../AuthorizationResultBasedEntityAssociationLoader';
5
+ import EnforcingEntityAssociationLoader from '../EnforcingEntityAssociationLoader';
6
+
7
+ describe(EnforcingEntityAssociationLoader, () => {
8
+ describe('loadAssociatedEntityAsync', () => {
9
+ it('throws when result is unsuccessful', async () => {
10
+ const nonEnforcingEntityAssociationLoaderMock =
11
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
12
+ const rejection = new Error();
13
+ when(
14
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityAsync(anything(), anything()),
15
+ ).thenResolve(result(rejection));
16
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
17
+ const enforcingEntityAssociationLoader = new EnforcingEntityAssociationLoader(
18
+ nonEnforcingEntityAssociationLoader,
19
+ );
20
+ await expect(
21
+ enforcingEntityAssociationLoader.loadAssociatedEntityAsync(anything(), anything()),
22
+ ).rejects.toThrow(rejection);
23
+ });
24
+
25
+ it('returns value when result is successful', async () => {
26
+ const nonEnforcingEntityAssociationLoaderMock =
27
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
28
+ const resolved = {} as any;
29
+ when(
30
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityAsync(anything(), anything()),
31
+ ).thenResolve(result(resolved));
32
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
33
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
34
+ nonEnforcingEntityAssociationLoader,
35
+ );
36
+ await expect(
37
+ enforcingEntityLoader.loadAssociatedEntityAsync(anything(), anything()),
38
+ ).resolves.toEqual(resolved);
39
+ });
40
+ });
41
+
42
+ describe('loadManyAssociatedEntitiesAsync', () => {
43
+ it('throws when result is unsuccessful', async () => {
44
+ const nonEnforcingEntityAssociationLoaderMock =
45
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
46
+ const rejection = new Error();
47
+ when(
48
+ nonEnforcingEntityAssociationLoaderMock.loadManyAssociatedEntitiesAsync(
49
+ anything(),
50
+ anything() as never,
51
+ ),
52
+ ).thenResolve([result(rejection)]);
53
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
54
+ const enforcingEntityAssociationLoader = new EnforcingEntityAssociationLoader(
55
+ nonEnforcingEntityAssociationLoader,
56
+ );
57
+ await expect(
58
+ enforcingEntityAssociationLoader.loadManyAssociatedEntitiesAsync(
59
+ anything(),
60
+ anything() as never,
61
+ ),
62
+ ).rejects.toThrow(rejection);
63
+ });
64
+
65
+ it('returns value when result is successful', async () => {
66
+ const nonEnforcingEntityAssociationLoaderMock =
67
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
68
+ const resolved = [] as any;
69
+ when(
70
+ nonEnforcingEntityAssociationLoaderMock.loadManyAssociatedEntitiesAsync(
71
+ anything(),
72
+ anything() as never,
73
+ ),
74
+ ).thenResolve([result(resolved)]);
75
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
76
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
77
+ nonEnforcingEntityAssociationLoader,
78
+ );
79
+ await expect(
80
+ enforcingEntityLoader.loadManyAssociatedEntitiesAsync(anything(), anything() as never),
81
+ ).resolves.toEqual([resolved]);
82
+ });
83
+ });
84
+
85
+ describe('loadAssociatedEntityByFieldEqualingAsync', () => {
86
+ it('throws when result is unsuccessful', async () => {
87
+ const nonEnforcingEntityAssociationLoaderMock =
88
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
89
+ const rejection = new Error();
90
+ when(
91
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityByFieldEqualingAsync(
92
+ anything(),
93
+ anything(),
94
+ anything() as never,
95
+ ),
96
+ ).thenResolve(result(rejection));
97
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
98
+ const enforcingEntityAssociationLoader = new EnforcingEntityAssociationLoader(
99
+ nonEnforcingEntityAssociationLoader,
100
+ );
101
+ await expect(
102
+ enforcingEntityAssociationLoader.loadAssociatedEntityByFieldEqualingAsync(
103
+ anything(),
104
+ anything(),
105
+ anything() as never,
106
+ ),
107
+ ).rejects.toThrow(rejection);
108
+ });
109
+
110
+ it('returns value when result is successful', async () => {
111
+ const nonEnforcingEntityAssociationLoaderMock =
112
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
113
+ const resolved = {} as any;
114
+ when(
115
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityByFieldEqualingAsync(
116
+ anything(),
117
+ anything(),
118
+ anything() as never,
119
+ ),
120
+ ).thenResolve(result(resolved));
121
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
122
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
123
+ nonEnforcingEntityAssociationLoader,
124
+ );
125
+ await expect(
126
+ enforcingEntityLoader.loadAssociatedEntityByFieldEqualingAsync(
127
+ anything(),
128
+ anything(),
129
+ anything() as never,
130
+ ),
131
+ ).resolves.toEqual(resolved);
132
+ });
133
+
134
+ it('returns null when result is successful but null', async () => {
135
+ const nonEnforcingEntityAssociationLoaderMock =
136
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
137
+ const resolved = null;
138
+ when(
139
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityByFieldEqualingAsync(
140
+ anything(),
141
+ anything(),
142
+ anything() as never,
143
+ ),
144
+ ).thenResolve(resolved);
145
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
146
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
147
+ nonEnforcingEntityAssociationLoader,
148
+ );
149
+ await expect(
150
+ enforcingEntityLoader.loadAssociatedEntityByFieldEqualingAsync(
151
+ anything(),
152
+ anything(),
153
+ anything() as never,
154
+ ),
155
+ ).resolves.toEqual(resolved);
156
+ });
157
+ });
158
+
159
+ describe('loadManyAssociatedEntitiesByFieldEqualingAsync', () => {
160
+ it('throws when result is unsuccessful', async () => {
161
+ const nonEnforcingEntityAssociationLoaderMock =
162
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
163
+ const rejection = new Error();
164
+ when(
165
+ nonEnforcingEntityAssociationLoaderMock.loadManyAssociatedEntitiesByFieldEqualingAsync(
166
+ anything(),
167
+ anything(),
168
+ anything() as never,
169
+ ),
170
+ ).thenResolve([result(rejection)]);
171
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
172
+ const enforcingEntityAssociationLoader = new EnforcingEntityAssociationLoader(
173
+ nonEnforcingEntityAssociationLoader,
174
+ );
175
+ await expect(
176
+ enforcingEntityAssociationLoader.loadManyAssociatedEntitiesByFieldEqualingAsync(
177
+ anything(),
178
+ anything(),
179
+ anything() as never,
180
+ ),
181
+ ).rejects.toThrow(rejection);
182
+ });
183
+
184
+ it('returns value when result is successful', async () => {
185
+ const nonEnforcingEntityAssociationLoaderMock =
186
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
187
+ const resolved = [] as any;
188
+ when(
189
+ nonEnforcingEntityAssociationLoaderMock.loadManyAssociatedEntitiesByFieldEqualingAsync(
190
+ anything(),
191
+ anything(),
192
+ anything() as never,
193
+ ),
194
+ ).thenResolve([result(resolved)]);
195
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
196
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
197
+ nonEnforcingEntityAssociationLoader,
198
+ );
199
+ await expect(
200
+ enforcingEntityLoader.loadManyAssociatedEntitiesByFieldEqualingAsync(
201
+ anything(),
202
+ anything(),
203
+ anything() as never,
204
+ ),
205
+ ).resolves.toEqual([resolved]);
206
+ });
207
+ });
208
+
209
+ describe('loadAssociatedEntityThroughAsync', () => {
210
+ it('throws when result is unsuccessful', async () => {
211
+ const nonEnforcingEntityAssociationLoaderMock =
212
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
213
+ const rejection = new Error();
214
+ when(
215
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityThroughAsync(anything()),
216
+ ).thenResolve(result(rejection));
217
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
218
+ const enforcingEntityAssociationLoader = new EnforcingEntityAssociationLoader(
219
+ nonEnforcingEntityAssociationLoader,
220
+ );
221
+ await expect(
222
+ enforcingEntityAssociationLoader.loadAssociatedEntityThroughAsync(anything()),
223
+ ).rejects.toThrow(rejection);
224
+ });
225
+
226
+ it('returns value when result is successful', async () => {
227
+ const nonEnforcingEntityAssociationLoaderMock =
228
+ mock<AuthorizationResultBasedEntityAssociationLoader<any, any, any, any, any>>();
229
+ const resolved = {} as any;
230
+ when(
231
+ nonEnforcingEntityAssociationLoaderMock.loadAssociatedEntityThroughAsync(anything()),
232
+ ).thenResolve(result(resolved));
233
+ const nonEnforcingEntityAssociationLoader = instance(nonEnforcingEntityAssociationLoaderMock);
234
+ const enforcingEntityLoader = new EnforcingEntityAssociationLoader(
235
+ nonEnforcingEntityAssociationLoader,
236
+ );
237
+ await expect(
238
+ enforcingEntityLoader.loadAssociatedEntityThroughAsync(anything()),
239
+ ).resolves.toEqual(resolved);
240
+ });
241
+ });
242
+
243
+ it('has the same method names as AuthorizationResultBasedEntityAssociationLoader', () => {
244
+ const enforcingLoaderProperties = Object.getOwnPropertyNames(
245
+ EnforcingEntityAssociationLoader.prototype,
246
+ );
247
+ const nonEnforcingLoaderProperties = Object.getOwnPropertyNames(
248
+ AuthorizationResultBasedEntityAssociationLoader.prototype,
249
+ );
250
+
251
+ expect(enforcingLoaderProperties).toEqual(nonEnforcingLoaderProperties);
252
+ });
253
+ });
@@ -1,20 +1,22 @@
1
1
  import Entity from '../Entity';
2
- import { CreateMutator, UpdateMutator } from '../EntityMutator';
2
+ import EntityCreator from '../EntityCreator';
3
+ import EntityDeleter from '../EntityDeleter';
4
+ import EntityUpdater from '../EntityUpdater';
3
5
  import ViewerContext from '../ViewerContext';
4
6
  import SimpleTestEntity from '../testfixtures/SimpleTestEntity';
5
7
  import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
6
8
 
7
9
  describe(Entity, () => {
8
10
  describe('creator', () => {
9
- it('creates a new CreateMutator', () => {
11
+ it('creates a new EntityCreator', () => {
10
12
  const companionProvider = createUnitTestEntityCompanionProvider();
11
13
  const viewerContext = new ViewerContext(companionProvider);
12
- expect(SimpleTestEntity.creator(viewerContext)).toBeInstanceOf(CreateMutator);
14
+ expect(SimpleTestEntity.creator(viewerContext)).toBeInstanceOf(EntityCreator);
13
15
  });
14
16
  });
15
17
 
16
18
  describe('updater', () => {
17
- it('creates a new UpdateMutator', () => {
19
+ it('creates a new EntityUpdater', () => {
18
20
  const companionProvider = createUnitTestEntityCompanionProvider();
19
21
  const viewerContext = new ViewerContext(companionProvider);
20
22
  const data = {
@@ -26,7 +28,24 @@ describe(Entity, () => {
26
28
  databaseFields: data,
27
29
  selectedFields: data,
28
30
  });
29
- expect(SimpleTestEntity.updater(testEntity)).toBeInstanceOf(UpdateMutator);
31
+ expect(SimpleTestEntity.updater(testEntity)).toBeInstanceOf(EntityUpdater);
32
+ });
33
+ });
34
+
35
+ describe('deleter', () => {
36
+ it('creates a new EntityDeleter', () => {
37
+ const companionProvider = createUnitTestEntityCompanionProvider();
38
+ const viewerContext = new ViewerContext(companionProvider);
39
+ const data = {
40
+ id: 'what',
41
+ };
42
+ const testEntity = new SimpleTestEntity({
43
+ viewerContext,
44
+ id: 'what',
45
+ databaseFields: data,
46
+ selectedFields: data,
47
+ });
48
+ expect(SimpleTestEntity.deleter(testEntity)).toBeInstanceOf(EntityDeleter);
30
49
  });
31
50
  });
32
51
  });
@@ -1,273 +1,30 @@
1
- import { enforceAsyncResult } from '@expo/results';
2
- import { v4 as uuidv4 } from 'uuid';
3
-
1
+ import AuthorizationResultBasedEntityAssociationLoader from '../AuthorizationResultBasedEntityAssociationLoader';
2
+ import EnforcingEntityAssociationLoader from '../EnforcingEntityAssociationLoader';
4
3
  import EntityAssociationLoader from '../EntityAssociationLoader';
5
- import { enforceResultsAsync } from '../entityUtils';
6
- import TestEntity from '../testfixtures/TestEntity';
7
- import TestEntity2 from '../testfixtures/TestEntity2';
8
- import TestViewerContext from '../testfixtures/TestViewerContext';
4
+ import ViewerContext from '../ViewerContext';
5
+ import SimpleTestEntity from '../testfixtures/SimpleTestEntity';
9
6
  import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
10
7
 
11
8
  describe(EntityAssociationLoader, () => {
12
- describe('loadAssociatedEntityAsync', () => {
13
- it('loads associated entities by ID and correctly handles a null value', async () => {
14
- const companionProvider = createUnitTestEntityCompanionProvider();
15
- const viewerContext = new TestViewerContext(companionProvider);
16
- const testOtherEntity = await enforceAsyncResult(
17
- TestEntity.creator(viewerContext).createAsync(),
18
- );
19
- const testEntity = await enforceAsyncResult(
20
- TestEntity.creator(viewerContext)
21
- .setField('stringField', testOtherEntity.getID())
22
- .createAsync(),
23
- );
24
- const loadedOther = await enforceAsyncResult(
25
- testEntity.associationLoader().loadAssociatedEntityAsync('stringField', TestEntity),
26
- );
27
- expect(loadedOther.getID()).toEqual(testOtherEntity.getID());
28
-
29
- const loadedOther2 = await enforceAsyncResult(
30
- testEntity.associationLoader().loadAssociatedEntityAsync('nullableField', TestEntity),
31
- );
32
- expect(loadedOther2).toBeNull();
33
- });
34
- });
35
-
36
- describe('loadManyAssociatedEntitiesAsync', () => {
37
- it('loads many associated entities referencing this entity', async () => {
38
- const companionProvider = createUnitTestEntityCompanionProvider();
39
- const viewerContext = new TestViewerContext(companionProvider);
40
- const testEntity = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
41
- const testOtherEntity1 = await enforceAsyncResult(
42
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
43
- );
44
- const testOtherEntity2 = await enforceAsyncResult(
45
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
46
- );
47
- const loaded = await enforceResultsAsync(
48
- testEntity.associationLoader().loadManyAssociatedEntitiesAsync(TestEntity, 'stringField'),
49
- );
50
- expect(loaded).toHaveLength(2);
51
- expect(loaded.find((e) => e.getID() === testOtherEntity1.getID())).not.toBeUndefined();
52
- expect(loaded.find((e) => e.getID() === testOtherEntity2.getID())).not.toBeUndefined();
53
- });
54
- });
55
-
56
- describe('loadAssociatedEntityByFieldEqualingAsync', () => {
57
- it('loads associated entity by field equaling', async () => {
9
+ describe('enforcing', () => {
10
+ it('creates a new EnforcingEntityLoader', async () => {
58
11
  const companionProvider = createUnitTestEntityCompanionProvider();
59
- const viewerContext = new TestViewerContext(companionProvider);
60
- const testOtherEntity = await enforceAsyncResult(
61
- TestEntity.creator(viewerContext).createAsync(),
12
+ const viewerContext = new ViewerContext(companionProvider);
13
+ const testEntity = await SimpleTestEntity.creator(viewerContext).enforcing().createAsync();
14
+ expect(testEntity.associationLoader().enforcing()).toBeInstanceOf(
15
+ EnforcingEntityAssociationLoader,
62
16
  );
63
- const testEntity = await enforceAsyncResult(
64
- TestEntity.creator(viewerContext)
65
- .setField('stringField', testOtherEntity.getID())
66
- .createAsync(),
67
- );
68
- const loadedOtherResult = await testEntity
69
- .associationLoader()
70
- .loadAssociatedEntityByFieldEqualingAsync('stringField', TestEntity, 'customIdField');
71
- expect(loadedOtherResult?.enforceValue().getID()).toEqual(testOtherEntity.getID());
72
- });
73
-
74
- it('returns null when loading associated entities by field equaling a non existent association', async () => {
75
- const companionProvider = createUnitTestEntityCompanionProvider();
76
- const viewerContext = new TestViewerContext(companionProvider);
77
- const testEntity = await enforceAsyncResult(
78
- TestEntity.creator(viewerContext).setField('stringField', uuidv4()).createAsync(),
79
- );
80
- const loadedOtherResult = await testEntity
81
- .associationLoader()
82
- .loadAssociatedEntityByFieldEqualingAsync('stringField', TestEntity, 'customIdField');
83
- expect(loadedOtherResult).toBeNull();
84
- });
85
-
86
- it('returns null when load-by field is null', async () => {
87
- const companionProvider = createUnitTestEntityCompanionProvider();
88
- const viewerContext = new TestViewerContext(companionProvider);
89
- const testEntity = await enforceAsyncResult(
90
- TestEntity.creator(viewerContext).setField('stringField', 'blah').createAsync(),
91
- );
92
- const loadedOtherResult = await testEntity
93
- .associationLoader()
94
- .loadAssociatedEntityByFieldEqualingAsync('nullableField', TestEntity, 'customIdField');
95
- expect(loadedOtherResult).toBeNull();
96
17
  });
97
18
  });
98
19
 
99
- describe('loadManyAssociatedEntitiesByFieldEqualingAsync', () => {
100
- it('loads many associated entities by field equaling', async () => {
20
+ describe('withAuthorizationResults', () => {
21
+ it('creates a new AuthorizationResultBasedEntityAssociationLoader', async () => {
101
22
  const companionProvider = createUnitTestEntityCompanionProvider();
102
- const viewerContext = new TestViewerContext(companionProvider);
103
- const testEntity = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
104
- const testOtherEntity1 = await enforceAsyncResult(
105
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
23
+ const viewerContext = new ViewerContext(companionProvider);
24
+ const testEntity = await SimpleTestEntity.creator(viewerContext).enforcing().createAsync();
25
+ expect(testEntity.associationLoader().withAuthorizationResults()).toBeInstanceOf(
26
+ AuthorizationResultBasedEntityAssociationLoader,
106
27
  );
107
- const testOtherEntity2 = await enforceAsyncResult(
108
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
109
- );
110
- const loaded = await enforceResultsAsync(
111
- testEntity
112
- .associationLoader()
113
- .loadManyAssociatedEntitiesByFieldEqualingAsync(
114
- 'customIdField',
115
- TestEntity,
116
- 'stringField',
117
- ),
118
- );
119
- expect(loaded).toHaveLength(2);
120
- expect(loaded.find((e) => e.getID() === testOtherEntity1.getID())).not.toBeUndefined();
121
- expect(loaded.find((e) => e.getID() === testOtherEntity2.getID())).not.toBeUndefined();
122
- });
123
-
124
- it('returns empty results when field being queried by is null', async () => {
125
- const companionProvider = createUnitTestEntityCompanionProvider();
126
- const viewerContext = new TestViewerContext(companionProvider);
127
- const testEntity = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
128
- const loaded = await enforceResultsAsync(
129
- testEntity
130
- .associationLoader()
131
- .loadManyAssociatedEntitiesByFieldEqualingAsync(
132
- 'nullableField',
133
- TestEntity,
134
- 'stringField',
135
- ),
136
- );
137
- expect(loaded).toHaveLength(0);
138
- });
139
- });
140
-
141
- describe('loadAssociatedEntityThroughAsync', () => {
142
- it('chain loads associated entities', async () => {
143
- const companionProvider = createUnitTestEntityCompanionProvider();
144
- const viewerContext = new TestViewerContext(companionProvider);
145
- const testEntity4 = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
146
- const testEntity3 = await enforceAsyncResult(
147
- TestEntity2.creator(viewerContext)
148
- .setField('foreignKey', testEntity4.getID())
149
- .createAsync(),
150
- );
151
- const testEntity2 = await enforceAsyncResult(
152
- TestEntity.creator(viewerContext)
153
- .setField('testIndexedField', testEntity3.getID())
154
- .createAsync(),
155
- );
156
- const testEntity = await enforceAsyncResult(
157
- TestEntity2.creator(viewerContext)
158
- .setField('foreignKey', testEntity2.getID())
159
- .createAsync(),
160
- );
161
-
162
- const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
163
- {
164
- associatedEntityClass: TestEntity,
165
- fieldIdentifyingAssociatedEntity: 'foreignKey',
166
- },
167
- ]);
168
- expect(loaded2Result?.enforceValue().getID()).toEqual(testEntity2.getID());
169
-
170
- const loaded3Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
171
- {
172
- associatedEntityClass: TestEntity,
173
- fieldIdentifyingAssociatedEntity: 'foreignKey',
174
- },
175
- {
176
- associatedEntityClass: TestEntity2,
177
- fieldIdentifyingAssociatedEntity: 'testIndexedField',
178
- },
179
- ]);
180
- expect(loaded3Result?.enforceValue().getID()).toEqual(testEntity3.getID());
181
-
182
- const loaded4Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
183
- {
184
- associatedEntityClass: TestEntity,
185
- fieldIdentifyingAssociatedEntity: 'foreignKey',
186
- },
187
- {
188
- associatedEntityClass: TestEntity2,
189
- fieldIdentifyingAssociatedEntity: 'testIndexedField',
190
- },
191
- {
192
- associatedEntityClass: TestEntity,
193
- fieldIdentifyingAssociatedEntity: 'foreignKey',
194
- },
195
- ]);
196
- expect(loaded4Result?.enforceValue().getID()).toEqual(testEntity4.getID());
197
- });
198
-
199
- it('fails when chain loading associated entity fails', async () => {
200
- const companionProvider = createUnitTestEntityCompanionProvider();
201
- const viewerContext = new TestViewerContext(companionProvider);
202
-
203
- const testEntity = await enforceAsyncResult(
204
- TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync(),
205
- );
206
-
207
- const loadResult = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
208
- {
209
- associatedEntityClass: TestEntity,
210
- fieldIdentifyingAssociatedEntity: 'foreignKey',
211
- },
212
- ]);
213
- expect(loadResult?.ok).toBe(false);
214
- });
215
-
216
- it('supports chain loading by field equality', async () => {
217
- const companionProvider = createUnitTestEntityCompanionProvider();
218
- const viewerContext = new TestViewerContext(companionProvider);
219
-
220
- const fieldValue = uuidv4();
221
- const testEntity2 = await enforceAsyncResult(
222
- TestEntity.creator(viewerContext).setField('stringField', fieldValue).createAsync(),
223
- );
224
- const testEntity = await enforceAsyncResult(
225
- TestEntity2.creator(viewerContext).setField('foreignKey', fieldValue).createAsync(),
226
- );
227
-
228
- const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
229
- {
230
- associatedEntityClass: TestEntity,
231
- fieldIdentifyingAssociatedEntity: 'foreignKey',
232
- associatedEntityLookupByField: 'stringField',
233
- },
234
- ]);
235
- expect(loaded2Result?.enforceValue().getID()).toEqual(testEntity2.getID());
236
- });
237
-
238
- it('returns null when chain loading by field equality returns null', async () => {
239
- const companionProvider = createUnitTestEntityCompanionProvider();
240
- const viewerContext = new TestViewerContext(companionProvider);
241
-
242
- const testEntity = await enforceAsyncResult(
243
- TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync(),
244
- );
245
-
246
- const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
247
- {
248
- associatedEntityClass: TestEntity,
249
- fieldIdentifyingAssociatedEntity: 'foreignKey',
250
- associatedEntityLookupByField: 'stringField',
251
- },
252
- ]);
253
- expect(loaded2Result).toBeNull();
254
- });
255
-
256
- it('returns null when chain loading by field is null', async () => {
257
- const companionProvider = createUnitTestEntityCompanionProvider();
258
- const viewerContext = new TestViewerContext(companionProvider);
259
-
260
- const testEntity = await enforceAsyncResult(
261
- TestEntity.creator(viewerContext).setField('nullableField', null).createAsync(),
262
- );
263
-
264
- const loadedResult = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
265
- {
266
- associatedEntityClass: TestEntity,
267
- fieldIdentifyingAssociatedEntity: 'nullableField',
268
- },
269
- ]);
270
- expect(loadedResult).toBeNull();
271
28
  });
272
29
  });
273
30
  });
@@ -118,15 +118,24 @@ it('runs through a common workflow', async () => {
118
118
  const vc2 = new TestUserViewerContext(entityCompanionProvider, uuidv4());
119
119
 
120
120
  const blahOwner1 = await enforceAsyncResult(
121
- BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
121
+ BlahEntity.creator(vc1)
122
+ .withAuthorizationResults()
123
+ .setField('ownerID', vc1.getUserID())
124
+ .createAsync(),
122
125
  );
123
126
 
124
127
  await enforceAsyncResult(
125
- BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
128
+ BlahEntity.creator(vc1)
129
+ .withAuthorizationResults()
130
+ .setField('ownerID', vc1.getUserID())
131
+ .createAsync(),
126
132
  );
127
133
 
128
134
  const blahOwner2 = await enforceAsyncResult(
129
- BlahEntity.creator(vc2).setField('ownerID', vc2.getUserID()!).createAsync(),
135
+ BlahEntity.creator(vc2)
136
+ .withAuthorizationResults()
137
+ .setField('ownerID', vc2.getUserID())
138
+ .createAsync(),
130
139
  );
131
140
 
132
141
  // sanity check created objects
@@ -149,14 +158,17 @@ it('runs through a common workflow', async () => {
149
158
  const results = await enforceResultsAsync(
150
159
  BlahEntity.loader(vc1)
151
160
  .withAuthorizationResults()
152
- .loadManyByFieldEqualingAsync('ownerID', vc1.getUserID()!),
161
+ .loadManyByFieldEqualingAsync('ownerID', vc1.getUserID()),
153
162
  );
154
163
  expect(results).toHaveLength(2);
155
164
 
156
165
  // check that two people can't create objects owned by others
157
166
  await expect(
158
167
  enforceAsyncResult(
159
- BlahEntity.creator(vc2).setField('ownerID', blahOwner1.getID()).createAsync(),
168
+ BlahEntity.creator(vc2)
169
+ .withAuthorizationResults()
170
+ .setField('ownerID', blahOwner1.getID())
171
+ .createAsync(),
160
172
  ),
161
173
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
162
174
 
@@ -169,7 +181,7 @@ it('runs through a common workflow', async () => {
169
181
  }
170
182
 
171
183
  // check that the user can't delete their own data (as specified by privacy rules)
172
- await expect(enforceAsyncResult(BlahEntity.deleteAsync(blahOwner2))).rejects.toBeInstanceOf(
173
- EntityNotAuthorizedError,
174
- );
184
+ await expect(
185
+ enforceAsyncResult(BlahEntity.deleter(blahOwner2).withAuthorizationResults().deleteAsync()),
186
+ ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
175
187
  });
@@ -72,7 +72,7 @@ describe(EntityCompanion, () => {
72
72
 
73
73
  expect(mergedTriggers).toStrictEqual({
74
74
  afterCreate: [localTriggers!.afterCreate![0], globalMutationTriggers.afterCreate![0]],
75
- afterAll: [localTriggers!.afterAll![0], globalMutationTriggers!.afterAll![0]],
75
+ afterAll: [localTriggers!.afterAll![0], globalMutationTriggers.afterAll![0]],
76
76
  afterCommit: [localTriggers!.afterCommit![0]],
77
77
  });
78
78
  });
@@ -9,12 +9,12 @@ import { FieldTransformerMap } from '../internal/EntityFieldTransformationUtils'
9
9
  import { TestFields, testEntityConfiguration } from '../testfixtures/TestEntity';
10
10
 
11
11
  class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
12
- private fetchResults: object[];
13
- private insertResults: object[];
14
- private updateResults: object[];
15
- private fetchEqualityConditionResults: object[];
16
- private fetchRawWhereResults: object[];
17
- private deleteCount: number;
12
+ private readonly fetchResults: object[];
13
+ private readonly insertResults: object[];
14
+ private readonly updateResults: object[];
15
+ private readonly fetchEqualityConditionResults: object[];
16
+ private readonly fetchRawWhereResults: object[];
17
+ private readonly deleteCount: number;
18
18
 
19
19
  constructor({
20
20
  fetchResults = [],