@ethlete/query 0.1.0-next.1 → 0.1.0-next.11

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 (42) hide show
  1. package/esm2020/lib/auth/auth-provider.types.mjs +1 -1
  2. package/esm2020/lib/auth/basic-auth-provider.mjs +5 -5
  3. package/esm2020/lib/auth/bearer-auth-provider.mjs +12 -9
  4. package/esm2020/lib/auth/custom-header-auth-provider.mjs +4 -4
  5. package/esm2020/lib/directives/infinity-query-trigger.directive.mjs +3 -3
  6. package/esm2020/lib/directives/infinity-query.directive.mjs +36 -11
  7. package/esm2020/lib/directives/query.directive.mjs +17 -17
  8. package/esm2020/lib/infinite-query/infinity-query.mjs +11 -11
  9. package/esm2020/lib/infinite-query/infinity-query.types.mjs +1 -1
  10. package/esm2020/lib/query/query.mjs +49 -23
  11. package/esm2020/lib/query/query.types.mjs +1 -1
  12. package/esm2020/lib/query/query.utils.mjs +17 -2
  13. package/esm2020/lib/query-client/query-client.mjs +7 -7
  14. package/esm2020/lib/query-client/query-client.types.mjs +1 -1
  15. package/esm2020/lib/query-form/query-form.mjs +10 -7
  16. package/esm2020/lib/query-form/query-form.types.mjs +1 -1
  17. package/esm2020/lib/query-form/query-form.utils.mjs +21 -1
  18. package/esm2020/lib/request/request.mjs +5 -3
  19. package/esm2020/lib/request/request.types.mjs +1 -1
  20. package/esm2020/lib/request/request.util.mjs +24 -6
  21. package/esm2020/lib/utils/deep-freeze.util.mjs +5 -1
  22. package/fesm2015/ethlete-query.mjs +240 -117
  23. package/fesm2015/ethlete-query.mjs.map +1 -1
  24. package/fesm2020/ethlete-query.mjs +231 -114
  25. package/fesm2020/ethlete-query.mjs.map +1 -1
  26. package/lib/auth/auth-provider.types.d.ts +11 -1
  27. package/lib/directives/infinity-query-trigger.directive.d.ts +1 -1
  28. package/lib/directives/infinity-query.directive.d.ts +7 -2
  29. package/lib/directives/query.directive.d.ts +1 -1
  30. package/lib/infinite-query/infinity-query.types.d.ts +7 -4
  31. package/lib/query/query.d.ts +5 -3
  32. package/lib/query/query.types.d.ts +17 -14
  33. package/lib/query/query.utils.d.ts +8 -3
  34. package/lib/query-client/query-client.d.ts +9 -9
  35. package/lib/query-client/query-client.types.d.ts +9 -9
  36. package/lib/query-form/query-form.d.ts +1 -1
  37. package/lib/query-form/query-form.types.d.ts +13 -3
  38. package/lib/query-form/query-form.utils.d.ts +5 -0
  39. package/lib/request/request.types.d.ts +12 -10
  40. package/lib/request/request.util.d.ts +2 -2
  41. package/lib/utils/deep-freeze.util.d.ts +1 -1
  42. package/package.json +7 -6
@@ -1,33 +1,34 @@
1
- import { Subject, timer, filter, takeWhile, BehaviorSubject, interval, takeUntil, tap, switchMap, of, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
1
+ import { Subject, timer, filter, takeWhile, switchMap, of, BehaviorSubject, interval, takeUntil, tap, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
2
2
  import * as i0 from '@angular/core';
3
3
  import { Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef } from '@angular/core';
4
+ import { DestroyService } from '@ethlete/core';
4
5
  import { FormGroup } from '@angular/forms';
5
6
  import { Router, ActivatedRoute } from '@angular/router';
6
7
 
7
8
  class CustomHeaderAuthProvider {
9
+ get header() {
10
+ return { [this._config.name]: this._config.value };
11
+ }
8
12
  constructor(_config) {
9
13
  this._config = _config;
10
14
  this.queryClient = null;
11
15
  }
12
- get header() {
13
- return { [this._config.name]: this._config.value };
14
- }
15
16
  cleanUp() {
16
17
  // noop
17
18
  }
18
19
  }
19
20
 
20
21
  class BasicAuthProvider {
21
- constructor(_config) {
22
- this._config = _config;
23
- this.queryClient = null;
24
- }
25
22
  get header() {
26
23
  return { Authorization: `Basic ${this._basicAuthString}` };
27
24
  }
28
25
  get _basicAuthString() {
29
26
  return btoa(`${this._config.username}:${this._config.password}`);
30
27
  }
28
+ constructor(_config) {
29
+ this._config = _config;
30
+ this.queryClient = null;
31
+ }
31
32
  cleanUp() {
32
33
  // noop
33
34
  }
@@ -164,13 +165,15 @@ const buildTimestampFromSeconds = (seconds) => {
164
165
  }
165
166
  return new Date(Date.now() + seconds * 1000).getTime();
166
167
  };
167
- const buildRequestError = async (error) => {
168
+ const buildRequestError = async (error, route, requestInit) => {
168
169
  if (error instanceof DOMException && error.code === error.ABORT_ERR) {
169
170
  const err = {
170
171
  code: -1,
171
172
  message: 'Request aborted',
172
173
  detail: null,
173
174
  raw: error,
175
+ route,
176
+ requestInit,
174
177
  };
175
178
  return err;
176
179
  }
@@ -180,6 +183,8 @@ const buildRequestError = async (error) => {
180
183
  message: 'Syntax error',
181
184
  detail: null,
182
185
  raw: error,
186
+ route,
187
+ requestInit,
183
188
  };
184
189
  return err;
185
190
  }
@@ -189,23 +194,35 @@ const buildRequestError = async (error) => {
189
194
  message: `${error.name}: ${error.message}`,
190
195
  detail: null,
191
196
  raw: error,
197
+ route,
198
+ requestInit,
192
199
  };
193
200
  return err;
194
201
  }
195
202
  if (isFetchResponse(error)) {
196
203
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
197
- let detail;
204
+ let detail = null;
198
205
  try {
199
- detail = await error.text();
206
+ detail = await error.json();
207
+ }
208
+ catch {
209
+ // noop
200
210
  }
201
- catch (err) {
202
- detail = null;
211
+ if (!detail) {
212
+ try {
213
+ detail = await error.text();
214
+ }
215
+ catch {
216
+ // noop
217
+ }
203
218
  }
204
219
  const err = {
205
220
  code: error.status,
206
221
  message: error.statusText,
207
222
  detail,
208
223
  raw: error,
224
+ route,
225
+ requestInit,
209
226
  };
210
227
  return err;
211
228
  }
@@ -214,6 +231,8 @@ const buildRequestError = async (error) => {
214
231
  message: 'Unknown error',
215
232
  detail: null,
216
233
  raw: error,
234
+ route,
235
+ requestInit,
217
236
  };
218
237
  return err;
219
238
  };
@@ -260,7 +279,9 @@ const request = async (options) => {
260
279
  if (!response.ok) {
261
280
  throw response;
262
281
  }
263
- const data = (await response.json());
282
+ const isJsonResponse = response.headers.get('Content-Type')?.includes('application/json');
283
+ const isTextResponse = response.headers.get('Content-Type')?.includes('text/plain');
284
+ const data = (isJsonResponse ? await response.json() : isTextResponse ? await response.text() : null);
264
285
  const expiresInSeconds = options.cacheAdapter
265
286
  ? options.cacheAdapter(response.headers)
266
287
  : extractExpiresInSeconds(response.headers);
@@ -268,7 +289,7 @@ const request = async (options) => {
268
289
  return { data, expiresInTimestamp };
269
290
  }
270
291
  catch (error) {
271
- throw await buildRequestError(error);
292
+ throw await buildRequestError(error, options.route, options.init);
272
293
  }
273
294
  };
274
295
 
@@ -292,6 +313,9 @@ const decryptBearer = (token) => {
292
313
  };
293
314
 
294
315
  class BearerAuthProvider {
316
+ get header() {
317
+ return { Authorization: `Bearer ${this._token}` };
318
+ }
295
319
  constructor(_config) {
296
320
  this._config = _config;
297
321
  this._refreshToken = null;
@@ -306,9 +330,6 @@ class BearerAuthProvider {
306
330
  this._setupRefresh(this._config.refreshConfig);
307
331
  }
308
332
  }
309
- get header() {
310
- return { Authorization: `Bearer ${this._token}` };
311
- }
312
333
  cleanUp() {
313
334
  this._refreshTimerSubscription?.unsubscribe();
314
335
  this._refreshTimerSubscription = null;
@@ -321,10 +342,11 @@ class BearerAuthProvider {
321
342
  const expiresInPropertyName = config.expiresInPropertyName || 'exp';
322
343
  const expiresIn = bearer[expiresInPropertyName];
323
344
  const fiveMinutes = 5 * 60 * 1000;
345
+ const refreshBuffer = config.refreshBuffer ?? fiveMinutes;
324
346
  if (expiresIn === undefined) {
325
347
  throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
326
348
  }
327
- const remainingTime = new Date(expiresIn * 1000).getTime() - fiveMinutes - new Date().getTime();
349
+ const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
328
350
  const strategy = config.strategy ?? "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
329
351
  switch (strategy) {
330
352
  case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
@@ -339,17 +361,19 @@ class BearerAuthProvider {
339
361
  if (!this.queryClient) {
340
362
  throw new Error('Query client instance is null');
341
363
  }
342
- const { method, route, bodyAdapter, responseAdapter } = config;
364
+ const { method, route, requestAdapter, responseAdapter, paramLocation } = config;
365
+ const data = requestAdapter?.(this._refreshToken) ?? { refreshToken: this._refreshToken };
343
366
  const fullRoute = buildRoute({
344
367
  base: this.queryClient.config.baseRoute,
345
368
  route,
369
+ queryParams: paramLocation === 'query' ? data : undefined,
346
370
  });
347
- const body = bodyAdapter ? bodyAdapter(this._refreshToken) : { refreshToken: this._refreshToken };
371
+ const requestInit = { body: paramLocation === 'body' ? buildBody(data) : undefined, method };
348
372
  this.onRefreshInitiation$.next();
349
373
  try {
350
374
  const result = await request({
351
375
  route: fullRoute,
352
- init: { body: buildBody(body), method },
376
+ init: requestInit,
353
377
  });
354
378
  const tokens = responseAdapter ? responseAdapter(result.data) : result.data;
355
379
  if (!tokens.token) {
@@ -364,7 +388,7 @@ class BearerAuthProvider {
364
388
  }
365
389
  catch (error) {
366
390
  if (error instanceof Error) {
367
- this.onRefreshFailure$.next(await buildRequestError(error));
391
+ this.onRefreshFailure$.next(await buildRequestError(error, fullRoute, requestInit));
368
392
  }
369
393
  else {
370
394
  this.onRefreshFailure$.next(error);
@@ -396,27 +420,6 @@ const gql = (strings, ...values) => {
396
420
  return str;
397
421
  };
398
422
 
399
- const deepFreeze = (object) => {
400
- // Retrieve the property names defined on object
401
- const propNames = Object.getOwnPropertyNames(object);
402
- // Freeze properties before freezing self
403
- for (const name of propNames) {
404
- const value = object[name];
405
- if (value && typeof value === 'object') {
406
- deepFreeze(value);
407
- }
408
- }
409
- return Object.freeze(object);
410
- };
411
-
412
- /**
413
- * Dummy function for providing types while not breaking inference.
414
- * **This function always returns null.**
415
- * @see https://github.com/microsoft/TypeScript/issues/26242
416
- * @returns null
417
- */
418
- const def = () => null;
419
-
420
423
  function filterSuccess() {
421
424
  return function (source) {
422
425
  return source.pipe(filter((value) => isQueryStateSuccess(value)));
@@ -427,11 +430,26 @@ function filterFailure() {
427
430
  return source.pipe(filter((value) => isQueryStateFailure(value)));
428
431
  };
429
432
  }
433
+ function filterQueryStates(allowedStates) {
434
+ return function (source) {
435
+ return source.pipe(filter((value) => value && allowedStates.includes(value.type)));
436
+ };
437
+ }
430
438
  function takeUntilResponse() {
431
439
  return function (source) {
432
440
  return source.pipe(takeWhile((value) => isQueryStateLoading(value), true));
433
441
  };
434
442
  }
443
+ function filterNull() {
444
+ return function (source) {
445
+ return source.pipe(filter((value) => value !== null));
446
+ };
447
+ }
448
+ function switchQueryState() {
449
+ return function (source) {
450
+ return source.pipe(switchMap((value) => value?.state$ ?? of(null)));
451
+ };
452
+ }
435
453
  const isQueryStateLoading = (state) => state?.type === "LOADING" /* QueryStateType.Loading */;
436
454
  const isQueryStateSuccess = (state) => state?.type === "SUCCESS" /* QueryStateType.Success */;
437
455
  const isQueryStateFailure = (state) => state?.type === "FAILURE" /* QueryStateType.Failure */;
@@ -459,21 +477,8 @@ const isGqlQueryConfig = (config) => {
459
477
  };
460
478
 
461
479
  class Query {
462
- constructor(_client, _queryConfig, _route, _args) {
463
- this._client = _client;
464
- this._queryConfig = _queryConfig;
465
- this._route = _route;
466
- this._args = _args;
467
- this._currentId = 0;
468
- this._abortController = new AbortController();
469
- this._pollingSubscription = null;
470
- this._state$ = new BehaviorSubject({
471
- type: "PREPARED" /* QueryStateType.Prepared */,
472
- meta: { id: this._currentId },
473
- });
474
- }
475
480
  get _nextId() {
476
- return this._currentId++;
481
+ return ++this._currentId;
477
482
  }
478
483
  get state$() {
479
484
  return this._state$.asObservable();
@@ -491,6 +496,20 @@ class Query {
491
496
  }
492
497
  return ts < Date.now();
493
498
  }
499
+ constructor(_client, _queryConfig, _route, _args) {
500
+ this._client = _client;
501
+ this._queryConfig = _queryConfig;
502
+ this._route = _route;
503
+ this._args = _args;
504
+ this._currentId = 0;
505
+ this._abortController = new AbortController();
506
+ this._pollingSubscription = null;
507
+ this._onAbort$ = new Subject();
508
+ this._state$ = new BehaviorSubject({
509
+ type: "PREPARED" /* QueryStateType.Prepared */,
510
+ meta: { id: this._currentId },
511
+ });
512
+ }
494
513
  clone() {
495
514
  return this._client.fetch(this._queryConfig);
496
515
  }
@@ -505,11 +524,12 @@ class Query {
505
524
  if (isQueryStateLoading(this._state$.value)) {
506
525
  this.abort();
507
526
  }
508
- const meta = deepFreeze({ id });
527
+ const meta = { id };
509
528
  this._state$.next({
510
529
  type: "LOADING" /* QueryStateType.Loading */,
511
530
  meta,
512
531
  });
532
+ this._updateUseResultInDependencies();
513
533
  let body = null;
514
534
  let contentType = null;
515
535
  if (isGqlQueryConfig(this._queryConfig)) {
@@ -559,7 +579,11 @@ class Query {
559
579
  const isResponseObject = typeof response === 'object';
560
580
  const isGql = isGqlQueryConfig(this._queryConfig);
561
581
  let responseData = null;
562
- if (isGql && isResponseObject && 'data' in response.data) {
582
+ if (isGql &&
583
+ isResponseObject &&
584
+ !!response.data &&
585
+ typeof response.data === 'object' &&
586
+ 'data' in response.data) {
563
587
  responseData = response.data['data'];
564
588
  }
565
589
  else {
@@ -570,9 +594,9 @@ class Query {
570
594
  : responseData;
571
595
  this._state$.next({
572
596
  type: "SUCCESS" /* QueryStateType.Success */,
573
- response: deepFreeze(transformedResponse),
574
- rawResponse: deepFreeze(responseData),
575
- meta: deepFreeze({ ...meta, expiresAt: response.expiresInTimestamp }),
597
+ response: transformedResponse,
598
+ rawResponse: responseData,
599
+ meta: { ...meta, expiresAt: response.expiresInTimestamp },
576
600
  });
577
601
  })
578
602
  .catch((error) => this._handleExecuteError(error, meta));
@@ -581,6 +605,7 @@ class Query {
581
605
  abort() {
582
606
  this._abortController.abort();
583
607
  this._abortController = new AbortController();
608
+ this._onAbort$.next();
584
609
  return this;
585
610
  }
586
611
  poll(config) {
@@ -597,6 +622,26 @@ class Query {
597
622
  this._pollingSubscription = null;
598
623
  return this;
599
624
  }
625
+ _updateUseResultInDependencies() {
626
+ if (!this._args?.useResultIn?.length) {
627
+ return;
628
+ }
629
+ this.state$
630
+ .pipe(filterSuccess(), takeUntil(this._onAbort$), takeUntilResponse(), tap((state) => {
631
+ if (!this._args?.useResultIn) {
632
+ return;
633
+ }
634
+ for (const query of this._args.useResultIn) {
635
+ query._state$.next({
636
+ type: "SUCCESS" /* QueryStateType.Success */,
637
+ meta: { ...state.meta, id: query._nextId },
638
+ rawResponse: state.rawResponse,
639
+ response: state.response,
640
+ });
641
+ }
642
+ }))
643
+ .subscribe();
644
+ }
600
645
  _handleExecuteError(error, meta) {
601
646
  if (isAbortRequestError(error)) {
602
647
  this._state$.next({
@@ -618,6 +663,19 @@ class Query {
618
663
  }
619
664
 
620
665
  class QueryDirective {
666
+ get query() {
667
+ return this._query;
668
+ }
669
+ set query(v) {
670
+ this._query = v;
671
+ this._subscribeToQuery();
672
+ }
673
+ get cache() {
674
+ return this._cache;
675
+ }
676
+ set cache(v) {
677
+ this._cache = v;
678
+ }
621
679
  constructor(_mainTemplateRef, _viewContainerRef, _errorHandler, _cdr) {
622
680
  this._mainTemplateRef = _mainTemplateRef;
623
681
  this._viewContainerRef = _viewContainerRef;
@@ -634,19 +692,6 @@ class QueryDirective {
634
692
  };
635
693
  this._cache = false;
636
694
  }
637
- get query() {
638
- return this._query;
639
- }
640
- set query(v) {
641
- this._query = v;
642
- this._subscribeToQuery();
643
- }
644
- get cache() {
645
- return this._cache;
646
- }
647
- set cache(v) {
648
- this._cache = v;
649
- }
650
695
  static ngTemplateContextGuard(dir, ctx) {
651
696
  return true;
652
697
  }
@@ -698,9 +743,9 @@ class QueryDirective {
698
743
  }
699
744
  }
700
745
  }
701
- QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
702
- QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.9", type: QueryDirective, isStandalone: true, selector: "[query]", inputs: { query: "query", cache: ["queryCache", "cache"] }, ngImport: i0 });
703
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: QueryDirective, decorators: [{
746
+ QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
747
+ QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.0", type: QueryDirective, isStandalone: true, selector: "[query]", inputs: { query: "query", cache: ["queryCache", "cache"] }, ngImport: i0 });
748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: QueryDirective, decorators: [{
704
749
  type: Directive,
705
750
  args: [{
706
751
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -716,16 +761,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImpor
716
761
 
717
762
  /* eslint-disable @typescript-eslint/no-explicit-any */
718
763
  class InfinityQuery {
719
- constructor(_config) {
720
- this._config = _config;
721
- this._currentPage$ = new BehaviorSubject(null);
722
- this._currentCalculatedPage$ = new BehaviorSubject(null);
723
- this._totalPages$ = new BehaviorSubject(null);
724
- this._itemsPerPage$ = new BehaviorSubject(this._config.limitParam?.value ?? 10);
725
- this._currentQuery$ = new BehaviorSubject(null);
726
- this._data$ = new BehaviorSubject([]);
727
- this._subscriptions = [];
728
- }
729
764
  get currentPage$() {
730
765
  return this._currentPage$.asObservable();
731
766
  }
@@ -762,6 +797,16 @@ class InfinityQuery {
762
797
  get data() {
763
798
  return this._data$.getValue();
764
799
  }
800
+ constructor(_config) {
801
+ this._config = _config;
802
+ this._currentPage$ = new BehaviorSubject(null);
803
+ this._currentCalculatedPage$ = new BehaviorSubject(null);
804
+ this._totalPages$ = new BehaviorSubject(null);
805
+ this._itemsPerPage$ = new BehaviorSubject(this._config.limitParam?.value ?? 10);
806
+ this._currentQuery$ = new BehaviorSubject(null);
807
+ this._data$ = new BehaviorSubject([]);
808
+ this._subscriptions = [];
809
+ }
765
810
  nextPage() {
766
811
  const newPage = (this._currentPage$.value ?? 0) + 1;
767
812
  const calculatedPage = this._config?.pageParam?.valueCalculator?.({
@@ -880,6 +925,7 @@ const skipPaginationPageParamCalculator = ({ page, itemsPerPage }) => itemsPerPa
880
925
  const INFINITY_QUERY_TOKEN = new InjectionToken('INFINITY_QUERY_TOKEN');
881
926
  class InfinityQueryDirective {
882
927
  constructor() {
928
+ this._queryConfigChanged$ = new Subject();
883
929
  this._viewContext = {
884
930
  $implicit: null,
885
931
  infinityQuery: null,
@@ -893,17 +939,19 @@ class InfinityQueryDirective {
893
939
  itemsPerPage: null,
894
940
  };
895
941
  this._infinityQueryInstance = null;
896
- this._destroy$ = new Subject();
942
+ this._destroy$ = inject(DestroyService).destroy$;
897
943
  this._cdr = inject(ChangeDetectorRef);
898
944
  this._viewContainerRef = inject(ViewContainerRef);
899
945
  this._mainTemplateRef = inject((TemplateRef));
900
946
  this._errorHandler = inject(ErrorHandler);
947
+ this._data$ = new BehaviorSubject([]);
901
948
  this._isMainViewCreated = false;
902
949
  }
903
950
  get infinityQuery() {
904
951
  return this._infinityQuery;
905
952
  }
906
953
  set infinityQuery(v) {
954
+ this._cleanup();
907
955
  this._infinityQuery = v;
908
956
  this._infinityQueryInstance = this._setupInfinityQuery(v);
909
957
  this._loadNextPage();
@@ -914,6 +962,12 @@ class InfinityQueryDirective {
914
962
  get instance() {
915
963
  return this._infinityQueryInstance;
916
964
  }
965
+ get data$() {
966
+ return this._data$.asObservable();
967
+ }
968
+ get data() {
969
+ return this._data$.getValue();
970
+ }
917
971
  static ngTemplateContextGuard(dir, ctx) {
918
972
  return true;
919
973
  }
@@ -921,8 +975,6 @@ class InfinityQueryDirective {
921
975
  this._renderMainView();
922
976
  }
923
977
  ngOnDestroy() {
924
- this._destroy$.next(true);
925
- this._destroy$.unsubscribe();
926
978
  this.instance?._destroy();
927
979
  }
928
980
  _setupInfinityQuery(config) {
@@ -961,15 +1013,17 @@ class InfinityQueryDirective {
961
1013
  this._viewContext.currentPage = null;
962
1014
  this._viewContext.itemsPerPage = null;
963
1015
  this._viewContext.totalPages = null;
1016
+ this._data$.next([]);
964
1017
  }
965
1018
  this._cdr.markForCheck();
966
- }), takeUntil(this._destroy$))
1019
+ }), takeUntil(this._destroy$), takeUntil(this._queryConfigChanged$))
967
1020
  .subscribe();
968
1021
  instance.data$
969
1022
  .pipe(tap((data) => {
970
1023
  this._viewContext.infinityQuery = this._viewContext.$implicit = data;
1024
+ this._data$.next(data);
971
1025
  this._cdr.markForCheck();
972
- }), takeUntil(this._destroy$))
1026
+ }), takeUntil(this._destroy$), takeUntil(this._queryConfigChanged$))
973
1027
  .subscribe();
974
1028
  return instance;
975
1029
  }
@@ -985,16 +1039,31 @@ class InfinityQueryDirective {
985
1039
  this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
986
1040
  }
987
1041
  }
1042
+ _cleanup() {
1043
+ this._queryConfigChanged$.next(true);
1044
+ this.instance?._destroy();
1045
+ this._viewContext.loading = false;
1046
+ this._viewContext.error = null;
1047
+ this._viewContext.infinityQuery = null;
1048
+ this._viewContext.$implicit = null;
1049
+ this._viewContext.isFirstLoad = false;
1050
+ this._viewContext.canLoadMore = false;
1051
+ this._viewContext.currentPage = null;
1052
+ this._viewContext.itemsPerPage = null;
1053
+ this._viewContext.totalPages = null;
1054
+ this._data$.next([]);
1055
+ }
988
1056
  }
989
- InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
990
- InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.9", type: InfinityQueryDirective, isStandalone: true, selector: "[infinityQuery]", inputs: { infinityQuery: "infinityQuery" }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], ngImport: i0 });
991
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: InfinityQueryDirective, decorators: [{
1057
+ InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1058
+ InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.0", type: InfinityQueryDirective, isStandalone: true, selector: "[infinityQuery]", inputs: { infinityQuery: "infinityQuery" }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService], exportAs: ["infinityQuery"], ngImport: i0 });
1059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: InfinityQueryDirective, decorators: [{
992
1060
  type: Directive,
993
1061
  args: [{
994
1062
  // eslint-disable-next-line @angular-eslint/directive-selector
995
1063
  selector: '[infinityQuery]',
1064
+ exportAs: 'infinityQuery',
996
1065
  standalone: true,
997
- providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }],
1066
+ providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService],
998
1067
  }]
999
1068
  }], propDecorators: { infinityQuery: [{
1000
1069
  type: Input
@@ -1037,9 +1106,9 @@ class InfinityQueryTriggerDirective {
1037
1106
  this._observer.observe(this._elementRef.nativeElement);
1038
1107
  }
1039
1108
  }
1040
- InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1041
- InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.9", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[infinityQueryTrigger], infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
1042
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1109
+ InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1110
+ InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.0", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[infinityQueryTrigger], infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
1111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.0", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1043
1112
  type: Directive,
1044
1113
  args: [{
1045
1114
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1131,6 +1200,12 @@ config, args) => {
1131
1200
  };
1132
1201
 
1133
1202
  class QueryClient {
1203
+ get config() {
1204
+ return this._clientConfig;
1205
+ }
1206
+ get authProvider() {
1207
+ return this._authProvider;
1208
+ }
1134
1209
  constructor(_clientConfig) {
1135
1210
  this._clientConfig = _clientConfig;
1136
1211
  this._authProvider = null;
@@ -1205,23 +1280,17 @@ class QueryClient {
1205
1280
  enableGarbageCollectorLogging: _clientConfig.logging?.queryStateGarbageCollector,
1206
1281
  });
1207
1282
  }
1208
- get config() {
1209
- return this._clientConfig;
1210
- }
1211
- get authProvider() {
1212
- return this._authProvider;
1213
- }
1214
1283
  }
1215
1284
 
1216
1285
  class QueryField {
1286
+ get control() {
1287
+ return this.data.control;
1288
+ }
1217
1289
  constructor(data) {
1218
1290
  this.data = data;
1219
1291
  this.changes$ = this._setupChangesObservable();
1220
1292
  this._currentDebounceTimeout = null;
1221
1293
  }
1222
- get control() {
1223
- return this.data.control;
1224
- }
1225
1294
  setValue(value) {
1226
1295
  if (this._currentDebounceTimeout !== null) {
1227
1296
  clearTimeout(this._currentDebounceTimeout);
@@ -1268,10 +1337,11 @@ class QueryForm {
1268
1337
  const queryParams = this._activatedRoute.snapshot.queryParams;
1269
1338
  for (const [key, field] of Object.entries(this._fields)) {
1270
1339
  const value = queryParams[key];
1271
- if (value === undefined) {
1340
+ // We only check using == because the value types can be different (e.g. "1" and 1)
1341
+ if (value === undefined || value == field.control.value) {
1272
1342
  continue;
1273
1343
  }
1274
- const deserializedValue = field.data.queryParamTransformFn?.(value) ?? value;
1344
+ const deserializedValue = field.data.queryParamToValueTransformFn?.(value) ?? value;
1275
1345
  field.setValue(deserializedValue);
1276
1346
  }
1277
1347
  }
@@ -1321,7 +1391,9 @@ class QueryForm {
1321
1391
  delete queryParams[key];
1322
1392
  }
1323
1393
  else {
1324
- queryParams[key] = value;
1394
+ queryParams[key] = this._fields[key].data.valueToQueryParamTransformFn
1395
+ ? this._fields[key].data.valueToQueryParamTransformFn?.(value)
1396
+ : value;
1325
1397
  }
1326
1398
  }
1327
1399
  this._router.navigate([], {
@@ -1403,10 +1475,55 @@ const transformToDateArray = (value) => {
1403
1475
  }
1404
1476
  return null;
1405
1477
  };
1478
+ const transformToSort = (value) => {
1479
+ if (typeof value === 'string') {
1480
+ const [active, direction] = value.split(':');
1481
+ return {
1482
+ active,
1483
+ direction: direction,
1484
+ };
1485
+ }
1486
+ return null;
1487
+ };
1488
+ const transformToSortQueryParam = (value) => {
1489
+ if (typeof value === 'string') {
1490
+ return value;
1491
+ }
1492
+ if (value && typeof value === 'object' && 'active' in value && 'direction' in value) {
1493
+ const valAsSort = value;
1494
+ return valAsSort.direction ? `${valAsSort.active}:${valAsSort.direction}` : null;
1495
+ }
1496
+ return null;
1497
+ };
1498
+
1499
+ const deepFreeze = (object) => {
1500
+ // check if object is actually an object or frozen
1501
+ if (!object || typeof object !== 'object' || Object.isFrozen(object)) {
1502
+ return object;
1503
+ }
1504
+ // Retrieve the property names defined on object
1505
+ const propNames = Object.getOwnPropertyNames(object);
1506
+ // Freeze properties before freezing self
1507
+ for (const name of propNames) {
1508
+ const value = object[name];
1509
+ if (value && typeof value === 'object') {
1510
+ deepFreeze(value);
1511
+ }
1512
+ }
1513
+ return Object.freeze(object);
1514
+ };
1515
+
1516
+ /**
1517
+ * Dummy function for providing types while not breaking inference.
1518
+ * **This function always returns null.**
1519
+ * @see https://github.com/microsoft/TypeScript/issues/26242
1520
+ * @returns null
1521
+ */
1522
+ const def = () => null;
1406
1523
 
1407
1524
  /**
1408
1525
  * Generated bundle index. Do not edit.
1409
1526
  */
1410
1527
 
1411
- export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryDirective, QueryError, QueryField, QueryForm, QueryStore, buildBody, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryString, buildRequestError, buildRoute, buildTimestampFromSeconds, createInfinityQueryConfig, decryptBearer, deepFreeze, def, extractExpiresInSeconds, filterFailure, filterInvalidParams, filterSuccess, gql, guessContentType, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAbortRequestError, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isFetchResponse, isGqlQueryConfig, isParamValid, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, mergeHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, shouldCacheQuery, skipPaginationPageParamCalculator, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToString, transformToStringArray };
1528
+ export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryDirective, QueryError, QueryField, QueryForm, QueryStore, buildBody, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryString, buildRequestError, buildRoute, buildTimestampFromSeconds, createInfinityQueryConfig, decryptBearer, deepFreeze, def, extractExpiresInSeconds, filterFailure, filterInvalidParams, filterNull, filterQueryStates, filterSuccess, gql, guessContentType, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAbortRequestError, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isFetchResponse, isGqlQueryConfig, isParamValid, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, mergeHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, shouldCacheQuery, skipPaginationPageParamCalculator, switchQueryState, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
1412
1529
  //# sourceMappingURL=ethlete-query.mjs.map