erdia icon indicating copy to clipboard operation
erdia copied to clipboard

Inclusion of ViewEntities causes build error

Open Johoseph opened this issue 1 year ago • 3 comments

Using version 3.7.0

Repro steps

  1. Add a view entity, include in entities TypeORM datasource config, e.g.
// View entity
@ViewEntity({
  name: "MyView",
  expression: `...query builder or sql expression`
})
export class MyViewEntity {
  @ViewColumn()
  column: string
  
  ...
}

// Datasource config
const appDataSource = new DataSource({
  entities: [...entities, MyViewEntity],
  ...otherConfig,
});

export default appDataSource;
  1. Run CLI build
  2. Build errors Cannot read properties of undefined (reading 'toString') - as below image

It may be far too complicated to construct an ERD based on the expression config key. Potentially the default behaviour should be to filter out Views based on the tableType property on entityMetadata?

This library is so handy otherwise!! Thank you for maintaining 🙏

Johoseph avatar May 31 '24 03:05 Johoseph

@Johoseph Have you solve this problem?

Finally, I have some room to solve this problem. I dug into this problem and then realized the reason.

The ViewColumn decorator cannot populate the default type and configuration by TypeORM.

Therefore, Erdia cannot extract database type information from the column information.

Add a type to the ViewColumn decorator; it will work fine, like this:

import { DataSource, ViewColumn, ViewEntity } from 'typeorm';
import { User } from './User';

/* istanbul ignore next */
@ViewEntity({
  materialized: true,
  expression: (dataSource: DataSource) => dataSource.createQueryBuilder().select().from(User, 'user'),
})
export class UserView {
  @ViewColumn({ type: 'integer' })
  id: number;

  @ViewColumn({ type: 'varchar', length: 64, name: 'first_name', comment: 'user firstname', charset: 'utf8mb4' })
  firstName: string;

  @ViewColumn({ type: 'varchar', length: 64, charset: 'utf8mb4' })
  lastName: string;

  @ViewColumn({ type: 'boolean', comment: 'line1\nline2\nline3' })
  isActive: boolean;

  constructor() {
    this.id = 0;
    this.firstName = '';
    this.lastName = '';
    this.isActive = false;
  }
}

Thank you for your waiting :)

imjuni avatar Jul 23 '24 07:07 imjuni

@imjuni Thank you for getting back to me! I am still using the workaround solution of commenting out view entities when generating.

As far as I am aware the type key does not exist on the ViewColumn (see below definition file from the TypeORM repo), so this solution wouldn't work. Are you using a future version of the library? https://github.com/typeorm/typeorm/blob/e7649d2746f907ff36b1efb600402dedd5f5a499/src/decorator/options/ViewColumnOptions.ts

Johoseph avatar Jul 24 '24 00:07 Johoseph

@Johoseph

ViewColumn determines its type based on another entity, so the decorator does not accept a column type. When I tried debugging TypeORM using example schemas and data sources, I found that TypeORM's entityMetadatas did not include column types. As a result, erdia raises an error because it cannot extract the column type from TypeORM's entityMetadatas. It seems that the TypeORM maintainers believe that ViewColumn does not need a column type. Therefore, erdia raises an error or handles it as an unknown type in diagrams

I am considering suggesting to the TypeORM development team to add a column type to ViewColumnOptions. However, as mentioned before, ViewColumn does not necessarily need a column type, so the suggestion is likely to be rejected. In this case, it will be marked as an unknown type. If you need to specify a column type, the only current method is to use the @ts-ignore directive to forcefully inject the type.

import { DataSource, ViewColumn, ViewEntity } from 'typeorm';
import { User } from './User';

/* istanbul ignore next */
@ViewEntity({
  materialized: true,
  expression: (dataSource: DataSource) => dataSource.createQueryBuilder().select().from(User, 'user'),
})
export class UserView {
  @ViewColumn({
    // @ts-ignore
    type: 'integer',
  })
  id: number;

  @ViewColumn({
    // @ts-ignore
    type: 'varchar',
  })
  firstName: string;

  @ViewColumn({
    // @ts-ignore
    type: 'varchar',
  })
  lastName: string;

  @ViewColumn({
    // @ts-ignore
    type: 'varchar',
  })
  isActive: boolean;

  constructor() {
    this.id = 0;
    this.firstName = '';
    this.lastName = '';
    this.isActive = false;
  }
}

imjuni avatar Jul 24 '24 03:07 imjuni

Thanks for looking into this! Happy to close with this info for now 😁

Johoseph avatar Aug 17 '24 04:08 Johoseph