All files gql.service.ts

100% Statements 20/20
100% Branches 8/8
100% Functions 12/12
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122                                1x 12x   12x   12x   12x             2x   2x                   3x   3x 3x 3x   3x                           2x         2x                   4x         4x               5x 5x                                 5x                   3x      
import { inject, Injectable } from '@angular/core';
import { ApolloClient, ApolloClientOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client/core';
import { AppHttpHandlersService, TGqlClient } from '@app/client-store-http-progress';
import { IUserState, userSelector } from '@app/client-store-user';
import { Store } from '@ngrx/store';
import { Apollo } from 'apollo-angular';
import { DocumentNode } from 'graphql';
import { from, Observable, of } from 'rxjs';
import { first, map, switchMap, tap } from 'rxjs/operators';
 
/**
 * Client Graphql service.
 */
@Injectable({
  providedIn: 'root',
})
export class AppGqlService {
  private readonly apollo = inject(Apollo);
 
  private readonly handlers = inject(AppHttpHandlersService);
 
  private readonly store = inject(Store<IUserState>);
 
  private readonly userToken$ = this.store.select(userSelector.token).pipe(first());
 
  /**
   * Creates apollo client for a specific user role.
   * @param name the client name
   */
  public createApolloClient(name: TGqlClient = 'graphql'): Observable<ApolloClientOptions<NormalizedCacheObject>> {
    return this.getApolloClientOptions(name).pipe(
      tap(options => {
        this.apollo.create(options, name);
      }),
    );
  }
 
  /**
   * Resets apollo client for a specific user role.
   * @param name the client name
   */
  public resetApolloClient(name: TGqlClient = 'graphql') {
    return this.getApolloClientOptions(name).pipe(
      switchMap(options => {
        const newClient = new ApolloClient(options);
        const client = this.apollo.use(name).client as ApolloClient<NormalizedCacheObject> | undefined;
        return this.clearClient(client).pipe(
          tap(() => {
            this.apollo.use(name).client = newClient;
          }),
        );
      }),
    );
  }
 
  /**
   * Gql query - a read-only fetch.
   * @param query the quesry
   * @param name the client name
   * @param variables the query arguments
   */
  public query<T>(query: DocumentNode, name: TGqlClient = 'graphql', variables: Record<string, unknown> = {}) {
    const observable = this.apollo.use(name).watchQuery<T>({
      query,
      variables,
      fetchPolicy: 'no-cache',
    }).valueChanges;
    return this.handlers.pipeGqlResponse<T>(observable);
  }
 
  /**
   * Gql mutation - a write followed by a fetch.
   * @param mutation the muration
   * @param name the client name
   * @param variables the mutation arguments
   */
  public mutate<T>(mutation: DocumentNode, name: TGqlClient = 'graphql', variables: Record<string, unknown> = {}) {
    const observable = this.apollo.use(name).mutate<T>({
      mutation,
      variables,
      fetchPolicy: 'no-cache',
    });
    return this.handlers.pipeGqlResponse<T>(observable);
  }
 
  /**
   * Returns apollo client options depending on user role.
   * @param name the client name
   */
  private getApolloClientOptions(name: TGqlClient): Observable<ApolloClientOptions<NormalizedCacheObject>> {
    return this.userToken$.pipe(
      map(token => this.handlers.createGqlLink(token, name)),
      map(link => {
        const options: ApolloClientOptions<NormalizedCacheObject> = {
          link,
          cache: new InMemoryCache({ resultCaching: false }),
          defaultOptions: {
            query: {
              errorPolicy: 'all',
            },
            watchQuery: {
              errorPolicy: 'all',
            },
            mutate: {
              errorPolicy: 'all',
            },
          },
        };
        return options;
      }),
    );
  }
 
  /**
   * Clears apollo client.
   * @param client apollo client
   */
  private clearClient(client?: ApolloClient<NormalizedCacheObject>) {
    return typeof client !== 'undefined' ? from(client.resetStore()) : of(null);
  }
}