Skip to content

Latest commit

 

History

History
520 lines (385 loc) · 23.9 KB

decorators.md

File metadata and controls

520 lines (385 loc) · 23.9 KB
title
Decorators

Entity Definition

Some options affect how the Schema Generator works, and those are SQL only, meaning they affect only SQL drivers - whereas, mongo has no schema.

@Entity()

@Entity decorator is used to mark your model classes as entities. Do not use it for abstract base classes.

Parameter Type Optional Description
tableName string yes Override default collection/table name.
schema string yes Sets the schema name.
collection string yes Alias for tableName.
comment string yes Specify comment to table. (SQL only)
customRepository () => EntityRepository yes Set custom repository class.
discriminatorColumn string yes For Single Table Inheritance.
discriminatorMap Dictionary<string> yes For Single Table Inheritance.
discriminatorValue number | string yes For Single Table Inheritance.
forceConstructor boolean yes Enforce use of constructor when creating managed entity instances
abstract boolean yes Marks entity as abstract, such entities are inlined during discovery.
readonly boolean yes Disables change tracking - such entities are ignored during flush.
@Entity({ tableName: 'authors' })
export class Author { ... }

Entity Properties

@Property()

@Property() decorator is used to define regular entity property. All following decorators extend the @Property() decorator, so you can also use its parameters there.

Parameter Type Optional Description
fieldName string yes Override default property name (see Naming Strategy).
type string | Constructor<Type> | Type yes Explicitly specify the runtime type (see Metadata Providers and Custom Types).
customType Type yes Explicitly specify the mapped type instance for this property (see Custom Types).
onUpdate () => any yes Automatically update the property value every time entity gets updated.
persist boolean yes Set to false to define Shadow Property.
hidden boolean yes Set to true to omit the property when Serializing.
columnType string yes Specify exact database column type for Schema Generator. (SQL only)
length number yes Length/precision of database column, used for datetime/timestamp/varchar column types for Schema Generator. (SQL only)
default any yes Specify default column value for Schema Generator. (SQL only)
unique boolean yes Set column as unique for Schema Generator. (SQL only)
nullable boolean yes Set column as nullable for Schema Generator. (SQL only)
unsigned boolean yes Set column as unsigned for Schema Generator. (SQL only)
comment string yes Specify comment of column for Schema Generator. (SQL only)
version boolean yes Set to true to enable Optimistic Locking via version field. (SQL only)
concurrencyCheck boolean yes Set to true to enable Concurrency Check via concurrency fields.
customOrder string[] | number[] | boolean[] yes Specify a custom order for the column. (SQL only)

You can use property initializers as usual.

@Property({ length: 50, fieldName: 'first_name' })
name!: string;

@Property({ columnType: 'datetime', fieldName: 'born_date' })
born?: Date;

@Property({ columnType: 'tinyint' })
age?: number;

@Property({ onUpdate: () => new Date() })
updatedAt = new Date();

@Property()
registered = false;

@PrimaryKey()

@PrimaryKey() decorator is used to define entity's unique primary key identifier.

@PrimaryKey() decorator extend the @Property() decorator, so you can use all its parameters.

Every entity needs to have at least one primary key (see composite primary keys).

Note that if only one PrimaryKey is set and it's type is number it will be set to auto incremented automatically in all SQL drivers.

@PrimaryKey()
id!: number; // auto increment PK in SQL drivers

@PrimaryKey({ autoincrement: false })
id!: number; // numeric PK without auto increment

@PrimaryKey()
uuid: string = uuid.v4(); // uuid PK in SQL drivers

@PrimaryKey()
_id!: ObjectId; // ObjectId PK in mongodb driver

@SerializedPrimaryKey()

Property marked with @SerializedPrimaryKey() is virtual, it will not be persisted into the database.

For MongoDB you can define serialized primary key, which will be then used in entity serialization via JSON.stringify() (through method entity.toJSON()). You will be able to use it to manipulate with the primary key as string.

See Usage with MongoDB and Serializing.

@PrimaryKey()
_id: ObjectId;

@SerializedPrimaryKey()
id!: string;

@Enum()

@Enum() decorator extend the @Property() decorator, so you can use all its parameters.

@Enum() decorator can be used for both numeric and string enums. By default enums are considered numeric, and will be represented in the database schema as tinyint/smallint. For string enums, if you define the enum in same file, its values will be automatically sniffed.

See Defining Entities.

Parameter Type Optional Description
items number[] | string[] | () => Dictionary yes Specify enum items explicitly.
@Enum() // with ts-morph metadata provider we do not need to specify anything
enum0 = MyEnum1.VALUE_1;

@Enum(() => MyEnum1) // or @Enum({ items: () => MyEnum1 })
enum1 = MyEnum1.VALUE_1;

@Enum({ type: 'MyEnum2', nullable: true })
enum2?: MyEnum2; // MyEnum2 needs to be defined in current file (can be re-exported)

@Enum({ items: [1, 2, 3] })
enum3 = 3;

@Enum({ items: ['a', 'b', 'c'] })
enum4 = 'a';

@Formula()

@Formula() decorator can be used to map some SQL snippet to your entity. The SQL fragment can be as complex as you want and even include subselects.

See Defining Entities.

Parameter Type Optional Description
formula string | () => string no SQL fragment that will be part of the select clause.
@Formula('obj_length * obj_height * obj_width')
objectVolume?: number;

@Index() and @Unique()

Use @Index() to create an index, or @Unique() to create unique constraint. You can use those decorators both on the entity level and on property level. To create compound index, use the decorator on the entity level and provide list of property names via the properties option.

See Defining Entities.

Parameter Type Optional Description
name string yes index name
properties string | string[] yes list of properties, required when using on entity level
type string yes index type, not available for @Unique(). Use fulltext to enable support for the $fulltext operator
@Entity()
@Index({ properties: ['name', 'age'] }) // compound index, with generated name
@Index({ name: 'custom_idx_name', properties: ['name'] }) // simple index, with custom name
@Unique({ properties: ['name', 'email'] })
export class Author {

  @Property()
  @Unique()
  email!: string;

  @Index() // generated name
  @Property()
  age?: number;

  @Index({ name: 'born_index' })
  @Property()
  born?: Date;

}

@Check()

We can define check constraints via @Check() decorator. We can use it either on entity class, or on entity property. It has a required expression property, that can be either a string or a callback, that receives map of property names to column names. Note that we need to use the generic type argument if we want TypeScript suggestions for the property names.

Check constraints are currently supported only in postgres driver.

See Defining Entities.

Parameter Type Optional Description
name string yes constraint name
property string yes property name, only used when generating the constraint name
expression string | CheckCallback no constraint definition, can be a callback that gets a map of property to column names
@Entity()
// with generated name based on the table name 
@Check({ expression: 'price1 >= 0' })
// with explicit name 
@Check({ name: 'foo', expression: columns => `${columns.price1} >= 0` })
// with explicit type argument we get autocomplete on `columns` 
@Check<FooEntity>({ expression: columns => `${columns.price1} >= 0` })
export class Book {

  @PrimaryKey()
  id!: number;

  @Property()
  price1!: number;

  @Property()
  @Check({ expression: 'price2 >= 0' })
  price2!: number;

  @Property({ check: columns => `${columns.price3} >= 0` })
  price3!: number;

}

Entity Relationships

All relationship decorators have entity, cascade and eager optional parameters. If you use the default ReflectMetadataProvider, then entity parameter might be required You will be warned about it being not defined while required during discovery process if you use ReflectMetadataProvider.

You can also use type parameter instead of it - the difference being that type parameter needs to be string, while in entity parameter you can provide a reference (wrapped in a callback to overcome issues with circular dependencies) to the entity, which plays nice with refactoring features in IDEs like WebStorm.

If you explicitly provide entity as a reference, it will enable type checks for other reference parameters like inversedBy or mappedBy.

@ManyToOne()

@ManyToOne() decorator extend the @Property() decorator, so you can use all its parameters.

Many instances of the current Entity refer to One instance of the referred Entity.

See Defining Entities for more examples.

Parameter Type Optional Description
entity string | () => EntityName yes Set target entity type.
cascade Cascade[] yes Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eager boolean yes Always load the relationship.
inversedBy (string & keyof T) | (e: T) => any yes Point to the inverse side property name.
wrappedReference boolean yes Wrap the entity in Reference wrapper.
ref boolean yes Alias for wrappedReference.
primary boolean yes Use this relation as primary key.
onDelete string yes Referential integrity.
onUpdateIntegrity string yes Referential integrity.
@ManyToOne()
author1?: Author; // type taken via reflection (TsMorphMetadataProvider)

@ManyToOne(() => Author) // explicit type
author2?: Author;

@ManyToOne({ entity: () => Author, cascade: [Cascade.ALL] }) // options object
author3?: Author;

@OneToOne()

@OneToOne() decorator extend the @Property() decorator, so you can use all its parameters.

One instance of the current Entity refers to One instance of the referred Entity.

See Defining Entities for more examples, including bi-directional 1:1.

Parameter Type Optional Description
entity string | () => EntityName yes Set target entity type.
cascade Cascade[] yes Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eager boolean yes Always load the relationship.
owner boolean yes Explicitly set as owning side (same as providing inversedBy).
inversedBy (string & keyof T) | (e: T) => any yes Point to the inverse side property name.
mappedBy (string & keyof T) | (e: T) => any yes Point to the owning side property name.
wrappedReference boolean yes Wrap the entity in Reference wrapper.
ref boolean yes Alias for wrappedReference.
orphanRemoval boolean yes Remove the entity when it gets disconnected from the relationship (see Cascading).
joinColumn string yes Override default database column name on the owning side (see Naming Strategy).
primary boolean yes Use this relation as primary key.
onDelete string yes Referential integrity.
onUpdateIntegrity string yes Referential integrity.
// when none of `owner/inverseBy/mappedBy` is provided, it will be considered owning side
@OneToOne()
bestFriend1!: User;

// side with `inversedBy` is the owning one, to define inverse side use `mappedBy`
@OneToOne({ inversedBy: 'bestFriend1', orphanRemoval: true })
bestFriend2!: User;

// when defining it like this, you need to specifically mark the owning side with `owner: true`
@OneToOne(() => User, user => user.bestFriend2, { owner: true, orphanRemoval: true })
bestFriend3!: User;

@OneToMany()

@OneToMany() decorator extend the @Property() decorator, so you can use all its parameters.

One instance of the current Entity has Many instances (references) to the referred Entity.

See Defining Entities for more examples, including bi-directional 1:m.

You need to initialize the value with Collection<T> instance.

Parameter Type Optional Description
mappedBy (string & keyof T) | (e: T) => any no Point to the owning side property name.
entity string | () => EntityName yes Set target entity type.
cascade Cascade[] yes Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eager boolean yes Always load the relationship.
orphanRemoval boolean yes Remove the entity when it gets disconnected from the connection (see Cascading).
orderBy { [field: string]: QueryOrder } yes Set default ordering condition.
joinColumn string yes Override default database column name on the owning side (see Naming Strategy).
inverseJoinColumn string yes Override default database column name on the inverse side (see Naming Strategy).
@OneToMany(() => Book, book => book.author)
books1 = new Collection<Book>(this);

@OneToMany({ mappedBy: 'author', cascade: [Cascade.ALL] })
books2 = new Collection<Book>(this); // target entity type can be read via `TsMorphMetadataProvider` too

@ManyToMany()

@ManyToMany() decorator extend the @Property() decorator, so you can use all its parameters.

Many instances of the current Entity refers to Many instances of the referred Entity.

See Defining Entities for more examples, including bi-directional m:n.

You need to initialize the value with Collection<T> instance.

Parameter Type Optional Description
entity string | () => EntityName yes Set target entity type.
cascade Cascade[] yes Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eager boolean yes Always load the relationship.
owner boolean yes Explicitly set as owning side (same as providing inversedBy).
inversedBy (string & keyof T) | (e: T) => any yes Point to the inverse side property name.
mappedBy (string & keyof T) | (e: T) => any yes Point to the owning side property name.
orderBy { [field: string]: QueryOrder } yes Set default ordering condition.
fixedOrder boolean yes Force stable insertion order of items in the collection (see Collections).
fixedOrderColumn string yes Override default order column name (id).
pivotTable string yes Override default name for pivot table (see Naming Strategy).
joinColumn string yes Override default database column name on the owning side (see Naming Strategy).
inverseJoinColumn string yes Override default database column name on the inverse side (see Naming Strategy).
@ManyToMany({ entity: () => BookTag, cascade: [], fixedOrderColumn: 'order' })
tags = new Collection<BookTag>(this); // m:n with autoincrement PK

@ManyToMany(() => BookTag, undefined, { pivotTable: 'book_to_tag_unordered', orderBy: { name: QueryOrder.ASC } })
tagsUnordered = new Collection<BookTag>(this); // m:n with composite PK

Lifecycle Hooks

You can use lifecycle hooks to run some code when entity gets persisted. You can mark any of entity methods with them, you can also mark multiple methods with same hook.

All hooks support async methods with one exception - @OnInit.

@OnInit()

Fired when new instance of entity is created, either manually em.create(), or automatically when new entities are loaded from database

@OnInit is not fired when you create the entity manually via its constructor (new MyEntity())

@OnInit()
doStuffOnInit() {
  this.fullName = `${this.firstName} - ${this.lastName}`; // initialize shadow property
}

@OnLoad()

Fired when new entities are loaded from database. Unlike @InInit(), this will be fired only for fully loaded entities (not references). The method can be async.

@OnLoad()
async doStuffOnLoad() {
  // ...
}

@BeforeCreate()

Fired right before we persist the new entity into the database.

@BeforeCreate()
async doStuffBeforeCreate() {
  // ...
}

@AfterCreate()

Fired right after the new entity is created in the database and merged to identity map. Since this event entity will have reference to EntityManager and will be enabled to call wrap(entity).init() method (including all entity references and collections).

@AfterCreate()
async doStuffAfterCreate() {
  // ...
}

@BeforeUpdate()

Fired right before we update the entity in the database.

@BeforeUpdate()
async doStuffBeforeUpdate() {
  // ...
}

@AfterUpdate()

Fired right after the entity is updated in the database.

@AfterUpdate()
async doStuffAfterUpdate() {
  // ...
}

@BeforeDelete()

Fired right before we delete the record from database. It is fired only when removing entity or entity reference, not when deleting records by query.

@BeforeDelete()
async doStuffBeforeDelete() {
  // ...
}

@AfterDelete()

Fired right after the record gets deleted from database and it is unset from the identity map.

@AfterDelete()
async doStuffAfterDelete() {
  // ...
}

Event Subscriber

@Subscriber()

Used to register an event subscriber. Keep in mind that you need to make sure the file gets loaded in order to make this decorator registration work (e.g. you import that file explicitly somewhere).

@Subscriber()
export class AuthorSubscriber implements EventSubscriber<Author> {
  // ...
}