elasticsearch-resolver.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { Args, Mutation, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';
  2. import {
  3. Job as GraphQLJob,
  4. Permission,
  5. QuerySearchArgs,
  6. SearchResponse,
  7. } from '@vendure/common/lib/generated-types';
  8. import { Omit } from '@vendure/common/lib/omit';
  9. import {
  10. Allow,
  11. Collection,
  12. Ctx,
  13. FacetValue,
  14. RequestContext,
  15. SearchJobBufferService,
  16. SearchResolver,
  17. } from '@vendure/core';
  18. import { ElasticsearchService } from '../elasticsearch.service';
  19. import { ElasticSearchInput, SearchPriceData } from '../types';
  20. @Resolver('SearchResponse')
  21. export class ShopElasticSearchResolver implements Pick<SearchResolver, 'search'> {
  22. constructor(private elasticsearchService: ElasticsearchService) {}
  23. @Query()
  24. @Allow(Permission.Public)
  25. async search(
  26. @Ctx() ctx: RequestContext,
  27. @Args() args: QuerySearchArgs,
  28. ): Promise<Omit<SearchResponse, 'facetValues' | 'collections'>> {
  29. const result = await this.elasticsearchService.search(ctx, args.input, true);
  30. // ensure the facetValues property resolver has access to the input args
  31. (result as any).input = args.input;
  32. return result;
  33. }
  34. @ResolveField()
  35. async prices(
  36. @Ctx() ctx: RequestContext,
  37. @Parent() parent: { input: ElasticSearchInput },
  38. ): Promise<SearchPriceData> {
  39. return this.elasticsearchService.priceRange(ctx, parent.input);
  40. }
  41. }
  42. @Resolver('SearchResponse')
  43. export class AdminElasticSearchResolver implements Pick<SearchResolver, 'search' | 'reindex'> {
  44. constructor(
  45. private elasticsearchService: ElasticsearchService,
  46. private searchJobBufferService: SearchJobBufferService,
  47. ) {}
  48. @Query()
  49. @Allow(Permission.ReadCatalog, Permission.ReadProduct)
  50. async search(
  51. @Ctx() ctx: RequestContext,
  52. @Args() args: QuerySearchArgs,
  53. ): Promise<Omit<SearchResponse, 'facetValues' | 'collections'>> {
  54. const result = await this.elasticsearchService.search(ctx, args.input, false);
  55. // ensure the facetValues property resolver has access to the input args
  56. (result as any).input = args.input;
  57. return result;
  58. }
  59. @Mutation()
  60. @Allow(Permission.UpdateCatalog, Permission.UpdateProduct)
  61. async reindex(@Ctx() ctx: RequestContext): Promise<GraphQLJob> {
  62. return this.elasticsearchService.reindex(ctx) as unknown as GraphQLJob;
  63. }
  64. @Query()
  65. @Allow(Permission.ReadCatalog, Permission.ReadProduct)
  66. async pendingSearchIndexUpdates(...args: any[]): Promise<any> {
  67. return this.searchJobBufferService.getPendingSearchUpdates();
  68. }
  69. @Mutation()
  70. @Allow(Permission.UpdateCatalog, Permission.UpdateProduct)
  71. async runPendingSearchIndexUpdates(...args: any[]): Promise<any> {
  72. // Intentionally not awaiting this method call
  73. void this.searchJobBufferService.runPendingSearchUpdates();
  74. return { success: true };
  75. }
  76. }
  77. @Resolver('SearchResponse')
  78. export class EntityElasticSearchResolver implements Pick<SearchResolver, 'facetValues' | 'collections'> {
  79. constructor(private elasticsearchService: ElasticsearchService) {}
  80. @ResolveField()
  81. async facetValues(
  82. @Ctx() ctx: RequestContext,
  83. @Parent() parent: Omit<SearchResponse, 'facetValues' | 'collections'>,
  84. ): Promise<Array<{ facetValue: FacetValue; count: number }>> {
  85. const facetValues = await this.elasticsearchService.facetValues(ctx, (parent as any).input, true);
  86. return facetValues.filter(i => !i.facetValue.facet.isPrivate);
  87. }
  88. @ResolveField()
  89. async collections(
  90. @Ctx() ctx: RequestContext,
  91. @Parent() parent: Omit<SearchResponse, 'facetValues' | 'collections'>,
  92. ): Promise<Array<{ collection: Collection; count: number }>> {
  93. const collections = await this.elasticsearchService.collections(ctx, (parent as any).input, true);
  94. return collections.filter(i => !i.collection.isPrivate);
  95. }
  96. }