Skip to content
Snippets Groups Projects
resource.loader.ts 3.37 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { Resource, getUrl, hasLink } from '@ngxp/rest';
    import { isEqual, isNull } from 'lodash-es';
    import { Observable, combineLatest, filter, startWith, tap } from 'rxjs';
    import { ResourceStateService } from '../ngrx/state.service';
    import { isNotNull } from '../tech.util';
    import { ServiceConfig } from './resource.model';
    import { mapToFirst, mapToResource } from './resource.rxjs.operator';
    import {
      StateResource,
      createEmptyStateResource,
      isInvalidResourceCombination,
      isLoadingRequired,
      isStateResoureStable,
    } from './resource.util';
    
    export class ResourceLoader<B extends Resource, T extends Resource> {
      configResource: B = null;
    
      constructor(
        private config: ServiceConfig<B>,
    
        private resourceStateService: ResourceStateService<B, T>,
    
      ) {}
    
      public get(): Observable<StateResource<T>> {
        return combineLatest([
          this.resourceStateService.selectResource(),
          this.getConfigResource(),
        ]).pipe(
          tap(([stateResource, configResource]) =>
            this.handleResourceChanges(stateResource, configResource),
          ),
          filter(
            ([stateResource, configResource]) =>
              !isInvalidResourceCombination(stateResource, configResource),
          ),
          mapToFirst<T, B>(),
          startWith(createEmptyStateResource<T>(true)),
        );
      }
    
      private getConfigResource(): Observable<B> {
        return this.config.baseResource.pipe(filter(isStateResoureStable), mapToResource<B>());
      }
    
      handleResourceChanges(stateResource: StateResource<T>, configResource: B): void {
        if (!isEqual(this.configResource, configResource)) {
          this.handleConfigResourceChanges(stateResource, configResource);
        } else if (this.shouldLoadResource(stateResource, configResource)) {
          this.loadResource(configResource);
        }
      }
    
      handleConfigResourceChanges(stateResource: StateResource<T>, configResource: B) {
        this.configResource = configResource;
        if (isStateResoureStable(stateResource)) {
          this.updateStateResourceByConfigResource(stateResource, configResource);
        }
      }
    
      updateStateResourceByConfigResource(stateResource: StateResource<T>, configResource: B): void {
        if (this.shouldClearStateResource(stateResource, configResource)) {
          this.resourceStateService.clearResource();
        } else if (this.hasGetLink(configResource)) {
          this.loadResource(configResource);
        }
      }
    
      shouldClearStateResource(stateResource: StateResource<T>, configResource: B): boolean {
        return (
          (isNull(configResource) || this.hasNotGetLink(configResource)) &&
          !this.isStateResourceEmpty(stateResource)
        );
      }
    
      private hasNotGetLink(configResource: B) {
        return !this.hasGetLink(configResource);
      }
    
      hasGetLink(configResource: B): boolean {
        return isNotNull(configResource) && hasLink(configResource, this.config.getLinkRel);
      }
    
      private isStateResourceEmpty(stateResource: StateResource<T>): boolean {
        return isEqual(stateResource, createEmptyStateResource());
      }
    
      shouldLoadResource(stateResource: StateResource<T>, configResource: B): boolean {
        return (
          isNotNull(configResource) &&
          hasLink(configResource, this.config.getLinkRel) &&
          isLoadingRequired(stateResource)
        );
      }
    
      loadResource(configResource: B): void {
        this.resourceStateService.loadResource(this.getGetUrl(configResource));
      }
    
      private getGetUrl(configResource: B): string {
        return getUrl(configResource, this.config.getLinkRel);
      }
    }