Skip to content
Snippets Groups Projects
resource-search.service.ts 3.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { Resource } from '@ngxp/rest';
    
    import { isEmpty } from 'lodash-es';
    import { BehaviorSubject, Observable, first, map, tap, withLatestFrom } from 'rxjs';
    import { EMPTY_STRING, isNotEmpty } from '../tech.util';
    import { LinkRelationName, ListItemResource, SearchResourceServiceConfig } from './resource.model';
    import { ResourceRepository } from './resource.repository';
    import {
      ListResource,
      StateResource,
      createEmptyStateResource,
      createStateResource,
    } from './resource.util';
    
    /**
     * B = Type of baseresource
     * T = Type of listresource
     * I = Type of items in listresource
     */
    export class ResourceSearchService<
      B extends Resource,
      T extends ListResource,
      I extends ListItemResource,
    > {
      readonly listResource: BehaviorSubject<StateResource<T>> = new BehaviorSubject(
        createEmptyStateResource(),
      );
      readonly searchBy: BehaviorSubject<string> = new BehaviorSubject<string>(EMPTY_STRING);
    
      readonly selectedResource: BehaviorSubject<I> = new BehaviorSubject<I>(null);
    
    
      constructor(
        private config: SearchResourceServiceConfig<B>,
        private repository: ResourceRepository,
      ) {}
    
      public getResultList(): Observable<StateResource<T>> {
        return this.selectListResource().pipe(
          withLatestFrom(this.selectSearchBy(), this.config.baseResource),
          tap(([listResource, searchBy, baseResource]) => {
            this.handleChanges(listResource, searchBy, baseResource);
          }),
          map(([listResource]) => listResource),
        );
      }
    
      private selectListResource(): Observable<StateResource<T>> {
        return this.listResource.asObservable();
      }
    
      private selectSearchBy(): Observable<string> {
        return this.searchBy.asObservable();
      }
    
      handleChanges(listResource: StateResource<T>, searchBy: string, baseResource: B): void {
        if (listResource.loading) this.doSearch(searchBy, baseResource);
      }
    
      doSearch(searchBy: string, baseResource: B): void {
        if (isNotEmpty(searchBy)) {
          this.dispatchSearch(baseResource, this.config.searchLinkRel, searchBy);
        }
        if (isEmpty(searchBy)) {
          this.dispatchClearSearchList();
        }
      }
    
      dispatchSearch(baseResource: B, linkRel: LinkRelationName, searchBy: string): void {
        this.repository
          .search<T>(baseResource, linkRel, searchBy)
          .pipe(first())
          .subscribe((result: T) => this.dispatchSearchSuccess(result));
      }
    
      private dispatchSearchSuccess(result: T): void {
        this.listResource.next(createStateResource(result));
      }
    
      public clearResultList(): void {
        this.dispatchClearSearchList();
      }
    
      private dispatchClearSearchList(): void {
        this.listResource.next(createEmptyStateResource());
      }
    
      public search(searchBy: string): void {
        this.dispatchInitSearch(searchBy);
      }
    
    
      private dispatchInitSearch(searchBy: string): void {
    
        this.searchBy.next(searchBy);
        this.listResource.next({ ...this.listResource.value, loading: true });
      }
    
      public getSelectedResult(): Observable<I> {
    
        return this.selectedResource.asObservable();
      }
    
      public selectResult(selected: I): void {
    
        this.selectedResource.next(selected);
    
    
      public clearSelectedResult(): void {
        this.selectedResource.next(null);
      }