@vendure/elasticsearch-plugin 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/lib/src/{graphql-schema-extensions.d.ts → api/api-extensions.d.ts} +1 -1
  2. package/lib/src/{graphql-schema-extensions.js → api/api-extensions.js} +107 -56
  3. package/lib/src/api/api-extensions.js.map +1 -0
  4. package/lib/src/{custom-mappings.resolver.d.ts → api/custom-mappings.resolver.d.ts} +1 -1
  5. package/lib/src/{custom-mappings.resolver.js → api/custom-mappings.resolver.js} +1 -1
  6. package/lib/src/api/custom-mappings.resolver.js.map +1 -0
  7. package/lib/src/api/custom-script-fields.resolver.d.ts +12 -0
  8. package/lib/src/api/custom-script-fields.resolver.js +50 -0
  9. package/lib/src/api/custom-script-fields.resolver.js.map +1 -0
  10. package/lib/src/{elasticsearch-resolver.d.ts → api/elasticsearch-resolver.d.ts} +9 -6
  11. package/lib/src/{elasticsearch-resolver.js → api/elasticsearch-resolver.js} +27 -3
  12. package/lib/src/api/elasticsearch-resolver.js.map +1 -0
  13. package/lib/src/build-elastic-body.js +56 -41
  14. package/lib/src/build-elastic-body.js.map +1 -1
  15. package/lib/src/constants.d.ts +0 -1
  16. package/lib/src/constants.js +1 -2
  17. package/lib/src/constants.js.map +1 -1
  18. package/lib/src/elasticsearch.service.d.ts +11 -2
  19. package/lib/src/elasticsearch.service.js +139 -68
  20. package/lib/src/elasticsearch.service.js.map +1 -1
  21. package/lib/src/{elasticsearch-index.service.d.ts → indexing/elasticsearch-index.service.d.ts} +1 -1
  22. package/lib/src/{elasticsearch-index.service.js → indexing/elasticsearch-index.service.js} +0 -0
  23. package/lib/src/indexing/elasticsearch-index.service.js.map +1 -0
  24. package/lib/src/{indexer.controller.d.ts → indexing/indexer.controller.d.ts} +24 -10
  25. package/lib/src/{indexer.controller.js → indexing/indexer.controller.js} +221 -266
  26. package/lib/src/indexing/indexer.controller.js.map +1 -0
  27. package/lib/src/{indexing-utils.d.ts → indexing/indexing-utils.d.ts} +2 -2
  28. package/lib/src/{indexing-utils.js → indexing/indexing-utils.js} +3 -59
  29. package/lib/src/indexing/indexing-utils.js.map +1 -0
  30. package/lib/src/options.d.ts +203 -32
  31. package/lib/src/options.js +5 -0
  32. package/lib/src/options.js.map +1 -1
  33. package/lib/src/plugin.d.ts +4 -2
  34. package/lib/src/plugin.js +31 -11
  35. package/lib/src/plugin.js.map +1 -1
  36. package/lib/src/types.d.ts +51 -13
  37. package/package.json +4 -4
  38. package/lib/src/custom-mappings.resolver.js.map +0 -1
  39. package/lib/src/elasticsearch-index.service.js.map +0 -1
  40. package/lib/src/elasticsearch-resolver.js.map +0 -1
  41. package/lib/src/graphql-schema-extensions.js.map +0 -1
  42. package/lib/src/indexer.controller.js.map +0 -1
  43. package/lib/src/indexing-utils.js.map +0 -1
@@ -11,14 +11,15 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var ElasticsearchIndexerController_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.ElasticsearchIndexerController = exports.variantRelations = exports.productRelations = void 0;
16
+ exports.ElasticsearchIndexerController = exports.defaultVariantRelations = exports.defaultProductRelations = void 0;
16
17
  const common_1 = require("@nestjs/common");
17
18
  const unique_1 = require("@vendure/common/lib/unique");
18
19
  const core_1 = require("@vendure/core");
19
- const constants_1 = require("./constants");
20
+ const constants_1 = require("../constants");
20
21
  const indexing_utils_1 = require("./indexing-utils");
21
- exports.productRelations = [
22
+ exports.defaultProductRelations = [
22
23
  'variants',
23
24
  'featuredAsset',
24
25
  'facetValues',
@@ -26,7 +27,7 @@ exports.productRelations = [
26
27
  'channels',
27
28
  'channels.defaultTaxZone',
28
29
  ];
29
- exports.variantRelations = [
30
+ exports.defaultVariantRelations = [
30
31
  'featuredAsset',
31
32
  'facetValues',
32
33
  'facetValues.facet',
@@ -35,16 +36,20 @@ exports.variantRelations = [
35
36
  'channels',
36
37
  'channels.defaultTaxZone',
37
38
  ];
38
- let ElasticsearchIndexerController = class ElasticsearchIndexerController {
39
- constructor(connection, options, productVariantService, configService) {
39
+ let ElasticsearchIndexerController = ElasticsearchIndexerController_1 = class ElasticsearchIndexerController {
40
+ constructor(connection, options, productPriceApplicator, configService, productVariantService, requestContextCache) {
40
41
  this.connection = connection;
41
42
  this.options = options;
42
- this.productVariantService = productVariantService;
43
+ this.productPriceApplicator = productPriceApplicator;
43
44
  this.configService = configService;
45
+ this.productVariantService = productVariantService;
46
+ this.requestContextCache = requestContextCache;
44
47
  this.asyncQueue = new core_1.AsyncQueue('elasticsearch-indexer', 5);
45
48
  }
46
49
  onModuleInit() {
47
50
  this.client = indexing_utils_1.getClient(this.options);
51
+ this.productRelations = this.getReindexRelationsRelations(exports.defaultProductRelations, this.options.hydrateProductRelations);
52
+ this.variantRelations = this.getReindexRelationsRelations(exports.defaultVariantRelations, this.options.hydrateProductVariantRelations);
48
53
  }
49
54
  onModuleDestroy() {
50
55
  return this.client.close();
@@ -137,27 +142,17 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
137
142
  const timeStart = Date.now();
138
143
  const operations = [];
139
144
  const reindexTempName = new Date().getTime();
140
- const productIndexName = this.options.indexPrefix + constants_1.PRODUCT_INDEX_NAME;
141
145
  const variantIndexName = this.options.indexPrefix + constants_1.VARIANT_INDEX_NAME;
142
- const reindexProductAliasName = productIndexName + `-reindex-${reindexTempName}`;
143
146
  const reindexVariantAliasName = variantIndexName + `-reindex-${reindexTempName}`;
144
147
  try {
145
- await indexing_utils_1.createIndices(this.client, this.options.indexPrefix, this.options.indexSettings, this.options.indexMappingProperties, this.configService.entityIdStrategy.primaryKeyType, true, `-reindex-${reindexTempName}`);
146
- const reindexProductIndexName = await indexing_utils_1.getIndexNameByAlias(this.client, reindexProductAliasName);
148
+ await indexing_utils_1.createIndices(this.client, this.options.indexPrefix, this.options.indexSettings, this.options.indexMappingProperties, true, `-reindex-${reindexTempName}`);
147
149
  const reindexVariantIndexName = await indexing_utils_1.getIndexNameByAlias(this.client, reindexVariantAliasName);
148
- const originalProductAliasExist = await this.client.indices.existsAlias({
149
- name: productIndexName,
150
- });
151
150
  const originalVariantAliasExist = await this.client.indices.existsAlias({
152
151
  name: variantIndexName,
153
152
  });
154
- const originalProductIndexExist = await this.client.indices.exists({
155
- index: productIndexName,
156
- });
157
153
  const originalVariantIndexExist = await this.client.indices.exists({
158
154
  index: variantIndexName,
159
155
  });
160
- const originalProductIndexName = await indexing_utils_1.getIndexNameByAlias(this.client, productIndexName);
161
156
  const originalVariantIndexName = await indexing_utils_1.getIndexNameByAlias(this.client, variantIndexName);
162
157
  if (originalVariantAliasExist.body || originalVariantIndexExist.body) {
163
158
  await this.client.reindex({
@@ -172,19 +167,6 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
172
167
  },
173
168
  });
174
169
  }
175
- if (originalProductAliasExist.body || originalProductIndexExist.body) {
176
- await this.client.reindex({
177
- refresh: true,
178
- body: {
179
- source: {
180
- index: productIndexName,
181
- },
182
- dest: {
183
- index: reindexProductAliasName,
184
- },
185
- },
186
- });
187
- }
188
170
  const actions = [
189
171
  {
190
172
  remove: {
@@ -192,38 +174,13 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
192
174
  alias: reindexVariantAliasName,
193
175
  },
194
176
  },
195
- {
196
- remove: {
197
- index: reindexProductIndexName,
198
- alias: reindexProductAliasName,
199
- },
200
- },
201
177
  {
202
178
  add: {
203
179
  index: reindexVariantIndexName,
204
180
  alias: variantIndexName,
205
181
  },
206
182
  },
207
- {
208
- add: {
209
- index: reindexProductIndexName,
210
- alias: productIndexName,
211
- },
212
- },
213
183
  ];
214
- if (originalProductAliasExist.body) {
215
- actions.push({
216
- remove: {
217
- index: originalProductIndexName,
218
- alias: productIndexName,
219
- },
220
- });
221
- }
222
- else if (originalProductIndexExist.body) {
223
- await this.client.indices.delete({
224
- index: [productIndexName],
225
- });
226
- }
227
184
  if (originalVariantAliasExist.body) {
228
185
  actions.push({
229
186
  remove: {
@@ -242,11 +199,6 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
242
199
  actions,
243
200
  },
244
201
  });
245
- if (originalProductAliasExist.body) {
246
- await this.client.indices.delete({
247
- index: [originalProductIndexName],
248
- });
249
- }
250
202
  if (originalVariantAliasExist.body) {
251
203
  await this.client.indices.delete({
252
204
  index: [originalVariantIndexName],
@@ -270,18 +222,6 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
270
222
  index: [reindexVariantIndexName],
271
223
  });
272
224
  }
273
- const reindexProductAliasExist = await this.client.indices.existsAlias({
274
- name: reindexProductAliasName,
275
- });
276
- if (reindexProductAliasExist.body) {
277
- const reindexProductAliasResult = await this.client.indices.getAlias({
278
- name: reindexProductAliasName,
279
- });
280
- const reindexProductIndexName = Object.keys(reindexProductAliasResult.body)[0];
281
- await this.client.indices.delete({
282
- index: [reindexProductIndexName],
283
- });
284
- }
285
225
  }
286
226
  const deletedProductIds = await this.connection
287
227
  .getRepository(core_1.Product)
@@ -321,26 +261,18 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
321
261
  });
322
262
  }
323
263
  async updateAsset(data) {
324
- const result1 = await this.updateAssetFocalPointForIndex(constants_1.PRODUCT_INDEX_NAME, data.asset);
325
- const result2 = await this.updateAssetFocalPointForIndex(constants_1.VARIANT_INDEX_NAME, data.asset);
264
+ const result = await this.updateAssetFocalPointForIndex(constants_1.VARIANT_INDEX_NAME, data.asset);
326
265
  await this.client.indices.refresh({
327
- index: [
328
- this.options.indexPrefix + constants_1.PRODUCT_INDEX_NAME,
329
- this.options.indexPrefix + constants_1.VARIANT_INDEX_NAME,
330
- ],
266
+ index: [this.options.indexPrefix + constants_1.VARIANT_INDEX_NAME],
331
267
  });
332
- return result1 && result2;
268
+ return result;
333
269
  }
334
270
  async deleteAsset(data) {
335
- const result1 = await this.deleteAssetForIndex(constants_1.PRODUCT_INDEX_NAME, data.asset);
336
- const result2 = await this.deleteAssetForIndex(constants_1.VARIANT_INDEX_NAME, data.asset);
271
+ const result = await this.deleteAssetForIndex(constants_1.VARIANT_INDEX_NAME, data.asset);
337
272
  await this.client.indices.refresh({
338
- index: [
339
- this.options.indexPrefix + constants_1.PRODUCT_INDEX_NAME,
340
- this.options.indexPrefix + constants_1.VARIANT_INDEX_NAME,
341
- ],
273
+ index: [this.options.indexPrefix + constants_1.VARIANT_INDEX_NAME],
342
274
  });
343
- return result1 && result2;
275
+ return result;
344
276
  }
345
277
  async updateAssetFocalPointForIndex(indexName, asset) {
346
278
  const focalPoint = asset.focalPoint || null;
@@ -396,15 +328,22 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
396
328
  const operations = [];
397
329
  for (const productId of productIds) {
398
330
  operations.push(...(await this.deleteProductOperations(productId)));
399
- const product = await this.connection.getRepository(core_1.Product).findOne(productId, {
400
- relations: exports.productRelations,
401
- where: {
402
- deletedAt: null,
403
- },
404
- });
331
+ let product;
332
+ try {
333
+ product = await this.connection.getRepository(core_1.Product).findOne(productId, {
334
+ relations: this.productRelations,
335
+ where: {
336
+ deletedAt: null,
337
+ },
338
+ });
339
+ }
340
+ catch (e) {
341
+ core_1.Logger.error(e.message, constants_1.loggerCtx, e.stack);
342
+ throw e;
343
+ }
405
344
  if (product) {
406
345
  const updatedProductVariants = await this.connection.getRepository(core_1.ProductVariant).findByIds(product.variants.map(v => v.id), {
407
- relations: exports.variantRelations,
346
+ relations: this.variantRelations,
408
347
  where: {
409
348
  deletedAt: null,
410
349
  },
@@ -412,15 +351,18 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
412
351
  id: 'ASC',
413
352
  },
414
353
  });
354
+ // tslint:disable-next-line:no-non-null-assertion
415
355
  updatedProductVariants.forEach(variant => (variant.product = product));
416
356
  if (!product.enabled) {
417
357
  updatedProductVariants.forEach(v => (v.enabled = false));
418
358
  }
419
359
  core_1.Logger.verbose(`Updating Product (${productId})`, constants_1.loggerCtx);
420
- if (updatedProductVariants.length) {
421
- operations.push(...(await this.updateVariantsOperations(updatedProductVariants)));
360
+ const languageVariants = [];
361
+ languageVariants.push(...product.translations.map(t => t.languageCode));
362
+ for (const variant of product.variants) {
363
+ languageVariants.push(...variant.translations.map(t => t.languageCode));
422
364
  }
423
- const languageVariants = product.translations.map(t => t.languageCode);
365
+ const uniqueLanguageVariants = unique_1.unique(languageVariants);
424
366
  for (const channel of product.channels) {
425
367
  const channelCtx = new core_1.RequestContext({
426
368
  channel,
@@ -431,65 +373,73 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
431
373
  });
432
374
  const variantsInChannel = updatedProductVariants.filter(v => v.channels.map(c => c.id).includes(channelCtx.channelId));
433
375
  for (const variant of variantsInChannel) {
434
- await this.productVariantService.applyChannelPriceAndTax(variant, channelCtx);
376
+ await this.productPriceApplicator.applyChannelPriceAndTax(variant, channelCtx);
435
377
  }
436
- for (const languageCode of languageVariants) {
437
- operations.push({
438
- index: constants_1.PRODUCT_INDEX_NAME,
439
- operation: {
440
- update: {
441
- _id: this.getId(product.id, channelCtx.channelId, languageCode),
378
+ for (const languageCode of uniqueLanguageVariants) {
379
+ if (variantsInChannel.length) {
380
+ for (const variant of variantsInChannel) {
381
+ operations.push({
382
+ index: constants_1.VARIANT_INDEX_NAME,
383
+ operation: {
384
+ update: {
385
+ _id: ElasticsearchIndexerController_1.getId(variant.id, channelCtx.channelId, languageCode),
386
+ },
387
+ },
388
+ }, {
389
+ index: constants_1.VARIANT_INDEX_NAME,
390
+ operation: {
391
+ doc: await this.createVariantIndexItem(variant, variantsInChannel, channelCtx, languageCode),
392
+ doc_as_upsert: true,
393
+ },
394
+ });
395
+ }
396
+ }
397
+ else {
398
+ operations.push({
399
+ index: constants_1.VARIANT_INDEX_NAME,
400
+ operation: {
401
+ update: {
402
+ _id: ElasticsearchIndexerController_1.getId(-product.id, channelCtx.channelId, languageCode),
403
+ },
442
404
  },
443
- },
444
- }, {
445
- index: constants_1.PRODUCT_INDEX_NAME,
446
- operation: {
447
- doc: variantsInChannel.length
448
- ? this.createProductIndexItem(variantsInChannel, channelCtx.channelId, languageCode)
449
- : this.createSyntheticProductIndexItem(channelCtx, product, languageCode),
450
- doc_as_upsert: true,
451
- },
452
- });
405
+ }, {
406
+ index: constants_1.VARIANT_INDEX_NAME,
407
+ operation: {
408
+ doc: this.createSyntheticProductIndexItem(product, channelCtx, languageCode),
409
+ doc_as_upsert: true,
410
+ },
411
+ });
412
+ }
453
413
  }
454
414
  }
455
415
  }
456
416
  }
457
417
  return operations;
458
418
  }
459
- async updateVariantsOperations(productVariants) {
460
- if (productVariants.length === 0) {
461
- return [];
462
- }
463
- const operations = [];
464
- for (const variant of productVariants) {
465
- const languageVariants = variant.translations.map(t => t.languageCode);
466
- for (const channel of variant.channels) {
467
- const channelCtx = new core_1.RequestContext({
468
- channel,
469
- apiType: 'admin',
470
- authorizedAsOwnerOnly: false,
471
- isAuthorized: true,
472
- session: {},
473
- });
474
- await this.productVariantService.applyChannelPriceAndTax(variant, channelCtx);
475
- for (const languageCode of languageVariants) {
476
- operations.push({
477
- index: constants_1.VARIANT_INDEX_NAME,
478
- operation: {
479
- update: { _id: this.getId(variant.id, channelCtx.channelId, languageCode) },
480
- },
481
- }, {
482
- index: constants_1.VARIANT_INDEX_NAME,
483
- operation: {
484
- doc: this.createVariantIndexItem(variant, channelCtx.channelId, languageCode),
485
- doc_as_upsert: true,
486
- },
487
- });
419
+ /**
420
+ * Takes the default relations, and combines them with any extra relations specified in the
421
+ * `hydrateProductRelations` and `hydrateProductVariantRelations`. This method also ensures
422
+ * that the relation values are unique and that paths are fully expanded.
423
+ *
424
+ * This means that if a `hydrateProductRelations` value of `['assets.asset']` is specified,
425
+ * this method will also add `['assets']` to the relations array, otherwise TypeORM would
426
+ * throw an error trying to join a 2nd-level deep relation without the first level also
427
+ * being joined.
428
+ */
429
+ getReindexRelationsRelations(defaultRelations, hydratedRelations) {
430
+ const uniqueRelations = unique_1.unique([...defaultRelations, ...hydratedRelations]);
431
+ for (const relation of hydratedRelations) {
432
+ const path = relation.split('.');
433
+ const pathToPart = [];
434
+ for (const part of path) {
435
+ pathToPart.push(part);
436
+ const joinedPath = pathToPart.join('.');
437
+ if (!uniqueRelations.includes(joinedPath)) {
438
+ uniqueRelations.push(joinedPath);
488
439
  }
489
440
  }
490
441
  }
491
- core_1.Logger.verbose(`Updating ${productVariants.length} ProductVariants`, constants_1.loggerCtx);
492
- return operations;
442
+ return uniqueRelations;
493
443
  }
494
444
  async deleteProductOperations(productId) {
495
445
  const channels = await this.connection
@@ -505,29 +455,39 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
505
455
  }
506
456
  core_1.Logger.verbose(`Deleting 1 Product (id: ${productId})`, constants_1.loggerCtx);
507
457
  const operations = [];
458
+ const languageVariants = [];
459
+ languageVariants.push(...product.translations.map(t => t.languageCode));
460
+ for (const variant of product.variants) {
461
+ languageVariants.push(...variant.translations.map(t => t.languageCode));
462
+ }
463
+ const uniqueLanguageVariants = unique_1.unique(languageVariants);
508
464
  for (const { id: channelId } of channels) {
509
- const languageVariants = product.translations.map(t => t.languageCode);
510
- for (const languageCode of languageVariants) {
465
+ for (const languageCode of uniqueLanguageVariants) {
511
466
  operations.push({
512
- index: constants_1.PRODUCT_INDEX_NAME,
513
- operation: { delete: { _id: this.getId(product.id, channelId, languageCode) } },
467
+ index: constants_1.VARIANT_INDEX_NAME,
468
+ operation: {
469
+ delete: {
470
+ _id: ElasticsearchIndexerController_1.getId(-product.id, channelId, languageCode),
471
+ },
472
+ },
514
473
  });
515
474
  }
516
475
  }
517
- operations.push(...(await this.deleteVariantsInternalOperations(product.variants, channels.map(c => c.id))));
476
+ operations.push(...(await this.deleteVariantsInternalOperations(product.variants, channels.map(c => c.id), uniqueLanguageVariants)));
518
477
  return operations;
519
478
  }
520
- async deleteVariantsInternalOperations(variants, channelIds) {
479
+ async deleteVariantsInternalOperations(variants, channelIds, languageVariants) {
521
480
  core_1.Logger.verbose(`Deleting ${variants.length} ProductVariants`, constants_1.loggerCtx);
522
481
  const operations = [];
523
482
  for (const variant of variants) {
524
483
  for (const channelId of channelIds) {
525
- const languageVariants = variant.translations.map(t => t.languageCode);
526
484
  for (const languageCode of languageVariants) {
527
485
  operations.push({
528
486
  index: constants_1.VARIANT_INDEX_NAME,
529
487
  operation: {
530
- delete: { _id: this.getId(variant.id, channelId, languageCode) },
488
+ delete: {
489
+ _id: ElasticsearchIndexerController_1.getId(variant.id, channelId, languageCode),
490
+ },
531
491
  },
532
492
  });
533
493
  }
@@ -543,20 +503,11 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
543
503
  return unique_1.unique(variants.map(v => v.product.id));
544
504
  }
545
505
  async executeBulkOperations(operations) {
546
- const productOperations = [];
547
506
  const variantOperations = [];
548
507
  for (const operation of operations) {
549
- if (operation.index === constants_1.PRODUCT_INDEX_NAME) {
550
- productOperations.push(operation.operation);
551
- }
552
- else {
553
- variantOperations.push(operation.operation);
554
- }
508
+ variantOperations.push(operation.operation);
555
509
  }
556
- return Promise.all([
557
- this.runBulkOperationsOnIndex(constants_1.PRODUCT_INDEX_NAME, productOperations),
558
- this.runBulkOperationsOnIndex(constants_1.VARIANT_INDEX_NAME, variantOperations),
559
- ]);
510
+ return Promise.all([this.runBulkOperationsOnIndex(constants_1.VARIANT_INDEX_NAME, variantOperations)]);
560
511
  }
561
512
  async runBulkOperationsOnIndex(indexName, operations) {
562
513
  var _a;
@@ -594,127 +545,129 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
594
545
  core_1.Logger.error('Error details: ' + JSON.stringify((_a = e.body) === null || _a === void 0 ? void 0 : _a.error, null, 2), constants_1.loggerCtx);
595
546
  }
596
547
  }
597
- createVariantIndexItem(v, channelId, languageCode) {
598
- const productAsset = v.product.featuredAsset;
599
- const variantAsset = v.featuredAsset;
600
- const productTranslation = this.getTranslation(v.product, languageCode);
601
- const variantTranslation = this.getTranslation(v, languageCode);
602
- const collectionTranslations = v.collections.map(c => this.getTranslation(c, languageCode));
603
- const item = {
604
- channelId,
605
- languageCode,
606
- productVariantId: v.id,
607
- sku: v.sku,
608
- slug: productTranslation.slug,
609
- productId: v.product.id,
610
- productName: productTranslation.name,
611
- productAssetId: productAsset ? productAsset.id : undefined,
612
- productPreview: productAsset ? productAsset.preview : '',
613
- productPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
614
- productVariantName: variantTranslation.name,
615
- productVariantAssetId: variantAsset ? variantAsset.id : undefined,
616
- productVariantPreview: variantAsset ? variantAsset.preview : '',
617
- productVariantPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
618
- price: v.price,
619
- priceWithTax: v.priceWithTax,
620
- currencyCode: v.currencyCode,
621
- description: productTranslation.description,
622
- facetIds: this.getFacetIds([v]),
623
- channelIds: v.channels.map(c => c.id),
624
- facetValueIds: this.getFacetValueIds([v]),
625
- collectionIds: v.collections.map(c => c.id.toString()),
626
- collectionSlugs: collectionTranslations.map(c => c.slug),
627
- enabled: v.enabled && v.product.enabled,
628
- };
629
- const customMappings = Object.entries(this.options.customProductVariantMappings);
630
- for (const [name, def] of customMappings) {
631
- item[name] = def.valueFn(v, languageCode);
548
+ async createVariantIndexItem(v, variants, ctx, languageCode) {
549
+ try {
550
+ const productAsset = v.product.featuredAsset;
551
+ const variantAsset = v.featuredAsset;
552
+ const productTranslation = this.getTranslation(v.product, languageCode);
553
+ const variantTranslation = this.getTranslation(v, languageCode);
554
+ const collectionTranslations = v.collections.map(c => this.getTranslation(c, languageCode));
555
+ const productCollectionTranslations = variants.reduce((translations, variant) => [
556
+ ...translations,
557
+ ...variant.collections.map(c => this.getTranslation(c, languageCode)),
558
+ ], []);
559
+ const prices = variants.map(variant => variant.price);
560
+ const pricesWithTax = variants.map(variant => variant.priceWithTax);
561
+ const item = {
562
+ channelId: ctx.channelId,
563
+ languageCode,
564
+ productVariantId: v.id,
565
+ sku: v.sku,
566
+ slug: productTranslation.slug,
567
+ productId: v.product.id,
568
+ productName: productTranslation.name,
569
+ productAssetId: productAsset ? productAsset.id : undefined,
570
+ productPreview: productAsset ? productAsset.preview : '',
571
+ productPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
572
+ productVariantName: variantTranslation.name,
573
+ productVariantAssetId: variantAsset ? variantAsset.id : undefined,
574
+ productVariantPreview: variantAsset ? variantAsset.preview : '',
575
+ productVariantPreviewFocalPoint: variantAsset
576
+ ? variantAsset.focalPoint || undefined
577
+ : undefined,
578
+ price: v.price,
579
+ priceWithTax: v.priceWithTax,
580
+ currencyCode: v.currencyCode,
581
+ description: productTranslation.description,
582
+ facetIds: this.getFacetIds([v]),
583
+ channelIds: v.channels.map(c => c.id),
584
+ facetValueIds: this.getFacetValueIds([v]),
585
+ collectionIds: v.collections.map(c => c.id.toString()),
586
+ collectionSlugs: collectionTranslations.map(c => c.slug),
587
+ enabled: v.enabled && v.product.enabled,
588
+ productEnabled: variants.some(variant => variant.enabled) && v.product.enabled,
589
+ productPriceMin: Math.min(...prices),
590
+ productPriceMax: Math.max(...prices),
591
+ productPriceWithTaxMin: Math.min(...pricesWithTax),
592
+ productPriceWithTaxMax: Math.max(...pricesWithTax),
593
+ productFacetIds: this.getFacetIds(variants),
594
+ productFacetValueIds: this.getFacetValueIds(variants),
595
+ productCollectionIds: unique_1.unique(variants.reduce((ids, variant) => [...ids, ...variant.collections.map(c => c.id)], [])),
596
+ productCollectionSlugs: unique_1.unique(productCollectionTranslations.map(c => c.slug)),
597
+ productChannelIds: v.product.channels.map(c => c.id),
598
+ inStock: 0 < (await this.productVariantService.getSaleableStockLevel(ctx, v)),
599
+ productInStock: await this.getProductInStockValue(ctx, variants),
600
+ };
601
+ const variantCustomMappings = Object.entries(this.options.customProductVariantMappings);
602
+ for (const [name, def] of variantCustomMappings) {
603
+ item[`variant-${name}`] = def.valueFn(v, languageCode);
604
+ }
605
+ const productCustomMappings = Object.entries(this.options.customProductMappings);
606
+ for (const [name, def] of productCustomMappings) {
607
+ item[`product-${name}`] = def.valueFn(v.product, variants, languageCode);
608
+ }
609
+ return item;
632
610
  }
633
- return item;
634
- }
635
- createProductIndexItem(variants, channelId, languageCode) {
636
- const first = variants[0];
637
- const prices = variants.map(v => v.price);
638
- const pricesWithTax = variants.map(v => v.priceWithTax);
639
- const productAsset = first.product.featuredAsset;
640
- const variantAsset = variants.filter(v => v.featuredAsset).length
641
- ? variants.filter(v => v.featuredAsset)[0].featuredAsset
642
- : null;
643
- const productTranslation = this.getTranslation(first.product, languageCode);
644
- const variantTranslation = this.getTranslation(first, languageCode);
645
- const collectionTranslations = variants.reduce((translations, variant) => [
646
- ...translations,
647
- ...variant.collections.map(c => this.getTranslation(c, languageCode)),
648
- ], []);
649
- const item = {
650
- channelId,
651
- languageCode,
652
- sku: first.sku,
653
- slug: productTranslation.slug,
654
- productId: first.product.id,
655
- productName: productTranslation.name,
656
- productAssetId: productAsset ? productAsset.id : undefined,
657
- productPreview: productAsset ? productAsset.preview : '',
658
- productPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
659
- productVariantId: first.id,
660
- productVariantName: variantTranslation.name,
661
- productVariantAssetId: variantAsset ? variantAsset.id : undefined,
662
- productVariantPreview: variantAsset ? variantAsset.preview : '',
663
- productVariantPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
664
- priceMin: Math.min(...prices),
665
- priceMax: Math.max(...prices),
666
- priceWithTaxMin: Math.min(...pricesWithTax),
667
- priceWithTaxMax: Math.max(...pricesWithTax),
668
- currencyCode: first.currencyCode,
669
- description: productTranslation.description,
670
- facetIds: this.getFacetIds(variants),
671
- facetValueIds: this.getFacetValueIds(variants),
672
- collectionIds: variants.reduce((ids, v) => [...ids, ...v.collections.map(c => c.id)], []),
673
- collectionSlugs: collectionTranslations.map(c => c.slug),
674
- channelIds: first.product.channels.map(c => c.id),
675
- enabled: variants.some(v => v.enabled) && first.product.enabled,
676
- };
677
- const customMappings = Object.entries(this.options.customProductMappings);
678
- for (const [name, def] of customMappings) {
679
- item[name] = def.valueFn(variants[0].product, variants, languageCode);
611
+ catch (err) {
612
+ core_1.Logger.error(err.toString());
613
+ throw Error(`Error while reindexing!`);
680
614
  }
681
- return item;
615
+ }
616
+ async getProductInStockValue(ctx, variants) {
617
+ const stockLevels = await Promise.all(variants.map(variant => this.productVariantService.getSaleableStockLevel(ctx, variant)));
618
+ return stockLevels.some(stockLevel => 0 < stockLevel);
682
619
  }
683
620
  /**
684
621
  * If a Product has no variants, we create a synthetic variant for the purposes
685
622
  * of making that product visible via the search query.
686
623
  */
687
- createSyntheticProductIndexItem(ctx, product, languageCode) {
688
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
689
- const productTranslation = this.getTranslation(product, ctx.languageCode);
690
- return {
624
+ createSyntheticProductIndexItem(product, ctx, languageCode) {
625
+ var _a, _b, _c, _d, _e, _f, _g, _h;
626
+ const productTranslation = this.getTranslation(product, languageCode);
627
+ const productAsset = product.featuredAsset;
628
+ const item = {
691
629
  channelId: ctx.channelId,
692
630
  languageCode,
631
+ productVariantId: 0,
693
632
  sku: '',
694
633
  slug: productTranslation.slug,
695
634
  productId: product.id,
696
635
  productName: productTranslation.name,
697
- productAssetId: (_b = (_a = product.featuredAsset) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : undefined,
698
- productPreview: (_d = (_c = product.featuredAsset) === null || _c === void 0 ? void 0 : _c.preview) !== null && _d !== void 0 ? _d : '',
699
- productPreviewFocalPoint: (_f = (_e = product.featuredAsset) === null || _e === void 0 ? void 0 : _e.focalPoint) !== null && _f !== void 0 ? _f : undefined,
700
- productVariantId: 0,
636
+ productAssetId: productAsset ? productAsset.id : undefined,
637
+ productPreview: productAsset ? productAsset.preview : '',
638
+ productPreviewFocalPoint: productAsset ? productAsset.focalPoint || undefined : undefined,
701
639
  productVariantName: productTranslation.name,
702
640
  productVariantAssetId: undefined,
703
641
  productVariantPreview: '',
704
642
  productVariantPreviewFocalPoint: undefined,
705
- priceMin: 0,
706
- priceMax: 0,
707
- priceWithTaxMin: 0,
708
- priceWithTaxMax: 0,
643
+ price: 0,
644
+ priceWithTax: 0,
709
645
  currencyCode: ctx.channel.currencyCode,
710
646
  description: productTranslation.description,
711
- facetIds: (_h = (_g = product.facetValues) === null || _g === void 0 ? void 0 : _g.map(fv => fv.facet.id.toString())) !== null && _h !== void 0 ? _h : [],
712
- facetValueIds: (_k = (_j = product.facetValues) === null || _j === void 0 ? void 0 : _j.map(fv => fv.id.toString())) !== null && _k !== void 0 ? _k : [],
647
+ facetIds: (_b = (_a = product.facetValues) === null || _a === void 0 ? void 0 : _a.map(fv => fv.facet.id.toString())) !== null && _b !== void 0 ? _b : [],
648
+ channelIds: [ctx.channelId],
649
+ facetValueIds: (_d = (_c = product.facetValues) === null || _c === void 0 ? void 0 : _c.map(fv => fv.id.toString())) !== null && _d !== void 0 ? _d : [],
713
650
  collectionIds: [],
714
651
  collectionSlugs: [],
715
- channelIds: [ctx.channelId],
716
652
  enabled: false,
653
+ productEnabled: false,
654
+ productPriceMin: 0,
655
+ productPriceMax: 0,
656
+ productPriceWithTaxMin: 0,
657
+ productPriceWithTaxMax: 0,
658
+ productFacetIds: (_f = (_e = product.facetValues) === null || _e === void 0 ? void 0 : _e.map(fv => fv.facet.id.toString())) !== null && _f !== void 0 ? _f : [],
659
+ productFacetValueIds: (_h = (_g = product.facetValues) === null || _g === void 0 ? void 0 : _g.map(fv => fv.id.toString())) !== null && _h !== void 0 ? _h : [],
660
+ productCollectionIds: [],
661
+ productCollectionSlugs: [],
662
+ productChannelIds: product.channels.map(c => c.id),
663
+ inStock: false,
664
+ productInStock: false,
717
665
  };
666
+ const productCustomMappings = Object.entries(this.options.customProductMappings);
667
+ for (const [name, def] of productCustomMappings) {
668
+ item[`product-${name}`] = def.valueFn(product, [], languageCode);
669
+ }
670
+ return item;
718
671
  }
719
672
  getTranslation(translatable, languageCode) {
720
673
  return (translatable.translations.find(t => t.languageCode === languageCode) ||
@@ -733,15 +686,17 @@ let ElasticsearchIndexerController = class ElasticsearchIndexerController {
733
686
  const productFacetValueIds = variants[0].product.facetValues.map(facetValueIds);
734
687
  return unique_1.unique([...variantFacetValueIds, ...productFacetValueIds]);
735
688
  }
736
- getId(entityId, channelId, languageCode) {
689
+ static getId(entityId, channelId, languageCode) {
737
690
  return `${channelId.toString()}_${entityId.toString()}_${languageCode}`;
738
691
  }
739
692
  };
740
- ElasticsearchIndexerController = __decorate([
693
+ ElasticsearchIndexerController = ElasticsearchIndexerController_1 = __decorate([
741
694
  common_1.Injectable(),
742
695
  __param(1, common_1.Inject(constants_1.ELASTIC_SEARCH_OPTIONS)),
743
- __metadata("design:paramtypes", [core_1.TransactionalConnection, Object, core_1.ProductVariantService,
744
- core_1.ConfigService])
696
+ __metadata("design:paramtypes", [core_1.TransactionalConnection, Object, core_1.ProductPriceApplicator,
697
+ core_1.ConfigService,
698
+ core_1.ProductVariantService,
699
+ core_1.RequestContextCacheService])
745
700
  ], ElasticsearchIndexerController);
746
701
  exports.ElasticsearchIndexerController = ElasticsearchIndexerController;
747
702
  //# sourceMappingURL=indexer.controller.js.map