Search code examples
javascriptnode.jstypescripttypeorm

Why TypeORM repository findOne method are returning plain objects?


I recently realised on using typeorm that when I separate my entity definition from my model class and use the respective repository some methods as findOne are returning plain objects instead of model class instances. I would like to know if this is the expected behavior or if I'm losing something on my implementation.

The following code reproduce the described circunstance:


import { EntitySchema, createConnection } from 'typeorm'

class Nameable {
  id: number
  name: string
}

const NameableSchema = new EntitySchema<Nameable>({
  name: 'nameable', 
  columns: { 
    id: { type: Number, primary: true, generated: 'increment' },
    name: { type: String }
  }
})

createConnection({
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "logbook",
  password: "logbook",
  database: "logbook",
  entities: [ NameableSchema ], 
  synchronize: true 
})
.then(databaseConnection => databaseConnection.getRepository(NameableSchema))
.then(nameableRepository => nameableRepository.findOne({ where: { id: 1 }}))
.then(findedNameable => console.log(findedNameable))

In this case, considering that I have a persisted tuple in my database which id value is equal to 1, console.log(findedNameable) is printing out the following:

{ id: 1, name: 'NameableName' }

However, I was expecting something like that:

Nameable { id: 1, name: 'NameableName' }

I have done some tests using decorators in my model class and, for what I could see, in this case, all the instances returned by the repository methods were instances from my correspondent model class. This example using decorators indeed show the expected behavior:

import { createConnection, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'

@Entity()
class Nameable {

  @PrimaryGeneratedColumn()
  id: number

  @Column()
  name: string
}

createConnection({
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "username",
  password: "password",
  database: "database",
  entities: [ Nameable ], 
  synchronize: true 
})
.then(databaseConnection => databaseConnection.getRepository(Nameable))
.then(nameableRepository => nameableRepository.findOne({ where: { id: 1 }}))
.then(findedNameable => console.log(findedNameable))

What happens is that I really would like o keep my entity definitions separated from my models, so I have not considered to use decorators to address this problem yet.

Also, I could not find anything in the documentation pointing out that having a separated entity definition would interfere in repository classes behavior.


Solution

  • It looks like when using EntitySchema definitions separated from the model classes you need to specify a target value inside the options parameter indicating the class you want to map to. Also the name value should be equal to the model class name.

    The following EntitySchema definition should make the question's code work as expected:

    const NameableSchema = new EntitySchema<Nameable>({
      name: Nameable.name, // Or 'Nameable', as you wish
      target: Nameable,
      columns: { 
        id: { type: Number, primary: true, generated: 'increment' },
        name: { type: String }
      }
    })