vendure-ecommerce / vendure

The commerce platform with customization in its DNA.
https://www.vendure.io
Other
5.81k stars 1.03k forks source link

Big bug for vendure handle typeorm for custom fields with `relation` & `eager:true` #1873

Open tianyingchun opened 2 years ago

tianyingchun commented 2 years ago

Describe the bug If we use customFields with using relation with eager:true for productVariant and we have any other service like below

return this.listQueryBuilder
      .build(SupplierStockInTransit, options, {
        ctx,
        relations: ['supplierStock', 'supplierStock.productVariant'],
 })

To Reproduce

Please the minimal repo https://github.com/tianyingchun/vendure-issue

Installation

Preparing sample data maybe not required for this case

http://localhost:3001/admin-api

mutation {
  initializeDemo
}

Issue reproduce steps

http://localhost:3001/admin-api

{
  supplierStockInTransits(options: { skip: 0, take: 100 }) {
    items {
      id
      supplierStock {
        id
        productVariant {
          id
        }
      }
    }
  }
}

See errors

[ExceptionsHandler] Not unique table/alias: 'SuStInTr__suSt__prVaFiFrAs'
@semic/dev-server: QueryFailedError: Not unique table/alias: 'SuStInTr__suSt__prVaFiFrAs'
@semic/dev-server:     at QueryFailedError.TypeORMError [as constructor]

Analysis of above problems

  1. /custom-fields/product-variant-custom-fields.ts custom fields definitions as below with eager: true
{
    type: 'relation',
    name: 'tryonFrameAsset',
    nullable: true,
    entity: Asset,
    eager: true,
    public: true,
  },
  {
    type: 'relation',
    name: 'tryonTempleAsset',
    nullable: true,
    entity: Asset,
    eager: true,
    public: true,
  },
  ...
  1. In supplier-stock-in-transit.service.ts we attach nested relations supplierStock.productVariant

  findAll(
    ctx: RequestContext,
    options?: ListQueryOptions<SupplierStockInTransit>
  ): Promise<PaginatedList<SupplierStockInTransit>> {
    return this.listQueryBuilder
      .build(SupplierStockInTransit, options, {
        ctx,
        relations: ['supplierStock', 'supplierStock.productVariant'],
      })
      .getManyAndCount()
      .then(([items, totalItems]) => {
        return {
          items,
          totalItems,
        };
      });
  }

This issue may cause of custom Fields with nested relation with eager: true

Environment (please complete the following information):

Additional context Add any other context about the problem here.

michaelbromley commented 2 years ago

Thanks for putting in the work of creating a full reproduction! That's very, very helpful to me 👍

Initial investigation looks like it may have something to do with

and could be related to the naming strategy for shortening aliases - when shortening the alias, entity names are getting truncated any maybe this is leading to naming clashes.

michaelbromley commented 2 years ago

So I'm pretty sure I have tracked down the root cause:

There is this shorten function which is invoked if the alias name is greater than 63 chars long. The shortening algorithm it uses is creating identical aliases for multiple of the eager-loaded custom field relations. See the linked issue I just created in the TypeORM repo.

So a work-around for now is to rename your custom fields in a way that does not cause a conflict after shortening.