javascriptnode.jstypescripttypeormtypegraphql

Get the child type from the parent in typeorm


I have a typeorm entity that uses single table inheritance:

@Entity()
@TableInheritance({ column: { type: "varchar", name: "type" } })
@ObjectType({ isAbstract: false })
export class OrganisationEntity extends BaseEntity {
  @Field()
  @Column()
  name: string;

  @Field(() => [UserEntity])
  @OneToMany(() => UserEntity, (user) => user.organisation)
  users: UserEntity[];
}

and some child entities:

@ChildEntity()
@ObjectType()
class MedicalOrganisation {

}

@ChildEntity()
@ObjectType()
class SoftwareOrganisation {

}

@ChildEntity()
@ObjectType()
class MedicalOrganisation {

}

I'm wondering how I can get the type and the child properties from the parent organisation so that I can do something like:

const organisation = await OrganisationEntity.findOne()
if(organisation.type === "medicalOrganisation"){
...
}

But it seems I'm not allowed to access the type property through the parent. Does anyone know how this can be done?

I'd prefer not to use instanceof because it requires the child entities and is causing circular dependencies.


Solution

  • You've got two options. Either use .createQueryBuilder and get the item using getRawOne and the returned object would contain a field named OrganisationEntity_type which can be used to do the checks. It's value would either be 'MedicalOrganisation', or 'SoftwareOrganisation' and so on.

    const orgRepository: Repository<OrganisationEntity> = getRepository(OrganisationEntity);
    let organisation = await orgRepository.createQueryBuilder().getRawOne();
    
    // organisation = {
    //   OrganisationEntity_name: 'name',
    //   OrganisationEntity_users: [
    //     {},
    //     {}
    //   ],
    //   OrganisationEntity_type: 'MedicalOrganisation'
    // }
    

    Or, you could add the field type in the OrganisationEntity itself like this:

    @Entity()
    @TableInheritance({ column: { type: "varchar", name: "type" } })
    @ObjectType({ isAbstract: false })
    export class OrganisationEntity extends BaseEntity {
      @Field()
      @Column()
      name: string;
    
      @Field(() => [UserEntity])
      @OneToMany(() => UserEntity, (user) => user.organisation)
      users: UserEntity[];
    
      @Column
      type: string;
    }
    

    and do a straightforward:

    let organisation = await OrganisationEntity.findOne();
    
    // organisation = 
    // MedicalOrganisation {
    //   name: 'name',
    //   users: [{}, {}],
    //   type: 'MedicalOrganisation'
    // }
    

    and you get the type field in the object itself.