Fetching products with filenames

A creative approach will be needed to fetch the filenames.

There's just one remaining step: fetch the products together with their images' filenames. Unfortunately, this cannot be achieved with the @Expose() decorator, as the class-transformer library does not support asynchronous transformations. However, there is an event listener that can be used: afterLoad(). With a suggestive name, it executes after an entity is loaded. This way, we can perform this process in the file products -> subscribers -> products.subscriber. We should just remember to add it to the providers in the ProductsModule. Below we can see its basic template.

@EventSubscriber()
export class ProductsSubscriber implements EntitySubscriberInterface<Product> {
  constructor(private readonly dataSource: DataSource) {
    dataSource.subscribers.push(this);
  }

  listenTo() {
    return Product;
  }
}

Here, we'll first create a private method that receives the id of a product and returns the filenames of its images, if the respective directory exists.

private async getImagesFilenames(id: number) {
  const { BASE, IMAGES } = FilePath.Products;
  const path = join(BASE, id.toString(), IMAGES);

  if (!(await pathExists(join(BASE_PATH, path)))) return;

  return this.storageService.getDirFilenames(path);
}

And above it, we can then use the afterLoad() event listener to create a field for these filenames when fetching products. This may not be the most ideal way, but as the @Expose() decorator has the aforementioned flaw, this may be a viable alternative.

async afterLoad(entity: Product) {
  const imagesFilenames = await this.getImagesFilenames(entity.id);
  entity[this.IMAGES_FILENAMES_KEY] = imagesFilenames;
}

private readonly IMAGES_FILENAMES_KEY = 'imagesFilenames';

With this, the main content of the module is concluded. We'll now see further improvements.

Commit - Retrieving products with images filenames

Last updated