@intellegens/cornerstone-client 0.0.9999-alpha-41 → 0.0.9999-alpha-43

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 (233) hide show
  1. package/dist/adapters/collection-view-adapter.d.ts +123 -0
  2. package/dist/adapters/collection-view-adapter.integration.test.d.ts +1 -0
  3. package/dist/adapters/collection-view-adapter.integration.test.js +141 -0
  4. package/dist/adapters/collection-view-adapter.js +352 -0
  5. package/dist/adapters/index.d.ts +2 -2
  6. package/dist/adapters/index.js +2 -2
  7. package/dist/adapters/search-adapter.d.ts +83 -0
  8. package/dist/adapters/search-adapter.js +284 -0
  9. package/dist/data/api/dto/crud/crud-metadata-dto.js +1 -0
  10. package/dist/data/api/dto/crud/index.d.ts +1 -1
  11. package/dist/data/api/dto/crud/index.js +1 -1
  12. package/dist/data/api/dto/index.d.ts +1 -1
  13. package/dist/data/api/dto/index.js +1 -1
  14. package/dist/data/api/dto/property-path-dto.d.ts +4 -0
  15. package/dist/data/api/dto/property-path-dto.js +1 -0
  16. package/dist/data/api/dto/read/index.d.ts +10 -10
  17. package/dist/data/api/dto/read/index.js +10 -10
  18. package/dist/data/api/dto/read/read-metadata-dto.d.ts +8 -0
  19. package/dist/data/api/dto/read/read-metadata-dto.js +1 -0
  20. package/dist/data/api/dto/read/read-selected-definition-dto.d.ts +18 -0
  21. package/dist/data/api/dto/read/read-selected-definition-dto.js +1 -0
  22. package/dist/data/api/dto/read/read-selected-nested-collection-criteria-dto.d.ts +22 -0
  23. package/dist/data/api/dto/read/read-selected-nested-collection-criteria-dto.js +1 -0
  24. package/dist/data/api/dto/read/read-selected-nested-criteria-dto.d.ts +18 -0
  25. package/dist/data/api/dto/read/read-selected-nested-criteria-dto.js +1 -0
  26. package/dist/data/api/dto/read/read-selected-ordering-definition-dto.d.ts +7 -0
  27. package/dist/data/api/dto/read/read-selected-ordering-definition-dto.js +1 -0
  28. package/dist/data/api/dto/read/read-selected-ordering-property-definition-dto.d.ts +14 -0
  29. package/dist/data/api/dto/read/read-selected-ordering-property-definition-dto.js +1 -0
  30. package/dist/data/api/dto/read/read-selected-pagination-definition-dto.d.ts +13 -0
  31. package/dist/data/api/dto/read/read-selected-pagination-definition-dto.js +1 -0
  32. package/dist/data/api/dto/read/read-selected-search-definition-builder.d.ts +167 -0
  33. package/dist/data/api/dto/read/read-selected-search-definition-builder.js +267 -0
  34. package/dist/data/api/dto/read/read-selected-search-definition-dto.d.ts +33 -0
  35. package/dist/data/api/dto/read/read-selected-search-definition-dto.js +1 -0
  36. package/dist/data/api/dto/read/read-selected-search-property-definition-dto.d.ts +114 -0
  37. package/dist/data/api/dto/read/read-selected-search-property-definition-dto.js +1 -0
  38. package/dist/data/api/dto/read-options-dto.d.ts +8 -0
  39. package/dist/data/api/dto/read-options-dto.js +1 -0
  40. package/dist/data/api/dto/read-result-dto.d.ts +12 -0
  41. package/dist/data/api/dto/read-result-dto.js +1 -0
  42. package/dist/data/api/dto/read-result-metadata-dto.d.ts +8 -0
  43. package/dist/data/api/dto/read-result-metadata-dto.js +1 -0
  44. package/dist/data/api/dto/response/api-error-dto.d.ts +17 -0
  45. package/dist/data/api/dto/response/api-error-dto.js +1 -0
  46. package/dist/data/api/dto/response/api-error-response-dto.d.ts +11 -0
  47. package/dist/data/api/dto/response/api-error-response-dto.js +1 -0
  48. package/dist/data/api/dto/response/api-response-dto.d.ts +3 -0
  49. package/dist/data/api/dto/response/api-response-dto.js +1 -0
  50. package/dist/data/api/dto/response/api-success-response-dto.d.ts +13 -0
  51. package/dist/data/api/dto/response/api-success-response-dto.js +1 -0
  52. package/dist/data/api/dto/response/index.d.ts +5 -5
  53. package/dist/data/api/dto/response/index.js +5 -5
  54. package/dist/data/api/dto/response/metadata-dto.d.ts +25 -0
  55. package/dist/data/api/dto/response/metadata-dto.js +1 -0
  56. package/dist/data/api/enum/read/index.d.ts +5 -5
  57. package/dist/data/api/enum/read/index.js +5 -5
  58. package/dist/data/api/enum/read/read-selected-collection-operator.d.ts +16 -0
  59. package/dist/data/api/enum/read/read-selected-collection-operator.js +17 -0
  60. package/dist/data/api/enum/read/read-selected-comparison-operator.d.ts +69 -0
  61. package/dist/data/api/enum/read/read-selected-comparison-operator.js +76 -0
  62. package/dist/data/api/enum/read/read-selected-logical-operator.d.ts +15 -0
  63. package/dist/data/api/enum/read/read-selected-logical-operator.js +16 -0
  64. package/dist/data/api/enum/read/read-selected-ordering-direction.d.ts +13 -0
  65. package/dist/data/api/enum/read/read-selected-ordering-direction.js +14 -0
  66. package/dist/data/api/enum/read/read-selected-property-type.d.ts +66 -0
  67. package/dist/data/api/enum/read/read-selected-property-type.js +75 -0
  68. package/dist/data/api/enum/response/error-code.d.ts +14 -0
  69. package/dist/data/api/enum/response/error-code.js +15 -0
  70. package/dist/data/api/enum/response/index.d.ts +1 -1
  71. package/dist/data/api/enum/response/index.js +1 -1
  72. package/dist/data/api/interface/icommon-identifiable.d.ts +7 -0
  73. package/dist/data/api/interface/icommon-identifiable.js +1 -0
  74. package/dist/data/api/interface/iconcurrency-safe.d.ts +9 -0
  75. package/dist/data/api/interface/iconcurrency-safe.js +1 -0
  76. package/dist/data/api/interface/iidentifiable-secondary.d.ts +9 -0
  77. package/dist/data/api/interface/iidentifiable-secondary.js +1 -0
  78. package/dist/data/api/interface/iidentifiable.d.ts +11 -0
  79. package/dist/data/api/interface/iidentifiable.js +1 -0
  80. package/dist/data/api/interface/index.d.ts +4 -3
  81. package/dist/data/api/interface/index.js +4 -3
  82. package/dist/data/auth/dto/claim-dto.d.ts +4 -0
  83. package/dist/data/auth/dto/claim-dto.js +1 -0
  84. package/dist/data/auth/dto/index.d.ts +6 -5
  85. package/dist/data/auth/dto/index.js +6 -5
  86. package/dist/data/auth/dto/register-request-dto.d.ts +4 -0
  87. package/dist/data/auth/dto/register-request-dto.js +1 -0
  88. package/dist/data/auth/dto/role-dto.d.ts +5 -0
  89. package/dist/data/auth/dto/role-dto.js +1 -0
  90. package/dist/data/auth/dto/role-with-claims-dto.d.ts +5 -0
  91. package/dist/data/auth/dto/role-with-claims-dto.js +1 -0
  92. package/dist/data/auth/dto/sign-in-request-dto.d.ts +4 -0
  93. package/dist/data/auth/dto/sign-in-request-dto.js +1 -0
  94. package/dist/data/auth/dto/tokens-dto.d.ts +4 -0
  95. package/dist/data/auth/dto/tokens-dto.js +1 -0
  96. package/dist/data/auth/dto/user-dto.d.ts +16 -0
  97. package/dist/data/auth/dto/user-dto.js +1 -0
  98. package/dist/data/auth/dto/user-info-dto.d.ts +14 -0
  99. package/dist/data/auth/dto/user-info-dto.js +1 -0
  100. package/dist/services/api/api-crud-controller-client.d.ts +62 -0
  101. package/dist/services/api/api-crud-controller-client.integration.test.d.ts +1 -0
  102. package/dist/services/api/api-crud-controller-client.integration.test.js +34 -0
  103. package/dist/services/api/api-crud-controller-client.js +133 -0
  104. package/dist/services/api/api-initialization-service.d.ts +106 -0
  105. package/dist/services/api/api-initialization-service.js +207 -0
  106. package/dist/services/api/api-read-controller-client.d.ts +62 -0
  107. package/dist/services/api/api-read-controller-client.integration.test.d.ts +1 -0
  108. package/dist/services/api/api-read-controller-client.integration.test.js +59 -0
  109. package/dist/services/api/api-read-controller-client.js +129 -0
  110. package/dist/services/api/http-service/fetch-http-service.d.ts +7 -0
  111. package/dist/services/api/http-service/fetch-http-service.integration.test.d.ts +1 -0
  112. package/dist/services/api/http-service/fetch-http-service.integration.test.js +52 -0
  113. package/dist/services/api/http-service/fetch-http-service.js +29 -0
  114. package/dist/services/api/http-service/http-request-config.d.ts +10 -0
  115. package/dist/services/api/http-service/http-request-config.js +1 -0
  116. package/dist/services/api/http-service/http-response.d.ts +11 -0
  117. package/dist/services/api/http-service/http-response.js +3 -0
  118. package/dist/services/api/http-service/http-service.d.ts +5 -0
  119. package/dist/services/api/http-service/http-service.js +5 -0
  120. package/dist/services/api/http-service/ihttp-service.d.ts +13 -0
  121. package/dist/services/api/http-service/ihttp-service.js +3 -0
  122. package/dist/services/api/http-service/index.d.ts +5 -0
  123. package/dist/services/api/http-service/index.js +5 -0
  124. package/dist/services/api/index.d.ts +5 -5
  125. package/dist/services/api/index.js +5 -5
  126. package/dist/services/api/user-management-controller-client.d.ts +80 -0
  127. package/dist/services/api/user-management-controller-client.integration.test.d.ts +1 -0
  128. package/dist/services/api/user-management-controller-client.integration.test.js +60 -0
  129. package/dist/services/api/user-management-controller-client.js +291 -0
  130. package/dist/services/auth/client/auth-service.d.ts +75 -0
  131. package/dist/services/auth/client/auth-service.js +200 -0
  132. package/dist/services/auth/client/authorization-management-controller-client.d.ts +48 -0
  133. package/dist/services/auth/client/authorization-management-controller-client.integration.test.d.ts +1 -0
  134. package/dist/services/auth/client/authorization-management-controller-client.integration.test.js +89 -0
  135. package/dist/services/auth/client/authorization-management-controller-client.js +148 -0
  136. package/dist/services/auth/client/index.d.ts +2 -2
  137. package/dist/services/auth/client/index.js +2 -2
  138. package/dist/utils/authorization.d.ts +17 -0
  139. package/dist/utils/authorization.js +45 -0
  140. package/dist/utils/events.d.ts +19 -0
  141. package/dist/utils/events.js +12 -0
  142. package/dist/utils/index.d.ts +2 -0
  143. package/dist/utils/index.js +2 -0
  144. package/dist/utils/result.d.ts +21 -0
  145. package/dist/utils/result.js +16 -0
  146. package/dist/utils/search.d.ts +34 -0
  147. package/dist/utils/search.js +106 -0
  148. package/package.json +6 -6
  149. package/src/adapters/collection-view-adapter.integration.test.ts +172 -0
  150. package/src/adapters/collection-view-adapter.ts +458 -0
  151. package/src/adapters/index.ts +2 -2
  152. package/src/adapters/search-adapter.ts +374 -0
  153. package/src/data/api/dto/crud/crud-metadata-dto.ts +4 -0
  154. package/src/data/api/dto/crud/index.ts +1 -1
  155. package/src/data/api/dto/index.ts +1 -1
  156. package/src/data/api/dto/read/index.ts +10 -10
  157. package/src/data/api/dto/read/{ReadSelectedSearchDefinitionBuilder.ts → read-selected-search-definition-builder.ts} +4 -4
  158. package/src/data/api/dto/{ReadResultDto.ts → read-result-dto.ts} +1 -1
  159. package/src/data/api/dto/response/{ApiErrorDto.ts → api-error-dto.ts} +1 -1
  160. package/src/data/api/dto/response/index.ts +5 -5
  161. package/src/data/api/enum/read/index.ts +5 -5
  162. package/src/data/api/enum/response/{ErrorCode.ts → error-code.ts} +1 -0
  163. package/src/data/api/enum/response/index.ts +1 -1
  164. package/src/data/api/interface/{ICommonIdentifiable.ts → icommon-identifiable.ts} +1 -1
  165. package/src/data/api/interface/{IConcurrencySafe.ts → iconcurrency-safe.ts} +1 -1
  166. package/src/data/api/interface/{IIdentifiable.ts → iidentifiable.ts} +1 -1
  167. package/src/data/api/interface/index.ts +4 -3
  168. package/src/data/auth/dto/index.ts +6 -5
  169. package/src/data/auth/dto/role-with-claims-dto.ts +6 -0
  170. package/src/data/auth/dto/{UserDto.ts → user-dto.ts} +5 -6
  171. package/src/services/api/{ApiCrudControllerClient/index.integration.test.ts → api-crud-controller-client.integration.test.ts} +1 -1
  172. package/src/services/api/{ApiCrudControllerClient/index.ts → api-crud-controller-client.ts} +62 -7
  173. package/src/services/api/{ApiInitializationService/index.ts → api-initialization-service.ts} +2 -4
  174. package/src/services/api/{ApiReadControllerClient/index.integration.test.ts → api-read-controller-client.integration.test.ts} +1 -1
  175. package/src/services/api/{ApiReadControllerClient/index.ts → api-read-controller-client.ts} +55 -6
  176. package/src/services/api/{HttpService/FetchHttpService.integration.test.ts → http-service/fetch-http-service.integration.test.ts} +1 -1
  177. package/src/services/api/http-service/http-service.ts +6 -0
  178. package/src/services/api/http-service/index.ts +5 -0
  179. package/src/services/api/index.ts +5 -5
  180. package/src/services/api/{UserManagementControllerClient/index.integration.test.ts → user-management-controller-client.integration.test.ts} +1 -1
  181. package/src/services/api/user-management-controller-client.ts +322 -0
  182. package/src/services/auth/client/index.ts +2 -2
  183. package/src/utils/events.ts +29 -0
  184. package/src/utils/index.ts +2 -0
  185. package/demo/index.ts +0 -29
  186. package/demo/public_html/favicon.ico +0 -0
  187. package/demo/public_html/index.html +0 -105
  188. package/demo/public_html/websettings.json +0 -3
  189. package/src/adapters/CollectionViewAdapter/index.integration.test.ts +0 -197
  190. package/src/adapters/CollectionViewAdapter/index.ts +0 -477
  191. package/src/adapters/SearchAdapter/index.ts +0 -302
  192. package/src/services/api/HttpService/index.ts +0 -12
  193. package/src/services/api/UserManagementControllerClient/index.ts +0 -134
  194. /package/{src/data/api/dto/crud/CrudMetadataDto.ts → dist/data/api/dto/crud/crud-metadata-dto.d.ts} +0 -0
  195. /package/src/data/api/dto/{PropertyPathDto.ts → property-path-dto.ts} +0 -0
  196. /package/src/data/api/dto/read/{ReadMetadataDto.ts → read-metadata-dto.ts} +0 -0
  197. /package/src/data/api/dto/read/{ReadSelectedDefinitionDto.ts → read-selected-definition-dto.ts} +0 -0
  198. /package/src/data/api/dto/read/{ReadSelectedNestedCollectionCriteriaDto.ts → read-selected-nested-collection-criteria-dto.ts} +0 -0
  199. /package/src/data/api/dto/read/{ReadSelectedNestedCriteriaDto.ts → read-selected-nested-criteria-dto.ts} +0 -0
  200. /package/src/data/api/dto/read/{ReadSelectedOrderingDefinitionDto.ts → read-selected-ordering-definition-dto.ts} +0 -0
  201. /package/src/data/api/dto/read/{ReadSelectedOrderingPropertyDefinitionDto.ts → read-selected-ordering-property-definition-dto.ts} +0 -0
  202. /package/src/data/api/dto/read/{ReadSelectedPaginationDefinitionDto.ts → read-selected-pagination-definition-dto.ts} +0 -0
  203. /package/src/data/api/dto/read/{ReadSelectedSearchDefinitionDto.ts → read-selected-search-definition-dto.ts} +0 -0
  204. /package/src/data/api/dto/read/{ReadSelectedSearchPropertyDefinitionDto.ts → read-selected-search-property-definition-dto.ts} +0 -0
  205. /package/src/data/api/dto/{ReadOptionsDto.ts → read-options-dto.ts} +0 -0
  206. /package/src/data/api/dto/{ReadResultMetadataDto.ts → read-result-metadata-dto.ts} +0 -0
  207. /package/src/data/api/dto/response/{ApiErrorResponseDto.ts → api-error-response-dto.ts} +0 -0
  208. /package/src/data/api/dto/response/{ApiResponseDto.ts → api-response-dto.ts} +0 -0
  209. /package/src/data/api/dto/response/{ApiSuccessResponseDto.ts → api-success-response-dto.ts} +0 -0
  210. /package/src/data/api/dto/response/{MetadataDto.ts → metadata-dto.ts} +0 -0
  211. /package/src/data/api/enum/read/{ReadSelectedCollectionOperator.ts → read-selected-collection-operator.ts} +0 -0
  212. /package/src/data/api/enum/read/{ReadSelectedComparisonOperator.ts → read-selected-comparison-operator.ts} +0 -0
  213. /package/src/data/api/enum/read/{ReadSelectedLogicalOperator.ts → read-selected-logical-operator.ts} +0 -0
  214. /package/src/data/api/enum/read/{ReadSelectedOrderingDirection.ts → read-selected-ordering-direction.ts} +0 -0
  215. /package/src/data/api/enum/read/{ReadSelectedPropertyType.ts → read-selected-property-type.ts} +0 -0
  216. /package/src/data/api/interface/{IIdentifiableSecondary.ts → iidentifiable-secondary.ts} +0 -0
  217. /package/src/data/auth/dto/{ClaimDto.ts → claim-dto.ts} +0 -0
  218. /package/src/data/auth/dto/{RegisterRequestDto.ts → register-request-dto.ts} +0 -0
  219. /package/src/data/auth/dto/{RoleDto.ts → role-dto.ts} +0 -0
  220. /package/src/data/auth/dto/{SignInRequestDto.ts → sign-in-request-dto.ts} +0 -0
  221. /package/src/data/auth/dto/{TokensDto.ts → tokens-dto.ts} +0 -0
  222. /package/src/data/auth/dto/{UserInfoDto.ts → user-info-dto.ts} +0 -0
  223. /package/src/services/api/{HttpService → http-service}/README.md +0 -0
  224. /package/src/services/api/{HttpService/FetchHttpService.ts → http-service/fetch-http-service.ts} +0 -0
  225. /package/src/services/api/{HttpService/HttpRequestConfig.ts → http-service/http-request-config.ts} +0 -0
  226. /package/src/services/api/{HttpService/HttpResponse.ts → http-service/http-response.ts} +0 -0
  227. /package/src/services/api/{HttpService/IHttpService.ts → http-service/ihttp-service.ts} +0 -0
  228. /package/src/services/auth/client/{AuthService/index.ts → auth-service.ts} +0 -0
  229. /package/src/services/auth/client/{AuthorizationManagementControllerClient/index.integration.test.ts → authorization-management-controller-client.integration.test.ts} +0 -0
  230. /package/src/services/auth/client/{AuthorizationManagementControllerClient/index.ts → authorization-management-controller-client.ts} +0 -0
  231. /package/src/utils/{authorization/index.ts → authorization.ts} +0 -0
  232. /package/src/utils/{result/index.ts → result.ts} +0 -0
  233. /package/src/utils/{search/index.ts → search.ts} +0 -0
@@ -0,0 +1,172 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { CollectionViewAdapter, CollectionViewAdapterOptions } from '.';
3
+ import { ReadSelectedComparisonOperator, ReadSelectedOrderingDirection, ReadSelectedPropertyType } from '@/data';
4
+ import { dateInterval, searchTerm } from '@/utils';
5
+ import { ApiReadControllerClient } from '@services';
6
+
7
+ type TestDto = { id: number; name: string; dateOfBirth: string; rowVersion: string };
8
+
9
+ describe('CollectionViewAdapter', () => {
10
+ const options: CollectionViewAdapterOptions<TestDto> = {
11
+ primaryKey: 'id',
12
+ pagination: { defaultPageSize: 5, defaultPageIndex: 0 },
13
+ ordering: { maxOrderingColumns: 1 },
14
+ };
15
+
16
+ let adapter: CollectionViewAdapter<TestDto>;
17
+
18
+ const waitForData = async (adapterInstance: CollectionViewAdapter<TestDto>, timeout = 2000) => {
19
+ const start = Date.now();
20
+ while (adapterInstance.isLoading && Date.now() - start < timeout) {
21
+ await new Promise(res => setTimeout(res, 50));
22
+ }
23
+ };
24
+
25
+ beforeEach(() => {
26
+ options.pagination = { defaultPageSize: 5, defaultPageIndex: 0 };
27
+ options.ordering = { maxOrderingColumns: 1 };
28
+ });
29
+
30
+ it('returns correct loading status and collection data', async () => {
31
+ adapter = new CollectionViewAdapter(options, 'AnythingManuallyMappedRead');
32
+ await waitForData(adapter);
33
+
34
+ expect(adapter.isLoading).toBe(false);
35
+ expect(adapter.pageData).toBeDefined();
36
+ expect(adapter.pageData!.length).toBeGreaterThan(0);
37
+ expect(adapter.error).toBeUndefined();
38
+ });
39
+
40
+ it('adapter options set correct ordering', async () => {
41
+ adapter = new CollectionViewAdapter(options, 'AnythingManuallyMappedRead');
42
+ await waitForData(adapter);
43
+ adapter.setOrdering(['name'], ReadSelectedOrderingDirection.Descending);
44
+ await waitForData(adapter);
45
+
46
+ expect(adapter.ordering).toEqual([
47
+ {
48
+ path: ['name'],
49
+ direction: ReadSelectedOrderingDirection.Descending,
50
+ },
51
+ ]);
52
+ });
53
+
54
+ it('text search is applied to adapter', async () => {
55
+ const searchDefinition = searchTerm('Flu', ['name'], ['id']);
56
+ if (!searchDefinition) throw new Error('searchDefinition is undefined');
57
+ adapter = new CollectionViewAdapter(options, new ApiReadControllerClient<number, TestDto, TestDto>('AnythingManuallyMappedRead'));
58
+ await waitForData(adapter);
59
+ adapter.setSearch(searchDefinition);
60
+ await waitForData(adapter);
61
+
62
+ expect(adapter.pageData).toBeDefined();
63
+ expect(adapter.pageData!.length).toBeGreaterThan(0);
64
+ for (const item of adapter.pageData!) {
65
+ expect(item.name).toMatch(/flu/i);
66
+ }
67
+ });
68
+
69
+ it('numeric search is applied to adapter', async () => {
70
+ const searchDefinition = searchTerm('10000001', ['id'], ['id']);
71
+ if (!searchDefinition) throw new Error('searchDefinition is undefined');
72
+ adapter = new CollectionViewAdapter(options, new ApiReadControllerClient<number, TestDto, TestDto>('AnythingManuallyMappedRead'));
73
+ await waitForData(adapter);
74
+ adapter.setSearch(searchDefinition);
75
+ await waitForData(adapter);
76
+
77
+ expect(adapter.pageData).toBeDefined();
78
+ expect(adapter.pageData!.length).toBe(1);
79
+ for (const item of adapter.pageData!) {
80
+ expect(item.id).toBe(10000001);
81
+ }
82
+ });
83
+
84
+ it('applies date range filter from-to on the same date type property', async () => {
85
+ adapter = new CollectionViewAdapter(options, new ApiReadControllerClient<number, TestDto, TestDto>('PetsSlim'));
86
+ const from = new Date('2017-01-01T00:00:00.000Z');
87
+ const to = new Date('2017-12-31T00:00:00.000Z');
88
+
89
+ const searchDefinition = dateInterval<TestDto>(
90
+ from,
91
+ to,
92
+ ReadSelectedComparisonOperator.GreaterOrEqual,
93
+ ReadSelectedComparisonOperator.LessOrEqual,
94
+ ReadSelectedPropertyType.DateOnly,
95
+ 'dateOfBirth',
96
+ );
97
+ if (!searchDefinition) throw new Error('searchDefinition is undefined');
98
+ await waitForData(adapter);
99
+ adapter.setSearch(searchDefinition);
100
+ await waitForData(adapter);
101
+
102
+ expect(adapter.pageData).toBeDefined();
103
+ });
104
+
105
+ it('applies pagination: page size and jump to page set skip/limit', async () => {
106
+ adapter = new CollectionViewAdapter(options, 'AnythingManuallyMappedRead');
107
+ await waitForData(adapter);
108
+ const firstPageData = [...adapter.pageData!];
109
+ adapter.setPageIndex(3);
110
+ await waitForData(adapter);
111
+
112
+ expect(adapter.pageData).toBeDefined();
113
+ expect(adapter.pageData!.length).toBe(5);
114
+ expect([...adapter.pageData!]).not.toEqual(firstPageData);
115
+ });
116
+
117
+ it('calculates total when server does not return totalCount', async () => {
118
+ options.pagination = { defaultPageSize: 10, defaultPageIndex: 0 };
119
+ adapter = new CollectionViewAdapter(options, 'AnythingManuallyMappedRead');
120
+ await waitForData(adapter);
121
+ const firstPageLength = adapter.pageData!.length;
122
+ adapter.setPageIndex(2);
123
+ await waitForData(adapter);
124
+
125
+ expect(adapter.totalItemCount).toBe(firstPageLength + adapter.pageData!.length);
126
+ });
127
+
128
+ it('setOrdering correctly handles PropertyPathDto array comparison and limits columns', async () => {
129
+ options.ordering = { maxOrderingColumns: 2 };
130
+ adapter = new CollectionViewAdapter(options, 'AnythingManuallyMappedRead');
131
+ adapter.setOrdering(['name'], ReadSelectedOrderingDirection.Descending);
132
+ await waitForData(adapter);
133
+
134
+ expect(adapter.ordering).toEqual([
135
+ {
136
+ path: ['name'],
137
+ direction: ReadSelectedOrderingDirection.Descending,
138
+ },
139
+ ]);
140
+
141
+ // Add second ordering
142
+ adapter.setOrdering(['id'], ReadSelectedOrderingDirection.Ascending);
143
+ await waitForData(adapter);
144
+
145
+ // Should have both orderings, with 'id' first (most recent)
146
+ expect(adapter.ordering).toEqual([
147
+ {
148
+ path: ['id'],
149
+ direction: ReadSelectedOrderingDirection.Ascending,
150
+ },
151
+ {
152
+ path: ['name'],
153
+ direction: ReadSelectedOrderingDirection.Descending,
154
+ },
155
+ ]);
156
+
157
+ // Add third ordering - should remove the oldest one (name)
158
+ adapter.setOrdering(['description'], ReadSelectedOrderingDirection.Descending);
159
+ await waitForData(adapter);
160
+
161
+ expect(adapter.ordering).toEqual([
162
+ {
163
+ path: ['description'],
164
+ direction: ReadSelectedOrderingDirection.Descending,
165
+ },
166
+ {
167
+ path: ['id'],
168
+ direction: ReadSelectedOrderingDirection.Ascending,
169
+ },
170
+ ]);
171
+ });
172
+ });
@@ -0,0 +1,458 @@
1
+ import {
2
+ ErrorCode,
3
+ PropertyPathDto,
4
+ ReadSelectedDefinitionDto,
5
+ ReadSelectedLogicalOperator,
6
+ ReadSelectedOrderingDirection,
7
+ ReadSelectedSearchDefinitionDto,
8
+ } from '@data';
9
+ import { IHasObservableProperty, SingularEventTarget, toPascalCase } from '@utils';
10
+ import { ApiReadControllerClient } from '@services';
11
+ import { IReadSelectedClient } from '@services/api';
12
+
13
+ /**
14
+ * Options for the CollectionViewAdapter
15
+ */
16
+ export type CollectionViewAdapterOptions<TDto> = {
17
+ pagination?: {
18
+ defaultPageSize?: number;
19
+ defaultPageIndex?: number;
20
+ };
21
+ ordering?: {
22
+ maxOrderingColumns?: number;
23
+ defaultOrdering?: {
24
+ path: PropertyPathDto;
25
+ direction: ReadSelectedOrderingDirection;
26
+ }[];
27
+ };
28
+ search?: {
29
+ defaultSearch?: ReadSelectedSearchDefinitionDto<TDto>;
30
+ };
31
+ } & {
32
+ primaryKey: string | ((item: TDto) => string);
33
+ selection?: {
34
+ enabled: 'single' | 'multiple' | false;
35
+ defaultSelection?: TDto[];
36
+ };
37
+ };
38
+
39
+ /**
40
+ * Adapter for managing a collection view of data
41
+ */
42
+ export interface ICollectionViewAdapter<TDto>
43
+ extends
44
+ IHasObservableProperty<'isLoading', boolean>,
45
+ IHasObservableProperty<'pageData', readonly TDto[] | undefined>,
46
+ IHasObservableProperty<'error', string | undefined>,
47
+ IHasObservableProperty<'totalItemCount', number>,
48
+ IHasObservableProperty<'pageIndex', number>,
49
+ IHasObservableProperty<'pageSize', number>,
50
+ IHasObservableProperty<'ordering', readonly { path: PropertyPathDto; direction: ReadSelectedOrderingDirection }[]>,
51
+ IHasObservableProperty<'selection', readonly TDto[]>,
52
+ IHasObservableProperty<'search', ReadSelectedSearchDefinitionDto<TDto>> {
53
+ setSearch(searchDefinition: ReadSelectedSearchDefinitionDto<TDto>): void;
54
+
55
+ setOrdering(propertyPath: PropertyPathDto, orderDirection: ReadSelectedOrderingDirection): void;
56
+
57
+ setPageIndex(pageNumber: number): void;
58
+ setPageSize(pageSize: number): void;
59
+ refreshData(): void;
60
+
61
+ selectionToggle(item: TDto): void;
62
+ selectionAdd(item: TDto): void;
63
+ selectionRemove(item: TDto): void;
64
+ selectionClear(): void;
65
+ isSelected(item: TDto): boolean;
66
+ selectionAddPage(): void;
67
+ selectionRemovePage(): void;
68
+ isSelectedPage(): boolean;
69
+ isSomeSelectedPage(): boolean;
70
+
71
+ destroy(): void;
72
+ }
73
+
74
+ /**
75
+ * Adapter for managing a collection view of data
76
+ */
77
+ export class CollectionViewAdapter<TDto> implements ICollectionViewAdapter<TDto> {
78
+ // #region Event targets
79
+
80
+ public readonly isLoadingChanged = new SingularEventTarget<boolean>();
81
+ public readonly pageDataChanged = new SingularEventTarget<readonly TDto[] | undefined>();
82
+ public readonly errorChanged = new SingularEventTarget<string | undefined>();
83
+ public readonly totalItemCountChanged = new SingularEventTarget<number>();
84
+ public readonly pageIndexChanged = new SingularEventTarget<number>();
85
+ public readonly pageSizeChanged = new SingularEventTarget<number>();
86
+ public readonly selectionChanged = new SingularEventTarget<readonly TDto[]>();
87
+ public readonly searchChanged = new SingularEventTarget<ReadSelectedSearchDefinitionDto<TDto> | undefined>();
88
+ public readonly orderingChanged = new SingularEventTarget<readonly { path: PropertyPathDto; direction: ReadSelectedOrderingDirection }[]>();
89
+ // #endregion
90
+
91
+ private _readClient: IReadSelectedClient<any, any>;
92
+
93
+ private _isLoading = false;
94
+ private _pageData: TDto[] | undefined = undefined;
95
+ private _error: string | undefined = undefined;
96
+ private _totalItemCount = 0;
97
+ private _pageIndex = 0;
98
+ private _pageSize = 0;
99
+ private _selection: TDto[] = [];
100
+ private _search: ReadSelectedSearchDefinitionDto<TDto> = { logicalOperator: ReadSelectedLogicalOperator.And };
101
+ private _ordering: { path: PropertyPathDto; direction: ReadSelectedOrderingDirection }[] = [];
102
+ private _currentAbortController?: AbortController;
103
+ private _fetchTimeout?: ReturnType<typeof setTimeout>;
104
+
105
+ private _defaultOptions: Partial<CollectionViewAdapterOptions<TDto>> = {
106
+ pagination: {
107
+ defaultPageSize: 10,
108
+ defaultPageIndex: 0,
109
+ },
110
+ ordering: {
111
+ maxOrderingColumns: 1,
112
+ defaultOrdering: undefined,
113
+ },
114
+ search: {
115
+ defaultSearch: undefined,
116
+ },
117
+ selection: {
118
+ enabled: false,
119
+ defaultSelection: [],
120
+ },
121
+ };
122
+
123
+ private _currentOptions: CollectionViewAdapterOptions<TDto>;
124
+
125
+ /**
126
+ * Creates a new instance of CollectionViewAdapter
127
+ * @param options Options for the adapter
128
+ * @param client The client to use for reading data. If a string is provided, it will be used as the controller name for the ApiReadControllerClient, otherwise the provided client will be used directly.
129
+ */
130
+ constructor(options: CollectionViewAdapterOptions<TDto>, client: IReadSelectedClient<any, any> | string) {
131
+ this._readClient = typeof client === 'string' ? new ApiReadControllerClient<any, any, any>(client) : client;
132
+
133
+ this._currentOptions = {
134
+ ...options,
135
+ pagination: {
136
+ ...this._defaultOptions.pagination,
137
+ ...options.pagination,
138
+ },
139
+ ordering: {
140
+ ...this._defaultOptions.ordering,
141
+ ...options.ordering,
142
+ },
143
+ search: {
144
+ ...this._defaultOptions.search,
145
+ ...options.search,
146
+ },
147
+ selection: options.selection ?? this._defaultOptions.selection,
148
+ };
149
+
150
+ this._pageIndex = this._currentOptions.pagination?.defaultPageIndex ?? this._pageIndex;
151
+ this._pageSize = this._currentOptions.pagination?.defaultPageSize ?? this._pageSize;
152
+ this._search = this._currentOptions.search?.defaultSearch ?? this._search;
153
+ this._selection = this._currentOptions.selection?.defaultSelection ?? this._selection;
154
+ this._ordering = this._currentOptions.ordering?.defaultOrdering ?? this._ordering;
155
+
156
+ this._scheduleFetch();
157
+ }
158
+
159
+ // #region Getters
160
+
161
+ public get isLoading(): boolean {
162
+ return this._isLoading;
163
+ }
164
+
165
+ public get pageData(): readonly TDto[] | undefined {
166
+ return this._pageData;
167
+ }
168
+
169
+ public get error(): string | undefined {
170
+ return this._error;
171
+ }
172
+
173
+ public get totalItemCount(): number {
174
+ return this._totalItemCount;
175
+ }
176
+
177
+ public get pageIndex(): number {
178
+ return this._pageIndex;
179
+ }
180
+
181
+ public get pageSize(): number {
182
+ return this._pageSize;
183
+ }
184
+
185
+ public get selection(): readonly TDto[] {
186
+ return this._selection;
187
+ }
188
+
189
+ public get search(): ReadSelectedSearchDefinitionDto<TDto> {
190
+ return this._search;
191
+ }
192
+
193
+ // #endregion
194
+ // #region Search
195
+
196
+ public setSearch(searchDefinition: ReadSelectedSearchDefinitionDto<TDto>): void {
197
+ this._search = searchDefinition;
198
+ this._pageIndex = 0;
199
+ this.searchChanged.dispatchEvent(searchDefinition);
200
+ this.pageIndexChanged.dispatchEvent(0);
201
+ this._scheduleFetch();
202
+ }
203
+
204
+ public get ordering(): readonly { path: PropertyPathDto; direction: ReadSelectedOrderingDirection }[] {
205
+ return this._ordering;
206
+ }
207
+
208
+ // #endregion
209
+ // #region Ordering
210
+
211
+ public setOrdering(propertyPath: PropertyPathDto, orderDirection: ReadSelectedOrderingDirection): void {
212
+ this._ordering = this._ordering.filter(p => !this._arePropertyPathsEqual(p.path, propertyPath));
213
+
214
+ this._ordering = [{ path: propertyPath, direction: orderDirection }, ...this._ordering];
215
+
216
+ const maxColumns = this._currentOptions.ordering?.maxOrderingColumns ?? 1;
217
+ if (this._ordering.length > maxColumns) {
218
+ this._ordering = this._ordering.slice(0, maxColumns);
219
+ }
220
+
221
+ this._pageIndex = 0;
222
+ this.orderingChanged.dispatchEvent(this._ordering);
223
+ this.pageIndexChanged.dispatchEvent(0);
224
+ this._scheduleFetch();
225
+ }
226
+
227
+ // #endregion
228
+
229
+ // #region Pagination
230
+
231
+ public setPageIndex(pageIndex: number): void {
232
+ this._pageIndex = pageIndex;
233
+ this.pageIndexChanged.dispatchEvent(pageIndex);
234
+ this._scheduleFetch();
235
+ }
236
+
237
+ public setPageSize(pageSize: number): void {
238
+ this._pageSize = pageSize;
239
+ this._pageIndex = 0;
240
+ this.pageSizeChanged.dispatchEvent(pageSize);
241
+ this.pageIndexChanged.dispatchEvent(0);
242
+ this._scheduleFetch();
243
+ }
244
+
245
+ public refreshData(): void {
246
+ this._scheduleFetch();
247
+ }
248
+
249
+ // #endregion
250
+ // #region Selection
251
+
252
+ private _getItemKey(item: TDto): string {
253
+ const pk = this._currentOptions.primaryKey;
254
+ if (typeof pk === 'function') return pk(item);
255
+ return String((item as Record<string, unknown>)[pk]);
256
+ }
257
+
258
+ private get _selectionEnabled(): 'single' | 'multiple' | false {
259
+ return this._currentOptions.selection?.enabled ?? false;
260
+ }
261
+
262
+ public selectionToggle(item: TDto): void {
263
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
264
+ const key = this._getItemKey(item);
265
+ if (this._selection.find(x => this._getItemKey(x) === key)) {
266
+ this._selection = this._selection.filter(x => this._getItemKey(x) !== key);
267
+ } else if (this._selectionEnabled === 'single') {
268
+ this._selection = [item];
269
+ } else {
270
+ this._selection = [...this._selection, item];
271
+ }
272
+ this.selectionChanged.dispatchEvent(this._selection);
273
+ }
274
+
275
+ public selectionAdd(item: TDto): void {
276
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
277
+ const key = this._getItemKey(item);
278
+ if (this._selection.find(x => this._getItemKey(x) === key)) return;
279
+ if (this._selectionEnabled === 'single') {
280
+ this._selection = [item];
281
+ } else {
282
+ this._selection = [...this._selection, item];
283
+ }
284
+ this.selectionChanged.dispatchEvent(this._selection);
285
+ }
286
+
287
+ public selectionRemove(item: TDto): void {
288
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
289
+ const key = this._getItemKey(item);
290
+ this._selection = this._selection.filter(x => this._getItemKey(x) !== key);
291
+ this.selectionChanged.dispatchEvent(this._selection);
292
+ }
293
+
294
+ public selectionClear(): void {
295
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
296
+ this._selection = [];
297
+ this.selectionChanged.dispatchEvent(this._selection);
298
+ }
299
+
300
+ public isSelected(item: TDto): boolean {
301
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
302
+ const key = this._getItemKey(item);
303
+ return this._selection.some(x => this._getItemKey(x) === key);
304
+ }
305
+
306
+ public selectionAddPage(): void {
307
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
308
+ if (this._selectionEnabled !== 'multiple' || !this._pageData) return;
309
+ const newItems = this._pageData.filter(item => !this.isSelected(item));
310
+ if (newItems.length > 0) {
311
+ this._selection = [...this._selection, ...newItems];
312
+ this.selectionChanged.dispatchEvent(this._selection);
313
+ }
314
+ }
315
+
316
+ public selectionRemovePage(): void {
317
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
318
+ if (!this._pageData) return;
319
+ const pageItemKeys = new Set(this._pageData.map(item => this._getItemKey(item)));
320
+ this._selection = this._selection.filter(item => !pageItemKeys.has(this._getItemKey(item)));
321
+ this.selectionChanged.dispatchEvent(this._selection);
322
+ }
323
+
324
+ public isSelectedPage(): boolean {
325
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
326
+ if (!this._pageData || this._pageData.length === 0) return false;
327
+ return this._pageData.every(item => this.isSelected(item));
328
+ }
329
+
330
+ public isSomeSelectedPage(): boolean {
331
+ if (!this._selectionEnabled) throw new Error('Selection is not enabled');
332
+ if (!this._pageData || this._pageData.length === 0) return false;
333
+ const selectedCount = this._pageData.filter(item => this.isSelected(item)).length;
334
+ return selectedCount > 0 && selectedCount < this._pageData.length;
335
+ }
336
+
337
+ // #endregion
338
+
339
+ // #region Lifecycle
340
+
341
+ public destroy(): void {
342
+ this._cancelPendingRequests();
343
+ }
344
+
345
+ // #endregion
346
+
347
+ // #region Private
348
+
349
+ private _scheduleFetch(): void {
350
+ this._isLoading = true;
351
+ this.isLoadingChanged.dispatchEvent(true);
352
+ if (this._fetchTimeout !== undefined) {
353
+ clearTimeout(this._fetchTimeout);
354
+ }
355
+ this._fetchTimeout = setTimeout(() => this._executeFetch(), 50);
356
+ }
357
+
358
+ private async _executeFetch(): Promise<void> {
359
+ let abortController: AbortController | undefined;
360
+
361
+ try {
362
+ if (this._currentAbortController) {
363
+ try {
364
+ this._currentAbortController.abort();
365
+ } catch {
366
+ // Ignore abort errors
367
+ }
368
+ }
369
+ abortController = new AbortController();
370
+ this._currentAbortController = abortController;
371
+
372
+ const definition = this._parseOptionsToDefinition();
373
+ const response = await this._readClient.readSelected(definition, abortController.signal);
374
+
375
+ if (!response.ok) {
376
+ if (response.error.code === ErrorCode.Aborted) return;
377
+ this._error = response.error.details ?? response.error.message ?? 'Unknown error';
378
+ this._pageData = [];
379
+ } else {
380
+ this._error = undefined;
381
+ this._pageData = response.result;
382
+
383
+ if (response.metadata.totalCount !== undefined) {
384
+ this._totalItemCount = response.metadata.totalCount;
385
+ } else {
386
+ this._totalItemCount = this._calculateTotal(this._pageSize, this._pageIndex, this._pageData.length, this._totalItemCount);
387
+ }
388
+ }
389
+ } catch (error: unknown) {
390
+ console.error('Error fetching data:', error);
391
+ this._error = error instanceof Error ? error.message : 'Unknown error';
392
+ } finally {
393
+ if (abortController && this._currentAbortController === abortController) {
394
+ this._isLoading = false;
395
+ this._currentAbortController = undefined;
396
+ this.isLoadingChanged.dispatchEvent(false);
397
+ this.pageDataChanged.dispatchEvent(this._pageData);
398
+ this.errorChanged.dispatchEvent(this._error);
399
+ this.totalItemCountChanged.dispatchEvent(this._totalItemCount);
400
+ }
401
+ }
402
+ }
403
+
404
+ private _cancelPendingRequests(): void {
405
+ if (this._fetchTimeout !== undefined) {
406
+ clearTimeout(this._fetchTimeout);
407
+ this._fetchTimeout = undefined;
408
+ }
409
+ if (this._currentAbortController) {
410
+ try {
411
+ this._currentAbortController.abort();
412
+ } catch {
413
+ // Ignore abort errors
414
+ }
415
+ this._currentAbortController = undefined;
416
+ }
417
+ }
418
+
419
+ private _parseOptionsToDefinition(): ReadSelectedDefinitionDto<TDto> {
420
+ const definition: ReadSelectedDefinitionDto<TDto> = {
421
+ paginationDefinition: {
422
+ skip: this._pageIndex * this._pageSize,
423
+ limit: this._pageSize,
424
+ },
425
+ };
426
+
427
+ if (this._ordering.length > 0) {
428
+ definition.orderingDefinition = {
429
+ order: this._ordering.map(o => ({
430
+ propertyPath: o.path.map(x => toPascalCase(x)) as PropertyPathDto,
431
+ direction: o.direction,
432
+ })),
433
+ };
434
+ }
435
+
436
+ definition.searchDefinition = this._search;
437
+
438
+ return definition;
439
+ }
440
+
441
+ private _arePropertyPathsEqual(path1: PropertyPathDto, path2: PropertyPathDto): boolean {
442
+ if (path1.length !== path2.length) return false;
443
+ return path1.every((segment, index) => segment === path2[index]);
444
+ }
445
+
446
+ private _calculateTotal(pageSize: number, pageIndex: number, itemsOnCurrentPageCount: number, previousTotal: number): number {
447
+ if (itemsOnCurrentPageCount === 0) {
448
+ if (pageSize === 0) return 0;
449
+ return pageSize * pageIndex;
450
+ }
451
+ if (itemsOnCurrentPageCount < pageSize) {
452
+ return pageSize * pageIndex + itemsOnCurrentPageCount;
453
+ }
454
+ return previousTotal;
455
+ }
456
+
457
+ // #endregion
458
+ }
@@ -1,2 +1,2 @@
1
- export * from './CollectionViewAdapter';
2
- export * from './SearchAdapter';
1
+ export * from './collection-view-adapter';
2
+ export * from './search-adapter';