Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core) Add beforeMapArray and afterMapArray configs #618

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add(docs) add docs for afterMapArray configs
koenigstag committed May 4, 2024
commit 53618807a632e416934834173b7ec4e3c32b90b8
Original file line number Diff line number Diff line change
@@ -8,20 +8,40 @@ custom_edit_url: null

## Enumeration members

### beforeMap

• **beforeMap** = `0`

#### Defined in

[lib/types.ts:487](https://github.com/nartc/mapper/blob/9d18866/packages/core/src/lib/types.ts#L487)

___

### afterMap

• **afterMap** = `1`

#### Defined in

[lib/types.ts:483](https://github.com/nartc/mapper/blob/efc4cb9d/packages/core/src/lib/types.ts#L483)
[lib/types.ts:488](https://github.com/nartc/mapper/blob/9d18866/packages/core/src/lib/types.ts#L488)

___

### beforeMap
### beforeMapArray

• **beforeMap** = `0`
• **beforeMapArray** = `2`

#### Defined in

[lib/types.ts:489](https://github.com/nartc/mapper/blob/9d18866/packages/core/src/lib/types.ts#L489)

___

### afterMapArray

• **afterMapArray** = `3`

#### Defined in

[lib/types.ts:482](https://github.com/nartc/mapper/blob/efc4cb9d/packages/core/src/lib/types.ts#L482)
[lib/types.ts:490](https://github.com/nartc/mapper/blob/9d18866/packages/core/src/lib/types.ts#L490)
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
id: after-map-array
title: AfterMapArray
sidebar_label: AfterMapArray
sidebar_position: 3
---

As the name suggests, `afterMapArray()` sets up a `MapCallback` to be called **after** the mapArray operation.

## Configure on `Mapping`

Pass `afterMapArray()` in `createMap()` to sets up the `MapCallback`

```ts
createMap(
mapper,
User,
UserDto,
afterMapArray((sources, destinations) => {
// destinations.map((destination, index) => Object.assign(destination, { prop: sources[index].prop }));
})
);
```

## Configure on `mapArray()`

Pass `afterMap` in `MapOptions` when calling `mapArray()` to sets up the `MapCallback`

```ts
mapper.mapArray(user, User, UserDto, {
afterMap: (sources, destinations) => {},
});
```

:::info

- `afterMap()` on `mapArray()` has precedence over `afterMapArray` on `Mapping`
- both `afterMap()` on `mapArray()` and `afterMapArray()` on `Mapping` will be invoked with `(sourceArray, destinationArray)` parameters

:::

## Async Mapping

One of the common use-cases of `afterMapArray` is to execute some asynchronous operation. Let's assume our `Destinations` have some property whose value can only be computed from an asynchronous operation, we can leverage `mapArrayAsync()` and `afterMapArray()` for it.

```ts
createMap(
mapper,
User,
UserDto,
// 👇 We are fetching the "fullName" manually
// 👇 👇 so we need to ignore it
forMember((d) => d.fullName, ignore()),
afterMapArray(async (sources, destinations) => {
await Promise.all(
sources.map(async (source, index) => {
const fullName = await fetchFullName(source);
Object.assign(destinations[index], { fullName });
})
);
})
);

// 👇 mapArrayAsync is needed if we use the above "trick" with afterMapArray
const dto = await mapper.mapArrayAsync([user], User, UserDto);
```

:::caution

Simple asynchronous operations should be fine with this approach. However due to [Fake Async](../misc/fake-async), we should **NOT** use AutoMapper for a particular pair of models if those models require some heavy and complex asynchronous operations.

:::

## What about `postMap`?

When create the `Mapper`, we can customize the `postMap` function on the `MappingStrategy`. The differences between `postMap` and `afterMapArray` are:

- `postMap` runs after every **map** operation
- There is only one `postMap` per `Mapper`
- `postMap` runs **BEFORE** `afterMapArray`
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ mapper.map(user, User, UserDto, {
:::info

- `afterMap()` on `map()` has precedence over `Mapping`
- For `mapArray` (and its variants), `afterMap()` on `Mapping` is **ignored** because it would be bad for performance if we run `afterMap` for each and every item of the array. `afterMap()` on `mapArray()` will be invoked with `(sourceArray, destinationArray)` instead
- For `mapArray` (and its variants), `afterMap()` on `Mapping` is **ignored** because it would be bad for performance if we run `afterMap` for each and every item of the array. Use `afterMapArray()` on `Mapping` instead and it will be invoked with `(sourceArray, destinationArray)` params

:::

Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: auto-map
title: AutoMap
sidebar_label: AutoMap
sidebar_position: 3
sidebar_position: 4
---

`autoMap()` is an alternative to the the `@AutoMap()` decorator. It trivially maps a property with the **same name and type** on the `Source` and `Destination` objects.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
id: before-map-array
title: BeforeMapArray
sidebar_label: BeforeMapArray
sidebar_position: 6
---

As the name suggests, `beforeMapArray()` sets up a `MapCallback` to be called **before** the map array operation.

## Configure on `Mapping`

Pass `beforeMapArray()` in `createMap()` to sets up the `MapCallback`

```ts
createMap(
mapper,
User,
UserDto,
beforeMapArray((sources, destinations) => {})
);
```

## Configure on `mapArray()`

Pass `beforeMap` in `MapOptions` when calling `mapArray()` to sets up the `MapCallback`

```ts
mapper.mapArray([user], User, UserDto, {
beforeMap: (sources, destinations) => {},
});
```

:::info

- `beforeMapArray()` on `mapArray()` has precedence over `Mapping`
- `beforeMapArray()` on `mapArray()` will be invoked with `(sourceArray, [])` parameters

:::

## What about `preMap`?

When create the `Mapper`, we can customize the `preMap` function on the `MappingStrategy`. The differences between `preMap` and `beforeMapArray` are:

- `preMap` runs before every **map** operation
- There is only one `preMap` per `Mapper`
- `preMap` runs **AFTER** `beforeMapArray`
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: before-map
title: BeforeMap
sidebar_label: BeforeMap
sidebar_position: 4
sidebar_position: 5
---

As the name suggests, `beforeMap()` sets up a `MapCallback` to be called **before** the map operation.
@@ -33,7 +33,7 @@ mapper.map(user, User, UserDto, {
:::info

- `beforeMap()` on `map()` has precedence over `Mapping`
- For `mapArray` (and its variants), `beforeMap()` on `Mapping` is **ignored** because it would be bad for performance if we run `beforeMap` for each and every item of the array. `beforeMap()` on `mapArray()` will be invoked with `(sourceArray, [])` instead
- For `mapArray` (and its variants), `beforeMap()` on `Mapping` is **ignored** because it would be bad for performance if we run `beforeMap` for each and every item of the array. Use `beforeMapArray()` on `Mapping` instead and it will be invoked with `(sourceArray, [])` params

:::

Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: construct-using
title: ConstructUsing
sidebar_label: ConstructUsing
sidebar_position: 5
sidebar_position: 7
---

Call `constructUsing()` and pass in a `DestinationConstructor` to customize how AutoMapper should construct the `Destination` before every map operation against that `Destination`.
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: extend
title: Extend
sidebar_label: Extend
sidebar_position: 6
sidebar_position: 8
---

Call `extend()` and pass in either a `Mapping` or a pair of models to tell AutoMapper to extend the `MappingProperties` to the `Mapping` we are creating
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: for-self
title: ForSelf
sidebar_label: ForSelf
sidebar_position: 8
sidebar_position: 10
---

In previous sections, we've learned that we can have [Auto Flattening](../fundamentals/auto-flattening) with [Naming Conventions](../fundamentals/naming-convention).
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: naming-conventions
title: NamingConventions
sidebar_label: NamingConventions
sidebar_position: 9
sidebar_position: 11
---

Call `namingConventions()` and pass in a `NamingConventionInput` to customize the Mapping's [NamingConvention](../fundamentals/naming-convention)
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
id: type-converters
title: TypeConverters
sidebar_label: TypeConverters
sidebar_position: 10
sidebar_position: 12
---

## What is Type Converter?
2 changes: 2 additions & 0 deletions packages/documentations/sidebars.js
Original file line number Diff line number Diff line change
@@ -42,8 +42,10 @@ const sidebars = {
items: [
'mapping-configuration/overview',
'mapping-configuration/after-map',
'mapping-configuration/after-map-array',
'mapping-configuration/auto-map',
'mapping-configuration/before-map',
'mapping-configuration/before-map-array',
'mapping-configuration/construct-using',
'mapping-configuration/extend',
{