> For the complete documentation index, see [llms.txt](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/extra-module-5-advanced-querying/filtering-and-sorting/dto-orchestration.md).

# DTO Orchestration

We'll start with the DTOs for **filtering**. A product may be filtered by <mark style="color:blue;">`name`</mark>, <mark style="color:blue;">`price`</mark> or <mark style="color:blue;">`category`</mark>. Well, filtering by <mark style="color:blue;">`name`</mark> is something very common and that may be done with different entities. Due to this, let's create a dedicated DTO for it in <mark style="color:purple;">querying</mark>/<mark style="color:purple;">dto</mark>/<mark style="color:purple;">name-filter.dto</mark>. With it, we may then create the DTO for the filter fields of an entity without the need to define the <mark style="color:blue;">`name`</mark> field every time.

```typescript
export class NameFilterDto {
  @IsOptional()
  @IsString()
  readonly name?: string;
}
```

And that's what will be done now. Let's then create the file <mark style="color:purple;">products</mark>/<mark style="color:purple;">dto</mark>/<mark style="color:purple;">querying</mark>/<mark style="color:purple;">filter-products.dto</mark>. Here, we should create the two remaining fields and extend the <mark style="color:blue;">`NameFilterDto`</mark>.

```typescript
export class FilterProductsDto extends NameFilterDto {
  @IsOptional()
  @IsCurrency()
  readonly price?: number;

  @IsOptional()
  @IsCardinal()
  readonly categoryId?: number;
}
```

Excellent! We have the fields to filter by and their respective validations. Let's then proceed to create the DTOs for **sorting**.

With sorting, there will be a difference. When filtering by <mark style="color:blue;">`name`</mark>, for example, we may pass any text we want, as we are stating what should be in the <mark style="color:blue;">`name`</mark> of the product. However, when sorting, we should use **predefined values**, as we'll sort by the product's **existing fields**.

Well, sorting involves two steps: choosing the <mark style="color:blue;">`sort`</mark> field by which the sorting will happen, and the <mark style="color:blue;">`order`</mark> method. There are only two order methods: **ascending** and **descending**. Let's then represent them in the file <mark style="color:purple;">querying</mark>/<mark style="color:purple;">dto</mark>/<mark style="color:purple;">order.dto</mark>.

```typescript
export class OrderDto {
  @IsOptional()
  @IsString()
  readonly order?: string;
}
```

As was said, here predefined values are expected. There is no sense in accepting any text in the <mark style="color:blue;">`order`</mark> field, as it should only have the values <mark style="color:blue;">ASC</mark> or <mark style="color:blue;">DESC</mark>. Due to this, this validation is not enough. Fortunately, there's an interesting way to solve this.

First, we can create a constant array with the allowed values.

```typescript
const Order = ['ASC', 'DESC'] as const;
```

After that, we can create a namesake type which is the union of these values.

```typescript
type Order = (typeof Order)[number];
```

> This [article](https://steveholgado.com/typescript-types-from-arrays/) from **Steve Holgado** (blog) better explains this syntax, as a further read.

{% hint style="info" %}
This approach of const array + literal union can also be used in place of **enums**, if desired.
{% endhint %}

After that, we just need to adjust the DTO. Here, <mark style="color:blue;">ASC</mark> is used by default if no <mark style="color:blue;">`order`</mark> is sent.

```typescript
export class OrderDto {
  @IsOptional()
  @IsIn(Order)
  readonly order?: Order = 'ASC';
}
```

{% hint style="info" %}
TypeScript can infer when the **constant** or the **type** is being used.
{% endhint %}

Now, the DTO to represent both the <mark style="color:blue;">`sort`</mark> and <mark style="color:blue;">`order`</mark> fields will be created in <mark style="color:purple;">products</mark>/<mark style="color:purple;">dto</mark>/<mark style="color:purple;">querying</mark>/<mark style="color:purple;">sort-products.dto</mark>. If no <mark style="color:blue;">`sort`</mark> field is sent, products will be sorted by <mark style="color:blue;">`name`</mark>. Every sorting process uses the fields <mark style="color:blue;">`sort`</mark> and <mark style="color:blue;">`order`</mark>, meaning, respectively, the **field** to sort by and how this field will be **ordered**. Therefore, each entity will have its own <mark style="color:blue;">`sort`</mark> field with **predefined values**.

```typescript
const Sort = ['name', 'price'] as const;
type Sort = (typeof Sort)[number];

export class SortProductsDto extends OrderDto {
  @IsOptional()
  @IsIn(Sort)
  readonly sort?: Sort = 'name';
}
```

Finally, for just a bit more of type safety, we can enforce that the <mark style="color:blue;">`Sort`</mark> array must only contain values that are fields of the <mark style="color:blue;">`Product`</mark> entity, by adding at the end:

```typescript
satisfies (keyof Product)[];
```

We now have a DTO for **filtering** and another one for **sorting**. As only a single DTO may be used, what should be done now is to create a new DTO that will be the combination of these two, together with the one for **pagination**. We can do it in the same folder, and name the file <mark style="color:purple;">query-products.dto</mark>.

```typescript
export class QueryProductsDto extends IntersectionType(
  FilterProductsDto,
  SortProductsDto,
  PaginationDto,
) {}
```

With all these DTOs in hand, we may then proceed to actually apply filtering and sorting.

<mark style="color:green;">**Commit**</mark> - Orchestrating dtos for filtering and sorting
