Skip to main content

@Link

@Link declares a relationship from one entity to another — a to-one join, a to-many eager sub-query, or a multi-hop chain of either. See Associations for the full guide (key resolution rules, multi-hop chains, many-to-many via a join entity, filtering by association path).

function Link(options?: AssociationFieldOptions): LinkPropertyDecorator;

type LinkPropertyDecorator = PropertyDecorator & {
toOne<T>(type: TypeThunk<T>, args?: LinkArgs<T>): LinkPropertyDecorator;
toMany<T>(type: TypeThunk<T>, args?: LinkArgs<T>): LinkPropertyDecorator;
};

type LinkArgs<T> = {
sourceKey?: string; // column on *this* entity
targetKey?: keyof T; // column on the target entity
where?: object | object[];
};

Used bare, @Link() infers everything from the property's declared TypeScript type via Reflect.getMetadata('design:type', ...) reflection:

@Link({ exclusive: true })
declare readonly country?: Country;
  • If the declared type is Array, @Link() throws Can't get type information while it is an array. Please define entity type — a bare @Link() can't tell what element type an array holds; use .toMany(...) explicitly instead.
  • If the declared type is a class, @Link() requires it to already be an @Entity-registered class (throws No entity metadata found for type "..." otherwise) and calls .toOne(thatClass) for you.
  • If the property's declared type doesn't match what the association returns, @Link throws a TypeError at decoration time:
    • Link returns single instance however property type is an array
    • Link returns array of instances however property type is not an array

.toOne() / .toMany()

Call directly on the target type to be explicit about the join keys (and to declare a to-many relation, which a bare @Link() can never infer):

@(Link({ exclusive: true }).toOne(CustomerVip, {
sourceKey: 'id',
targetKey: 'customerId',
}))
declare readonly vipDetails: CustomerVip;

type can be the target class itself, or a thunk (() => Type | Promise<Type>) — useful to break circular import cycles between entity files. Note the decorator call is wrapped in parentheses (@(Link(...).toOne(...))) — required TypeScript decorator syntax whenever the decorator expression is more than a bare identifier or call.

Calling .toOne()/.toMany() again on the return value of a previous call extends the chain by one more hop (a multi-hop association) — see Associations → Multi-hop (chained) associations.

Key resolution

If sourceKey/targetKey are omitted, @sqb/connect tries, in order: an existing @ForeignKey between the two entities, then a naming convention based on the target's (to-one) or source's (to-many) single-column primary key. See Associations → Key resolution for the full convention.

where

where adds extra conditions (same syntax as a Repository filter) restricting which related rows are considered part of the relation.

Options

See AssociationFieldOptions — just the shared hidden/exclusive pair.