vendure-ecommerce/vendure

listQueryBuilder.build() throw `"Not unique table/alias:` error while upgrade to vendure `2.2.0-next.6`

Closed this issue ยท 9 comments

Describe the bug
While upgrade to vendure 2.2.0-next.6, typeorm 0typeorm@0.3.20

it wll throw "Not unique table/alias: if we have relation:['parent'], and parent reference this entity self

To Reproduce
Steps to reproduce the behavior:

@Entity('lens_process_option')
export class LensProcessOption extends VendureEntity implements Translatable {
  constructor(input?: DeepPartial<LensProcessOption>) {
    super(input);
  }

  @ManyToOne(() => LensProcessOption, (type) => type.parent)
  parent: LensProcessOption | null;


  @Column('int', { nullable: true })
  parentId: ID | null;

``

while we have query as below:

```ts
 findAll(
    ctx: RequestContext,
    options?: ListQueryOptions<LensProcessOption>
  ): Promise<PaginatedList<Translated<LensProcessOption>>> {
    return this.listQueryBuilder
      .build(LensProcessOption, options, { relations: ['parent'], ctx })
      .getManyAndCount()
      .then(([processOptions, totalItems]) => {
        const items = processOptions.map((processOption) =>
          translateDeep(processOption, ctx.languageCode, ['parent'])
        );
        return {
          items,
          totalItems,
        };
      });
  }

it will throw error

 code: 'ER_NONUNIQ_TABLE',
  errno: 1066,
  sqlState: '42000',
  sqlMessage: "Not unique table/alias: 'LensProcessOption'",
SELECT

	`LensProcessOption`.`parentId` AS `LensProcessOption_parentId`,
	`LensProcessOption`.`id` AS `LensProcessOption_id`,

	`LensProcessOption`.`createdAt` AS `LensProcessOption_createdAt`,
	`LensProcessOption`.`updatedAt` AS `LensProcessOption_updatedAt`,
	
	`LensProcessOption`.`parentId` AS `LensProcessOption_parentId`,
	`LensProcessOption`.`id` AS `LensProcessOption_id` 
FROM
	`lens_process_option` `LensProcessOption`
	LEFT JOIN `lens_process_option_translation` `LensProcessOption__translations` ON `LensProcessOption__translations`.`baseId` = `LensProcessOption`.`id`
	INNER JOIN `lens_process_option` `LensProcessOption` ON `LensProcessOption`.`parentId` = `LensProcessOption`.`id` 
WHERE
	`LensProcessOption`.`id` IN (

Expected behavior
A clear and concise description of what you expected to happen.

Environment (please complete the following information):

  • @vendure/core version: 2.2.0-next-6
  • Nodejs version:
  • Database (mysql/postgres etc):mysql

Additional context
Add any other context about the problem here.

https://github.com/tianyingchun/vendure-issue

checkout banch vendure_issue_2738

  1. yarn install
  2. cd dev-server
  3. yarn serve
  code: 'ER_NONUNIQ_TABLE',
  errno: 1066,
  sqlState: '42000',
  sqlMessage: "Not unique table/alias: 'Menu'",
  sql: ''
SELECT
	`Menu`.`createdAt` AS `Menu_createdAt`,
	`Menu`.`updatedAt` AS `Menu_updatedAt`,
	`Menu`.`code` AS `Menu_code`,
	`Menu`.`parentId` AS `Menu_parentId`,
	`Menu`.`id` AS `Menu_id`,
	`Menu`.`createdAt` AS `Menu_createdAt`,
	`Menu`.`updatedAt` AS `Menu_updatedAt`,
	`Menu`.`code` AS `Menu_code`,
	`Menu`.`parentId` AS `Menu_parentId`,
	`Menu`.`id` AS `Menu_id` 
FROM
	`menu` `Menu`
	INNER JOIN `menu` `Menu` ON `Menu`.`parentId` = `Menu`.`id` 
WHERE
	`Menu`.`id` IN (1,2,3)
image

@monrostar is this the issue you ran into when updating TypeORM?

Yes, it may be necessary to add a check not only for Tree but also if the relation decorator points to the same table.
I hadn't considered that such relations could be broken, too.

@monrostar is this the issue you ran into when updating TypeORM?

@michaelbromley I can do this fix today

A fix will be ready today. I found a cause

also need to considered translations

please see my latest updated repo https://github.com/tianyingchun/next-issue/tree/vendure_issue_2738
it will always throw

InternalServerError [GraphQLError]: error.entity-has-no-translation-in-language
    at new I18nError (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/i18n/i18n-error.js:21:9)
    at new InternalServerError (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/common/error/errors.js:15:9)
    at translateEntity (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/service/helpers/utils/translate-entity.js:33:15)
    at translateLeaf (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/service/helpers/utils/translate-entity.js:104:20)
    at translateDeep (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/service/helpers/utils/translate-entity.js:89:21)
    at TranslatorService.translate (/Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/node_modules/@vendure/core/dist/service/helpers/translator/translator.service.js:54:53)
    at file:///Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/packages/plugin-issue/src/services/menu.service.ts:82:76
    at Array.map (<anonymous>)
    at file:///Users/tianyingchun/Documents/coding/kzfoo/vendure-issue/packages/plugin-issue/src/services/menu.service.ts:82:37
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  path: undefined,
  locations: undefined,
  extensions: { code: 'INTERNAL_SERVER_ERROR' },
  variables: { entityName: 'Menu', languageCode: ',,en' },
  code: 'INTERNAL_SERVER_ERROR',
  logLevel: 0
}

because parent relation missed reload all translations eager

@Entity('menu')
export class Menu extends VendureEntity implements Translatable {
  constructor(input?: DeepPartial<Menu>) {
    super(input);
  }

  name: LocaleString;

  @Column({ unique: true })
  code: string;

  @ManyToOne(() => Menu, (type) => type.parent)
  parent: Menu | null;

  @Column('int', { nullable: true })
  parentId: ID | null;

  @OneToMany(() => MenuTranslation, (translation) => translation.base, {
    eager: true,
  })
  translations: Array<Translation<Menu>>;
}
@Entity('menu_translation')
export class MenuTranslation
  extends VendureEntity
  implements Translation<Menu>
{
  constructor(input?: DeepPartial<Translation<Menu>>) {
    super(input);
  }

  
  @Column('varchar')
  name: string;

  @Column('varchar')
  languageCode: LanguageCode;

  @ManyToOne(() => Menu, (base) => base.translations, {
    onDelete: 'CASCADE',
  })
  base: Relation<Menu>;
}
  findAll(
    ctx: RequestContext,
    options?: ListQueryOptions<Menu>
  ): Promise<PaginatedList<Menu>> {
    return this.listQueryBuilder
      .build(Menu, options, { relations: ['parent'], ctx })
      .getManyAndCount()
      .then(([menuItems, totalItems]) => {
        const items = menuItems.map((processOption) =>
          this.translator.translate(processOption, ctx, ['parent'])
        );
        return {
          items,
          totalItems,
        };
      });
  }

it works with minor local build , thanks @monrostar @michaelbromley