@angular-architects/ngrx-toolkit 19.4.0 → 19.4.2

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 (128) hide show
  1. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +119 -0
  2. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +1 -0
  3. package/fesm2022/angular-architects-ngrx-toolkit.mjs +2108 -0
  4. package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -0
  5. package/{src/index.ts → index.d.ts} +5 -32
  6. package/lib/assertions/assertions.d.ts +2 -0
  7. package/{src/lib/devtools/features/with-disabled-name-indicies.ts → lib/devtools/features/with-disabled-name-indicies.d.ts} +1 -5
  8. package/{src/lib/devtools/features/with-glitch-tracking.ts → lib/devtools/features/with-glitch-tracking.d.ts} +1 -6
  9. package/{src/lib/devtools/features/with-mapper.ts → lib/devtools/features/with-mapper.d.ts} +1 -7
  10. package/lib/devtools/internal/current-action-names.d.ts +1 -0
  11. package/lib/devtools/internal/default-tracker.d.ts +13 -0
  12. package/lib/devtools/internal/devtools-feature.d.ts +24 -0
  13. package/lib/devtools/internal/devtools-syncer.service.d.ts +39 -0
  14. package/lib/devtools/internal/glitch-tracker.service.d.ts +18 -0
  15. package/lib/devtools/internal/models.d.ts +24 -0
  16. package/{src/lib/devtools/provide-devtools-config.ts → lib/devtools/provide-devtools-config.d.ts} +4 -16
  17. package/lib/devtools/rename-devtools-name.d.ts +7 -0
  18. package/lib/devtools/update-state.d.ts +15 -0
  19. package/{src/lib/devtools/with-dev-tools-stub.ts → lib/devtools/with-dev-tools-stub.d.ts} +1 -2
  20. package/lib/devtools/with-devtools.d.ts +24 -0
  21. package/lib/flattening-operator.d.ts +14 -0
  22. package/lib/immutable-state/deep-freeze.d.ts +11 -0
  23. package/lib/immutable-state/is-dev-mode.d.ts +1 -0
  24. package/lib/immutable-state/with-immutable-state.d.ts +60 -0
  25. package/lib/mutation/http-mutation.d.ts +86 -0
  26. package/lib/mutation/mutation.d.ts +20 -0
  27. package/lib/mutation/rx-mutation.d.ts +76 -0
  28. package/{src/lib/shared/signal-store-models.ts → lib/shared/signal-store-models.d.ts} +4 -8
  29. package/lib/shared/throw-if-null.d.ts +1 -0
  30. package/lib/storage-sync/features/with-indexed-db.d.ts +2 -0
  31. package/lib/storage-sync/features/with-local-storage.d.ts +3 -0
  32. package/lib/storage-sync/internal/indexeddb.service.d.ts +29 -0
  33. package/lib/storage-sync/internal/local-storage.service.d.ts +8 -0
  34. package/lib/storage-sync/internal/models.d.ts +45 -0
  35. package/lib/storage-sync/internal/session-storage.service.d.ts +8 -0
  36. package/lib/storage-sync/with-storage-sync.d.ts +45 -0
  37. package/lib/with-call-state.d.ts +58 -0
  38. package/{src/lib/with-conditional.ts → lib/with-conditional.d.ts} +7 -31
  39. package/lib/with-data-service.d.ts +109 -0
  40. package/{src/lib/with-feature-factory.ts → lib/with-feature-factory.d.ts} +4 -32
  41. package/lib/with-mutations.d.ts +51 -0
  42. package/lib/with-pagination.d.ts +98 -0
  43. package/lib/with-redux.d.ts +147 -0
  44. package/lib/with-reset.d.ts +29 -0
  45. package/lib/with-undo-redo.d.ts +31 -0
  46. package/package.json +21 -4
  47. package/redux-connector/index.d.ts +2 -0
  48. package/redux-connector/src/lib/create-redux.d.ts +13 -0
  49. package/redux-connector/src/lib/model.d.ts +40 -0
  50. package/redux-connector/src/lib/rxjs-interop/redux-method.d.ts +14 -0
  51. package/redux-connector/src/lib/signal-redux-store.d.ts +11 -0
  52. package/redux-connector/src/lib/util.d.ts +5 -0
  53. package/eslint.config.cjs +0 -43
  54. package/jest.config.ts +0 -22
  55. package/ng-package.json +0 -7
  56. package/project.json +0 -37
  57. package/redux-connector/docs/README.md +0 -131
  58. package/redux-connector/index.ts +0 -6
  59. package/redux-connector/ng-package.json +0 -5
  60. package/redux-connector/src/lib/create-redux.ts +0 -102
  61. package/redux-connector/src/lib/model.ts +0 -89
  62. package/redux-connector/src/lib/rxjs-interop/redux-method.ts +0 -66
  63. package/redux-connector/src/lib/signal-redux-store.ts +0 -59
  64. package/redux-connector/src/lib/util.ts +0 -22
  65. package/src/lib/assertions/assertions.ts +0 -9
  66. package/src/lib/devtools/internal/current-action-names.ts +0 -1
  67. package/src/lib/devtools/internal/default-tracker.ts +0 -60
  68. package/src/lib/devtools/internal/devtools-feature.ts +0 -37
  69. package/src/lib/devtools/internal/devtools-syncer.service.ts +0 -202
  70. package/src/lib/devtools/internal/glitch-tracker.service.ts +0 -61
  71. package/src/lib/devtools/internal/models.ts +0 -29
  72. package/src/lib/devtools/rename-devtools-name.ts +0 -21
  73. package/src/lib/devtools/tests/action-name.spec.ts +0 -48
  74. package/src/lib/devtools/tests/basic.spec.ts +0 -111
  75. package/src/lib/devtools/tests/connecting.spec.ts +0 -37
  76. package/src/lib/devtools/tests/helpers.spec.ts +0 -43
  77. package/src/lib/devtools/tests/naming.spec.ts +0 -216
  78. package/src/lib/devtools/tests/provide-devtools-config.spec.ts +0 -25
  79. package/src/lib/devtools/tests/types.spec.ts +0 -19
  80. package/src/lib/devtools/tests/update-state.spec.ts +0 -29
  81. package/src/lib/devtools/tests/with-devtools.spec.ts +0 -5
  82. package/src/lib/devtools/tests/with-glitch-tracking.spec.ts +0 -272
  83. package/src/lib/devtools/tests/with-mapper.spec.ts +0 -69
  84. package/src/lib/devtools/update-state.ts +0 -38
  85. package/src/lib/devtools/with-devtools.ts +0 -81
  86. package/src/lib/flattening-operator.ts +0 -42
  87. package/src/lib/immutable-state/deep-freeze.ts +0 -43
  88. package/src/lib/immutable-state/is-dev-mode.ts +0 -6
  89. package/src/lib/immutable-state/tests/with-immutable-state.spec.ts +0 -260
  90. package/src/lib/immutable-state/with-immutable-state.ts +0 -115
  91. package/src/lib/mutation/http-mutation.spec.ts +0 -473
  92. package/src/lib/mutation/http-mutation.ts +0 -172
  93. package/src/lib/mutation/mutation.ts +0 -26
  94. package/src/lib/mutation/rx-mutation.spec.ts +0 -594
  95. package/src/lib/mutation/rx-mutation.ts +0 -208
  96. package/src/lib/shared/prettify.ts +0 -3
  97. package/src/lib/shared/throw-if-null.ts +0 -7
  98. package/src/lib/storage-sync/features/with-indexed-db.ts +0 -81
  99. package/src/lib/storage-sync/features/with-local-storage.ts +0 -58
  100. package/src/lib/storage-sync/internal/indexeddb.service.ts +0 -124
  101. package/src/lib/storage-sync/internal/local-storage.service.ts +0 -19
  102. package/src/lib/storage-sync/internal/models.ts +0 -62
  103. package/src/lib/storage-sync/internal/session-storage.service.ts +0 -18
  104. package/src/lib/storage-sync/tests/indexeddb.service.spec.ts +0 -99
  105. package/src/lib/storage-sync/tests/with-storage-async.spec.ts +0 -308
  106. package/src/lib/storage-sync/tests/with-storage-sync.spec.ts +0 -268
  107. package/src/lib/storage-sync/with-storage-sync.ts +0 -233
  108. package/src/lib/with-call-state.spec.ts +0 -42
  109. package/src/lib/with-call-state.ts +0 -195
  110. package/src/lib/with-conditional.spec.ts +0 -125
  111. package/src/lib/with-data-service.spec.ts +0 -564
  112. package/src/lib/with-data-service.ts +0 -433
  113. package/src/lib/with-feature-factory.spec.ts +0 -69
  114. package/src/lib/with-mutations.spec.ts +0 -537
  115. package/src/lib/with-mutations.ts +0 -146
  116. package/src/lib/with-pagination.spec.ts +0 -90
  117. package/src/lib/with-pagination.ts +0 -353
  118. package/src/lib/with-redux.spec.ts +0 -258
  119. package/src/lib/with-redux.ts +0 -387
  120. package/src/lib/with-reset.spec.ts +0 -112
  121. package/src/lib/with-reset.ts +0 -62
  122. package/src/lib/with-undo-redo.spec.ts +0 -287
  123. package/src/lib/with-undo-redo.ts +0 -199
  124. package/src/test-setup.ts +0 -8
  125. package/tsconfig.json +0 -29
  126. package/tsconfig.lib.json +0 -17
  127. package/tsconfig.lib.prod.json +0 -9
  128. package/tsconfig.spec.json +0 -17
@@ -1,537 +0,0 @@
1
- import { fakeAsync, TestBed, tick } from '@angular/core/testing';
2
- import { patchState, signalStore, withState } from '@ngrx/signals';
3
- import { delay, Observable, of, Subject, switchMap, throwError } from 'rxjs';
4
- import { concatOp, exhaustOp, mergeOp, switchOp } from './flattening-operator';
5
- import { rxMutation } from './mutation/rx-mutation';
6
- import { withMutations } from './with-mutations';
7
-
8
- type Param =
9
- | number
10
- | {
11
- value: number | Observable<number>;
12
- delay?: number;
13
- fail?: boolean;
14
- };
15
-
16
- type NormalizedParam = {
17
- value: number | Observable<number>;
18
- delay: number;
19
- fail: boolean;
20
- };
21
-
22
- async function asyncTick(): Promise<void> {
23
- return new Promise((resolve) => {
24
- setTimeout(() => {
25
- resolve();
26
- }, 0);
27
- });
28
- }
29
-
30
- function calcDouble(value: number, delayInMsec = 1000): Observable<number> {
31
- return of(value * 2).pipe(delay(delayInMsec));
32
- }
33
-
34
- function fail(_value: number, delayInMsec = 1000): Observable<number> {
35
- return of(null).pipe(
36
- delay(delayInMsec),
37
- switchMap(() => throwError(() => ({ error: 'Test-Error' }))),
38
- );
39
- }
40
-
41
- function createTestSetup(flatteningOperator = concatOp) {
42
- function normalizeParam(param: Param): NormalizedParam {
43
- if (typeof param === 'number') {
44
- return {
45
- value: param,
46
- delay: 1000,
47
- fail: false,
48
- };
49
- }
50
-
51
- return {
52
- value: param.value,
53
- delay: param.delay ?? 1000,
54
- fail: param.fail ?? false,
55
- };
56
- }
57
-
58
- type SuccessParams = { result: number; params: Param };
59
- type ErrorParams = { error: unknown; params: Param };
60
-
61
- let onSuccessCalls = 0;
62
- let onErrorCalls = 0;
63
-
64
- let lastOnSuccessParams: SuccessParams | undefined = undefined;
65
- let lastOnErrorParams: ErrorParams | undefined = undefined;
66
-
67
- return TestBed.runInInjectionContext(() => {
68
- const Store = signalStore(
69
- withState({ counter: 3 }),
70
- withMutations((store) => ({
71
- increment: rxMutation({
72
- operation: (param: Param) => {
73
- const normalized = normalizeParam(param);
74
-
75
- if (normalized.value instanceof Observable) {
76
- return normalized.value.pipe(
77
- switchMap((value) => {
78
- if (normalized.fail) {
79
- return fail(value, normalized.delay);
80
- }
81
- return calcDouble(value, normalized.delay);
82
- }),
83
- );
84
- }
85
-
86
- if (normalized.fail) {
87
- return fail(normalized.value, normalized.delay);
88
- }
89
- return calcDouble(normalized.value, normalized.delay);
90
- },
91
- operator: flatteningOperator,
92
- onSuccess: (result, params) => {
93
- lastOnSuccessParams = { result, params };
94
- onSuccessCalls++;
95
- patchState(store, (state) => ({
96
- counter: state.counter + result,
97
- }));
98
- },
99
- onError: (error, params) => {
100
- lastOnErrorParams = { error, params };
101
- onErrorCalls++;
102
- },
103
- }),
104
- })),
105
- );
106
-
107
- const store = new Store();
108
- return {
109
- store,
110
- onSuccessCalls: () => onSuccessCalls,
111
- onErrorCalls: () => onErrorCalls,
112
- lastOnSuccessParams: () => lastOnSuccessParams,
113
- lastOnErrorParams: () => lastOnErrorParams,
114
- };
115
- });
116
- }
117
-
118
- describe('withMutations with rxMutation', () => {
119
- it('should update the state', fakeAsync(() => {
120
- const testSetup = createTestSetup();
121
- const store = testSetup.store;
122
-
123
- expect(store.incrementStatus()).toEqual('idle');
124
- expect(store.incrementIsPending()).toEqual(false);
125
-
126
- store.increment(2);
127
- expect(store.incrementStatus()).toEqual('pending');
128
- expect(store.incrementIsPending()).toEqual(true);
129
-
130
- tick(2000);
131
- expect(store.incrementStatus()).toEqual('success');
132
- expect(store.incrementIsPending()).toEqual(false);
133
- expect(store.incrementError()).toEqual(undefined);
134
-
135
- expect(store.counter()).toEqual(7);
136
- }));
137
-
138
- it('sets error', fakeAsync(() => {
139
- const testSetup = createTestSetup();
140
- const store = testSetup.store;
141
-
142
- store.increment({ value: 2, fail: true });
143
-
144
- tick(2000);
145
- expect(store.incrementStatus()).toEqual('error');
146
- expect(store.incrementIsPending()).toEqual(false);
147
- expect(store.incrementError()).toEqual({
148
- error: 'Test-Error',
149
- });
150
-
151
- expect(store.counter()).toEqual(3);
152
- }));
153
-
154
- it('starts two concurrent operations using concatMap: the first one fails and the second one succeeds', fakeAsync(() => {
155
- const testSetup = createTestSetup(concatOp);
156
- const store = testSetup.store;
157
-
158
- store.increment({ value: 1, delay: 100, fail: true });
159
- store.increment({ value: 2, delay: 200, fail: false });
160
-
161
- tick(100);
162
-
163
- expect(store.incrementStatus()).toEqual('pending');
164
- expect(store.incrementIsPending()).toEqual(true);
165
- expect(store.incrementError()).toEqual({
166
- error: 'Test-Error',
167
- });
168
-
169
- tick(200);
170
-
171
- expect(store.incrementStatus()).toEqual('success');
172
- expect(store.incrementIsPending()).toEqual(false);
173
- expect(store.incrementError()).toEqual(undefined);
174
-
175
- expect(store.counter()).toEqual(7);
176
- }));
177
-
178
- it('starts two concurrent operations using mergeMap: the first one fails and the second one succeeds', fakeAsync(() => {
179
- const testSetup = createTestSetup(mergeOp);
180
- const store = testSetup.store;
181
-
182
- store.increment({ value: 1, delay: 100, fail: true });
183
- store.increment({ value: 2, delay: 200, fail: false });
184
-
185
- tick(100);
186
-
187
- expect(store.incrementStatus()).toEqual('pending');
188
- expect(store.incrementIsPending()).toEqual(true);
189
- expect(store.incrementError()).toEqual({
190
- error: 'Test-Error',
191
- });
192
-
193
- tick(100);
194
-
195
- expect(store.incrementStatus()).toEqual('success');
196
- expect(store.incrementIsPending()).toEqual(false);
197
- expect(store.incrementError()).toEqual(undefined);
198
-
199
- expect(store.counter()).toEqual(7);
200
- }));
201
-
202
- it('deals with race conditions using switchMap', fakeAsync(() => {
203
- const testSetup = createTestSetup(switchOp);
204
- const store = testSetup.store;
205
-
206
- store.increment(1);
207
-
208
- tick(500);
209
- expect(store.incrementStatus()).toEqual('pending');
210
- expect(store.incrementIsPending()).toEqual(true);
211
-
212
- store.increment(2);
213
- tick(1000);
214
-
215
- expect(store.incrementStatus()).toEqual('success');
216
- expect(store.incrementIsPending()).toEqual(false);
217
- expect(store.incrementError()).toEqual(undefined);
218
-
219
- expect(store.counter()).toEqual(7);
220
- expect(testSetup.onSuccessCalls()).toEqual(1);
221
- expect(testSetup.onErrorCalls()).toEqual(0);
222
- expect(testSetup.lastOnSuccessParams()).toEqual({
223
- params: 2,
224
- result: 4,
225
- });
226
- }));
227
-
228
- it('deals with race conditions using mergeMap', fakeAsync(() => {
229
- const testSetup = createTestSetup(mergeOp);
230
- const store = testSetup.store;
231
-
232
- store.increment(1);
233
- tick(500);
234
- store.increment(2);
235
- tick(500);
236
-
237
- expect(store.incrementStatus()).toEqual('pending');
238
- expect(store.incrementIsPending()).toEqual(true);
239
-
240
- // expect(store.counter()).toEqual(7);
241
- expect(testSetup.onSuccessCalls()).toEqual(1);
242
- expect(testSetup.onErrorCalls()).toEqual(0);
243
- expect(testSetup.lastOnSuccessParams()).toEqual({
244
- params: 1,
245
- result: 2,
246
- });
247
-
248
- tick(500);
249
-
250
- expect(store.incrementStatus()).toEqual('success');
251
- expect(store.incrementIsPending()).toEqual(false);
252
- expect(store.incrementError()).toEqual(undefined);
253
-
254
- expect(store.counter()).toEqual(9);
255
- expect(testSetup.onSuccessCalls()).toEqual(2);
256
- expect(testSetup.onErrorCalls()).toEqual(0);
257
- expect(testSetup.lastOnSuccessParams()).toEqual({
258
- params: 2,
259
- result: 4,
260
- });
261
- }));
262
-
263
- it('deals with race conditions using mergeMap where the 2nd task starts after and finishes before the 1st one', fakeAsync(() => {
264
- const testSetup = createTestSetup(mergeOp);
265
- const store = testSetup.store;
266
-
267
- store.increment({ value: 1, delay: 1000 });
268
- tick(500);
269
-
270
- expect(store.incrementStatus()).toEqual('pending');
271
- expect(store.incrementIsPending()).toEqual(true);
272
-
273
- store.increment({ value: 2, delay: 100 });
274
- tick(500);
275
-
276
- expect(store.incrementStatus()).toEqual('success');
277
- expect(store.incrementIsPending()).toEqual(false);
278
- expect(store.incrementError()).toEqual(undefined);
279
-
280
- expect(store.counter()).toEqual(9);
281
- expect(testSetup.onSuccessCalls()).toEqual(2);
282
- expect(testSetup.onErrorCalls()).toEqual(0);
283
- expect(testSetup.lastOnSuccessParams()).toEqual({
284
- params: { value: 1, delay: 1000 },
285
- result: 2,
286
- });
287
- }));
288
-
289
- it('deals with race conditions using concatMap', fakeAsync(() => {
290
- const testSetup = createTestSetup(concatOp);
291
- const store = testSetup.store;
292
-
293
- store.increment({ value: 1, delay: 1000 });
294
- tick(500);
295
- store.increment({ value: 2, delay: 100 });
296
- tick(500);
297
-
298
- expect(store.incrementStatus()).toEqual('pending');
299
- expect(store.incrementIsPending()).toEqual(true);
300
-
301
- expect(store.counter()).toEqual(5);
302
- expect(testSetup.onSuccessCalls()).toEqual(1);
303
- expect(testSetup.onErrorCalls()).toEqual(0);
304
- expect(testSetup.lastOnSuccessParams()).toEqual({
305
- params: { value: 1, delay: 1000 },
306
- result: 2,
307
- });
308
-
309
- tick(500);
310
-
311
- expect(store.incrementStatus()).toEqual('success');
312
- expect(store.incrementIsPending()).toEqual(false);
313
- expect(store.incrementError()).toEqual(undefined);
314
-
315
- expect(store.counter()).toEqual(9);
316
- expect(testSetup.onSuccessCalls()).toEqual(2);
317
- expect(testSetup.onErrorCalls()).toEqual(0);
318
- expect(testSetup.lastOnSuccessParams()).toEqual({
319
- params: { value: 2, delay: 100 },
320
- result: 4,
321
- });
322
- }));
323
-
324
- it('deals with race conditions using exhaustMap', fakeAsync(() => {
325
- const testSetup = createTestSetup(exhaustOp);
326
- const store = testSetup.store;
327
-
328
- store.increment({ value: 1, delay: 1000 });
329
- tick(500);
330
-
331
- expect(store.incrementStatus()).toEqual('pending');
332
- expect(store.incrementIsPending()).toEqual(true);
333
-
334
- store.increment({ value: 2, delay: 100 });
335
- tick(500);
336
-
337
- expect(store.incrementStatus()).toEqual('success');
338
- expect(store.incrementIsPending()).toEqual(false);
339
- expect(store.incrementError()).toEqual(undefined);
340
-
341
- expect(store.counter()).toEqual(5);
342
- expect(testSetup.onSuccessCalls()).toEqual(1);
343
- expect(testSetup.onErrorCalls()).toEqual(0);
344
- expect(testSetup.lastOnSuccessParams()).toEqual({
345
- params: { value: 1, delay: 1000 },
346
- result: 2,
347
- });
348
-
349
- tick(500);
350
-
351
- expect(store.incrementStatus()).toEqual('success');
352
- expect(store.incrementIsPending()).toEqual(false);
353
- expect(store.incrementError()).toEqual(undefined);
354
-
355
- expect(store.counter()).toEqual(5);
356
- expect(testSetup.onSuccessCalls()).toEqual(1);
357
- expect(testSetup.onErrorCalls()).toEqual(0);
358
- expect(testSetup.lastOnSuccessParams()).toEqual({
359
- params: { value: 1, delay: 1000 },
360
- result: 2,
361
- });
362
- }));
363
-
364
- it('informs about failed operation via the returned promise', async () => {
365
- const testSetup = createTestSetup(switchOp);
366
- const store = testSetup.store;
367
-
368
- const p1 = store.increment({ value: 1, delay: 1, fail: false });
369
- const p2 = store.increment({ value: 2, delay: 2, fail: true });
370
-
371
- expect(store.incrementStatus()).toEqual('pending');
372
- expect(store.incrementIsPending()).toEqual(true);
373
-
374
- await asyncTick();
375
-
376
- const result1 = await p1;
377
- const result2 = await p2;
378
-
379
- expect(result1.status).toEqual('aborted');
380
- expect(result2).toEqual({
381
- status: 'error',
382
- error: {
383
- error: 'Test-Error',
384
- },
385
- });
386
-
387
- expect(store.incrementIsPending()).toEqual(false);
388
- expect(store.incrementStatus()).toEqual('error');
389
- expect(store.incrementError()).toEqual({
390
- error: 'Test-Error',
391
- });
392
- });
393
-
394
- it('informs about successful operation via the returned promise', async () => {
395
- const testSetup = createTestSetup();
396
- const store = testSetup.store;
397
-
398
- const resultPromise = store.increment({ value: 2, delay: 2, fail: false });
399
-
400
- expect(store.incrementStatus()).toEqual('pending');
401
- expect(store.incrementIsPending()).toEqual(true);
402
-
403
- await asyncTick();
404
-
405
- const result = await resultPromise;
406
-
407
- expect(result).toEqual({
408
- status: 'success',
409
- value: 4,
410
- });
411
-
412
- expect(store.incrementIsPending()).toEqual(false);
413
- expect(store.incrementStatus()).toEqual('success');
414
- expect(store.incrementError()).toBeUndefined();
415
- });
416
-
417
- it('informs about aborted operation when using switchMap', async () => {
418
- const testSetup = createTestSetup(switchOp);
419
- const store = testSetup.store;
420
-
421
- const p1 = store.increment({ value: 1, delay: 1, fail: false });
422
- const p2 = store.increment({ value: 2, delay: 2, fail: false });
423
-
424
- expect(store.incrementStatus()).toEqual('pending');
425
- expect(store.incrementIsPending()).toEqual(true);
426
-
427
- await asyncTick();
428
-
429
- const result1 = await p1;
430
- const result2 = await p2;
431
-
432
- expect(result1.status).toEqual('aborted');
433
- expect(result2).toEqual({
434
- status: 'success',
435
- value: 4,
436
- });
437
-
438
- expect(store.incrementIsPending()).toEqual(false);
439
- expect(store.incrementStatus()).toEqual('success');
440
- expect(store.incrementError()).toBeUndefined();
441
- });
442
-
443
- it('informs about aborted operation when using exhaustMap', async () => {
444
- const testSetup = createTestSetup(exhaustOp);
445
- const store = testSetup.store;
446
-
447
- const p1 = store.increment({ value: 1, delay: 1, fail: false });
448
- const p2 = store.increment({ value: 2, delay: 1, fail: false });
449
-
450
- expect(store.incrementStatus()).toEqual('pending');
451
- expect(store.incrementIsPending()).toEqual(true);
452
-
453
- await asyncTick();
454
-
455
- const result1 = await p1;
456
- const result2 = await p2;
457
-
458
- expect(result1).toEqual({
459
- status: 'success',
460
- value: 2,
461
- });
462
-
463
- expect(result2.status).toEqual('aborted');
464
-
465
- expect(store.incrementIsPending()).toEqual(false);
466
- expect(store.incrementStatus()).toEqual('success');
467
- expect(store.incrementError()).toBeUndefined();
468
- });
469
-
470
- it('calls success handler per value in the stream and returns the final value via the promise', async () => {
471
- const testSetup = createTestSetup(switchOp);
472
- const store = testSetup.store;
473
-
474
- const input$ = new Subject<number>();
475
- const resultPromise = store.increment({
476
- value: input$,
477
- delay: 1,
478
- fail: false,
479
- });
480
-
481
- expect(store.incrementStatus()).toEqual('pending');
482
- expect(store.incrementIsPending()).toEqual(true);
483
-
484
- input$.next(1);
485
- input$.next(2);
486
- input$.next(3);
487
- input$.complete();
488
-
489
- await asyncTick();
490
-
491
- const result = await resultPromise;
492
-
493
- expect(result).toEqual({
494
- status: 'success',
495
- value: 6,
496
- });
497
-
498
- expect(store.counter()).toEqual(9);
499
- expect(testSetup.lastOnSuccessParams()).toMatchObject({
500
- result: 6,
501
- });
502
-
503
- expect(store.incrementIsPending()).toEqual(false);
504
- expect(store.incrementStatus()).toEqual('success');
505
- expect(store.incrementError()).toBeUndefined();
506
- });
507
-
508
- it('informs about failed operation via the returned promise', async () => {
509
- const testSetup = createTestSetup(switchOp);
510
- const store = testSetup.store;
511
-
512
- const p1 = store.increment({ value: 1, delay: 1, fail: false });
513
- const p2 = store.increment({ value: 2, delay: 2, fail: true });
514
-
515
- expect(store.incrementStatus()).toEqual('pending');
516
- expect(store.incrementIsPending()).toEqual(true);
517
-
518
- await asyncTick();
519
-
520
- const result1 = await p1;
521
- const result2 = await p2;
522
-
523
- expect(result1.status).toEqual('aborted');
524
- expect(result2).toEqual({
525
- status: 'error',
526
- error: {
527
- error: 'Test-Error',
528
- },
529
- });
530
-
531
- expect(store.incrementIsPending()).toEqual(false);
532
- expect(store.incrementStatus()).toEqual('error');
533
- expect(store.incrementError()).toEqual({
534
- error: 'Test-Error',
535
- });
536
- });
537
- });
@@ -1,146 +0,0 @@
1
- import { Signal } from '@angular/core';
2
- import {
3
- EmptyFeatureResult,
4
- signalStoreFeature,
5
- SignalStoreFeature,
6
- SignalStoreFeatureResult,
7
- StateSignals,
8
- StateSource,
9
- withComputed,
10
- withMethods,
11
- WritableStateSource,
12
- } from '@ngrx/signals';
13
- import { Mutation, MutationStatus } from './mutation/mutation';
14
-
15
- // NamedMutationMethods below will infer the actual parameter and return types
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- type MutationsDictionary = Record<string, Mutation<any, any>>;
18
-
19
- // withMethods uses Record<string, Function> internally
20
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
21
- export type MethodsDictionary = Record<string, Function>;
22
-
23
- type NamedMutationProps<T extends MutationsDictionary> = {
24
- [Prop in keyof T as `${Prop & string}IsPending`]: Signal<boolean>;
25
- } & {
26
- [Prop in keyof T as `${Prop & string}Status`]: Signal<MutationStatus>;
27
- } & {
28
- [Prop in keyof T as `${Prop & string}Error`]: Signal<Error | undefined>;
29
- };
30
-
31
- type NamedMutationMethods<T extends MutationsDictionary> = {
32
- [Prop in keyof T as `${Prop & string}`]: T[Prop] extends Mutation<
33
- infer P,
34
- infer R
35
- >
36
- ? Mutation<P, R>
37
- : never;
38
- };
39
-
40
- export type NamedMutationResult<T extends MutationsDictionary> =
41
- EmptyFeatureResult & {
42
- props: NamedMutationProps<T>;
43
- methods: NamedMutationMethods<T>;
44
- };
45
-
46
- /**
47
- * Adds mutation methods to the store. Also, for each mutation method, several
48
- * Signals are added informing about the mutation's status and errors.
49
- *
50
- * ```typescript
51
- * export type Params = {
52
- * value: number;
53
- * };
54
- *
55
- * export const CounterStore = signalStore(
56
- * { providedIn: 'root' },
57
- * withState({ counter: 0 }),
58
- * withMutations((store) => ({
59
- * increment: rxMutation({ ... }),
60
- * })),
61
- * );
62
- * ```
63
- *
64
- * There are several types of mutations. In the example shown, an {@link module:rx-mutation.rxMutation | rxMutation}
65
- * leveraging RxJS is used
66
- *
67
- * For the defined `increment` mutation, several the following properties and
68
- * methods are added to the store:
69
- * - `increment(params: Params): Promise<MutationResult<number>>`: The mutation method.
70
- * - `incrementIsPending`: A signal indicating if the mutation is in progress.
71
- * - `incrementStatus`: A signal representing the current status of the mutation.
72
- * - `incrementError`: A signal containing any error that occurred during the mutation.
73
- *
74
- * @param mutationsFactory
75
- */
76
- export function withMutations<
77
- Input extends SignalStoreFeatureResult,
78
- Result extends MutationsDictionary,
79
- >(
80
- mutationsFactory: (
81
- store: Input['props'] &
82
- Input['methods'] &
83
- WritableStateSource<Input['state']> &
84
- StateSignals<Input['state']>,
85
- ) => Result,
86
- ): SignalStoreFeature<Input, NamedMutationResult<Result>>;
87
-
88
- export function withMutations<
89
- Input extends SignalStoreFeatureResult,
90
- Result extends MutationsDictionary,
91
- >(
92
- mutationsFactory: (
93
- store: Input['props'] & Input['methods'] & StateSource<Input['state']>,
94
- ) => Result,
95
- ): SignalStoreFeature<Input> {
96
- return (store) => {
97
- // TODO: Is this the correct usage?
98
- const source = store as StateSource<typeof store.stateSignals>;
99
- const mutations = mutationsFactory({
100
- ...source,
101
- ...store.props,
102
- ...store.methods,
103
- ...store.stateSignals,
104
- });
105
-
106
- const feature = createMutationsFeature(mutations);
107
- return feature(store);
108
- };
109
- }
110
-
111
- function createMutationsFeature<Result extends MutationsDictionary>(
112
- mutations: Result,
113
- ) {
114
- const keys = Object.keys(mutations);
115
-
116
- const feature = signalStoreFeature(
117
- withMethods(() =>
118
- keys.reduce(
119
- (acc, key) => ({
120
- ...acc,
121
- [key]: async (params: never) => {
122
- const mutation = mutations[key];
123
- if (!mutation) {
124
- throw new Error(`Mutation ${key} not found`);
125
- }
126
- const result = await mutation(params);
127
- return result;
128
- },
129
- }),
130
- {} as MethodsDictionary,
131
- ),
132
- ),
133
- withComputed(() =>
134
- keys.reduce(
135
- (acc, key) => ({
136
- ...acc,
137
- [`${key}IsPending`]: mutations[key].isPending,
138
- [`${key}Status`]: mutations[key].status,
139
- [`${key}Error`]: mutations[key].error,
140
- }),
141
- {} as NamedMutationProps<Result>,
142
- ),
143
- ),
144
- );
145
- return feature;
146
- }