graycoreio/daffodil

View on GitHub
libs/category/driver/magento/src/category.service.ts

Summary

Maintainability
A
1 hr
Test Coverage
import {
  Injectable,
  Inject,
} from '@angular/core';
import { Apollo } from 'apollo-angular';
import { DocumentNode } from 'graphql';
import {
  Observable,
  combineLatest,
} from 'rxjs';
import {
  map,
  switchMap,
} from 'rxjs/operators';

import {
  DaffGetCategoryResponse,
  DaffCategoryUrlRequest,
  DaffCategoryRequestKind,
  DaffCategoryIdRequest,
  DaffCategoryRequest,
} from '@daffodil/category';
import { DaffCategoryServiceInterface } from '@daffodil/category/driver';
import {
  daffApplyRequestsToFilters,
  DaffFilterRequest,
} from '@daffodil/core';
import {
  DaffProductMagentoDriverConfig,
  DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_FRAGMENTS,
  MagentoProductGetFilterTypes,
  MagentoProductGetFilterTypesResponse,
  MAGENTO_PRODUCT_CONFIG_TOKEN,
  magentoAppliedSortOptionTransform,
  DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_PREVIEW_FRAGMENTS,
} from '@daffodil/product/driver/magento';

import { MAGENTO_CATEGORY_EXTRA_FRAGMENTS } from './fragments/public_api';
import {
  MAGENTO_CATEGORY_CONFIG_TOKEN,
  DaffCategoryMagentoDriverConfig,
} from './interfaces/public_api';
import {
  MagentoGetCategoryAndProductsRequest,
  MagentoGetCategoryAndProductsResponse,
  MagentoCategoryUrlResolverResponse,
  MagentoCompleteCategoryResponse,
} from './models/public_api';
import {
  MagentoGetCategoryAndProductsQuery,
  MagentoResolveCategoryUrl,
} from './queries/public_api';
import {
  DaffMagentoCategoryResponseTransformService,
  DaffMagentoAppliedFiltersTransformService,
} from './transformers/public_api';
import { addMetadataTypesToProductsResponse } from './transformers/pure/add-metadata-types-to-aggregates';

const applyFiltersOnResponse = (requests: DaffFilterRequest[], response: DaffGetCategoryResponse): DaffGetCategoryResponse => ({
  ...response,
  categoryPageMetadata: {
    ...response.categoryPageMetadata,
    filters: daffApplyRequestsToFilters(requests, response.categoryPageMetadata.filters),
  },
});

/**
 * A service for making magento apollo queries for categories. Should be provided via the {@link DaffCategoryDriver} token.
 *
 * @inheritdoc
 */
@Injectable({
  providedIn: 'root',
})
export class DaffMagentoCategoryService implements DaffCategoryServiceInterface {

  constructor(
    private apollo: Apollo,
    private magentoCategoryResponseTransformer: DaffMagentoCategoryResponseTransformService,
    private magentoAppliedFiltersTransformer: DaffMagentoAppliedFiltersTransformService,
    @Inject(MAGENTO_CATEGORY_CONFIG_TOKEN) private config: DaffCategoryMagentoDriverConfig,
    @Inject(MAGENTO_PRODUCT_CONFIG_TOKEN) private productConfig: DaffProductMagentoDriverConfig,
    @Inject(DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_FRAGMENTS) private extraProductFragments: DocumentNode[],
    @Inject(DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_PREVIEW_FRAGMENTS) private extraProductPreviewFragments: DocumentNode[],
    @Inject(MAGENTO_CATEGORY_EXTRA_FRAGMENTS) private extraCategoryFragments: DocumentNode[],
  ) {}

  get(categoryRequest: DaffCategoryIdRequest): Observable<DaffGetCategoryResponse> {
    return combineLatest([
      this.apollo.query<MagentoProductGetFilterTypesResponse>({
        query: MagentoProductGetFilterTypes,
      }),
      this.apollo.query<MagentoGetCategoryAndProductsResponse>({
        query: MagentoGetCategoryAndProductsQuery(this.extraCategoryFragments, [
          ...this.extraProductFragments,
          ...this.extraProductPreviewFragments,
        ]),
        variables: this.getCategoryAndProductsQueryVariables(categoryRequest),
      }),
    ]).pipe(
      map(([
        filterTypes,
        categoryAndProducts,
      ]) => this.transformCategory(categoryAndProducts.data, filterTypes.data, categoryRequest,this.productConfig.baseMediaUrl)),
      map(result => categoryRequest.filterRequests
        ? applyFiltersOnResponse(categoryRequest.filterRequests, result)
        : result,
      ),
    );
  }

  getByUrl(categoryRequest: DaffCategoryUrlRequest): Observable<DaffGetCategoryResponse> {
    return combineLatest([
      this.apollo.query<MagentoCategoryUrlResolverResponse>({
        query: MagentoResolveCategoryUrl,
        variables: {
          url: categoryRequest.url,
        },
      }),
      this.apollo.query<MagentoProductGetFilterTypesResponse>({
        query: MagentoProductGetFilterTypes,
      }),
    ]).pipe(
      switchMap(([
        category,
        filterTypes,
      ]) => this.apollo.query<MagentoGetCategoryAndProductsResponse>({
        query: MagentoGetCategoryAndProductsQuery(this.extraCategoryFragments, [
          ...this.extraProductFragments,
          ...this.extraProductPreviewFragments,
        ]),
        variables: this.getCategoryAndProductsQueryVariables({
          ...categoryRequest,
          id: category.data.route?.uid,
          kind: DaffCategoryRequestKind.ID,
        }),
      }).pipe(
        map(categoryAndProducts => this.transformCategory(categoryAndProducts.data, filterTypes.data, categoryRequest, this.productConfig.baseMediaUrl)),
        map(result => categoryRequest.filterRequests
          ? applyFiltersOnResponse(categoryRequest.filterRequests, result)
          : result,
        ),
      )),
    );
  }

  private getCategoryAndProductsQueryVariables(request: DaffCategoryIdRequest): MagentoGetCategoryAndProductsRequest {
    const queryVariables = {
      productFilter: this.magentoAppliedFiltersTransformer.transform(request.id, request.filterRequests),
      categoryFilters: {
        category_uid: {
          eq: request.id,
        },
      },
    };
    if(request.pageSize) {
      queryVariables['pageSize'] = request.pageSize;
    }
    if(request.currentPage) {
      queryVariables['currentPage'] = request.currentPage;
    }
    if(request.appliedSortOption && request.appliedSortDirection) {
      queryVariables['sort'] = magentoAppliedSortOptionTransform(request.appliedSortOption, request.appliedSortDirection);
    }

    return queryVariables;
  }

  private transformCategory(
    categoryResponse: MagentoGetCategoryAndProductsResponse,
    filterTypesResponse: MagentoProductGetFilterTypesResponse,
    request: DaffCategoryRequest,
    mediaUrl: string,
  ): DaffGetCategoryResponse {
    const aggregations = addMetadataTypesToProductsResponse(filterTypesResponse, categoryResponse);
    const completeCategory: MagentoCompleteCategoryResponse = {
      category: categoryResponse.categoryList[0],
      products: categoryResponse.products.items,
      aggregates: aggregations.products.aggregations,
      sort_fields: aggregations.products.sort_fields,
      total_count: categoryResponse.products.total_count,
      page_info: categoryResponse.products.page_info,
      appliedSortOption: request.appliedSortOption,
      appliedSortDirection: request.appliedSortDirection,
    };

    return this.magentoCategoryResponseTransformer.transform(completeCategory, mediaUrl);
  }
}