Skip to main content

Relations Decorator

Relations

Resolver param decorator which returns an array of relation paths which can be passed through to the TypeORM data layer in order to join only the required relations. This works by inspecting the GraphQL info object, examining the field selection, and then comparing this with information about the return type's relations.

In addition to analyzing the field selection, this decorator also checks for any @Calculated() properties on the entity, and additionally includes relations from the relations array of the calculated metadata, if defined.

So if, for example, the query only selects the id field of an Order, then no other relations need be joined in the resulting SQL query. This can massively speed up execution time for queries which do not include many deep nested relations.

Example

@Query()
@Allow(Permission.ReadOrder)
orders(
@Ctx() ctx: RequestContext,
@Args() args: QueryOrdersArgs,
@Relations(Order) relations: RelationPaths<Order>,
): Promise<PaginatedList<Order>> {
return this.orderService.findAll(ctx, args.options || undefined, relations);
}

In the above example, given the following query:

Example

{
orders(options: { take: 10 }) {
items {
id
customer {
id
firstName
lastName
}
totalQuantity
totalWithTax
}
}
}

then the value of relations will be

['customer', 'lines'']

The 'customer' comes from the fact that the query is nesting the "customer" object, and the 'lines' is taken from the Order entity's totalQuantity property, which uses Calculated decorator and defines those relations as dependencies for deriving the calculated value.

Depth

By default, when inspecting the GraphQL query, the Relations decorator will look 3 levels deep in any nested fields. So, e.g. if the above orders query were changed to:

Example

{
orders(options: { take: 10 }) {
items {
id
lines {
productVariant {
product {
featuredAsset {
preview
}
}
}
}
}
}
}

then the relations array would include 'lines', 'lines.productVariant', & 'lines.productVariant.product' - 3 levels deep - but it would not include 'lines.productVariant.product.featuredAsset' since that exceeds the default depth. To specify a custom depth, you would use the decorator like this:

Example

@Relations({ entity: Order, depth: 2 }) relations: RelationPaths<Order>,

Omit

The omit option is used to explicitly omit certain relations from the calculated relations array. This is useful in certain cases where we know for sure that we need to run the field resolver anyway. A good example is the Collection.productVariants relation. When a GraphQL query comes in for a Collection and also requests its productVariants field, there is no point using a lookahead to eagerly join that relation, because we will throw that data away anyway when the productVariants field resolver executes, since it returns a PaginatedList query rather than a simple array.

Example

@Relations({ entity: Collection, omit: ['productVariant'] }) relations: RelationPaths<Collection>,