You can define an entity and its columns right in the model, using decorators. But some people prefer to define an entity and its columns inside separate files which are called "entity schemas" in TypeORM.
When using the Decorator approach it is easy to extend basic columns to an abstract class and simply extend this. For example, your id, createdAt and updatedAt columns may be defined in such a BaseEntity. For more details, see the documentation on concrete table inheritance.
When using the EntitySchema approach, this is not possible. However, you can use the Spread Operator (...) to your advantage.
Reconsider the Category example from above. You may want to extract basic column descriptions and reuse it across your other schemas. This may be done in the following way:
import { EntitySchemaColumnOptions } from"typeorm"exportconstBaseColumnSchemaPart= { id: { type: Number, primary:true, generated:true, } asEntitySchemaColumnOptions, createdAt: { name:"created_at", type:"timestamp with time zone", createDate:true, } asEntitySchemaColumnOptions, updatedAt: { name:"updated_at", type:"timestamp with time zone", updateDate:true, } asEntitySchemaColumnOptions,}
Now you can use the BaseColumnSchemaPart in your other schema models, like this:
exportconstCategoryEntity=newEntitySchema<Category>({ name:"category", columns: {...BaseColumnSchemaPart,// the CategoryEntity now has the defined id, createdAt, updatedAt columns!// in addition, the following NEW fields are defined name: { type: String, }, },})
You can use embedded entities in schema models, like this:
Add the inheritance option to the parent class schema, specifying the inheritance pattern ("STI") and the discriminator column, which will store the name of the child class on each row
Set the type: "entity-child" option for all children classes' schemas, while extending the parent class columns using the spread operator syntax described above
// schema.tsconstBaseSchema=newEntitySchema<Base>({ target: Base, name:"Base", columns: { id: { type: Number, primary:true, generated:"increment", }, type: { type: String, }, createdAt: { type: Date, createDate:true, }, updatedAt: { type: Date, updateDate:true, }, },// NEW: Inheritance options inheritance: { pattern:"STI", column:"type", },})constASchema=newEntitySchema<A>({ target:A, name:"A", type:"entity-child",// When saving instances of 'A', the "type" column will have the value// specified on the 'discriminatorValue' property discriminatorValue:"my-custom-discriminator-value-for-A", columns: {...BaseSchema.options.columns, a: { type: Boolean, }, },})constBSchema=newEntitySchema<B>({ target:B, name:"B", type:"entity-child", discriminatorValue:undefined,// Defaults to the class name (e.g. "B") columns: {...BaseSchema.options.columns, b: { type: Number, }, },})constCSchema=newEntitySchema<C>({ target:C, name:"C", type:"entity-child", discriminatorValue:"my-custom-discriminator-value-for-C", columns: {...BaseSchema.options.columns, c: { type: String, }, },})
Using Schemas to Query / Insert Data
Of course, you can use the defined schemas in your repositories or entity manager as you would use the decorators. Consider the previously defined Category example (with its Interface and CategoryEntity schema) in order to get some data or manipulate the database.
// request dataconstcategoryRepository=dataSource.getRepository<Category>(CategoryEntity)constcategory=awaitcategoryRepository.findOneBy({ id:1,}) // category is properly typed!// insert a new category into the databaseconstcategoryDTO= {// note that the ID is autogenerated; see the schema above name:"new category",}constnewCategory=awaitcategoryRepository.save(categoryDTO)