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 autoMap mapping configuration #538

Merged
merged 1 commit into from
Mar 10, 2023

Conversation

gabrielkim13
Copy link
Contributor

Avoid using the @AutoMap decorator by replacing it with calls to autoMap inside the profile.


Motivation

First of all, great job on @automapper! I'm familiar with using the O.G. AutoMapper on C# projects and this library has been a huge help for my "mapping" needs.

Nevertheless, I do have some minor pain points with it:

  1. Using the @AutoMap decorator on models / DTOs definitions is undesirable, especially when used in DDD(-Lite) projects, where entity definitions are supposed to be "pure", exempt from any mapping responsibilities.

  2. Although a good approach for solving the issue above, the @automapper/classes/transforme-plugin failed on me on a NestJS project in Monorepo mode; not really sure why. If it's of interest, I'm willing to submit an issue alongside a minimal repository simulating the error.

Not only that, neither can be used with constructor assignments:

class MyClass {
    constructor(public foo: string, private bar: number) {}
}

My homebrewed solution

In the end, I ended up ditching both of the solutions described above and use a local autoMap function, which is a simple wrapper over forMember:

export function autoMap<
    TSource extends { [key in TKey]: TValue },
    TDestination extends { [key in TKey]: TValue },
    TKey extends keyof TSource & keyof TDestination,
    TValue extends TSource[TKey] & TDestination[TKey]
>(prop: TKey): MappingConfiguration<TSource, TDestination> {
    return forMember(
        (dest) => dest[prop] as TValue,
        mapFrom((src) => src[prop])
    );
}

Then it can be used as:

createMap(
    mapper,
    DecoratorlessUser,
    DecoratorlessUserDto,
    autoMap('firstName'),
    autoMap('lastName'),
    forMember(
        (d) => d.fullName,
        mapFrom((s) => s.firstName + ' ' + s.lastName)
    )
);

Not really sure if it's worthy to be included on the lib. Just thought I would share my issues with it and my approach to working around them.

Avoid using the @AutoMap decorator by replacing it with calls to
autoMap inside the profile.
@sonarcloud
Copy link

sonarcloud bot commented Mar 4, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@nartc nartc merged commit 5906add into nartc:main Mar 10, 2023
@nartc
Copy link
Owner

nartc commented Mar 10, 2023

Although a good approach for solving the issue above, the @automapper/classes/transforme-plugin failed on me on a NestJS project in Monorepo mode; not really sure why. If it's of interest, I'm willing to submit an issue alongside a minimal repository simulating the error.

Please do provide the reproduce. Thank you for the PR.

Also, can you please write the doc for autoMap()?

@gabrielkim13 gabrielkim13 deleted the map-without-decorators branch March 10, 2023 16:43
@gabrielkim13
Copy link
Contributor Author

Thank you for reviewing and merging this PR @nartc!

I submitted a new PR adding the docs for autoMap(), as per your request: #539.


I tried reproducing the error from @automapper/classes/transformer-plugin in a minimal project using Nest's Monorepo mode, but everything works out as expected when using the Nest CLI. I guess I was doing something wrong the first time around 😅.

In any case, I couldn't figure out how to successfully configure the transformer plugin to run with ts-jest. Here is the minimal reproduction repo: https://github.com/gabrielkim13/automapper-transformer-plugin-nestjs-monorepo.

The transform configuration is based on their official docs: AST transformers option.

@nartc
Copy link
Owner

nartc commented Mar 10, 2023

@gabrielkim13 Looks like ts-jest requires the plugin to have name and version (for caching purposes). I added it on main but haven't tested. I'll be releasing it soon after some testing.
image

@gabrielkim13
Copy link
Contributor Author

@nartc, I got the transformer plugin working by following the instructions on https://docs.nestjs.com/openapi/cli-plugin#integration-with-ts-jest-e2e-tests.

// automapper.plugin.ts

import * as plugin from '@automapper/classes/transformer-plugin';

export const name = '@automapper/classes/transformer-plugin';
export const version = 1;

export const factory = (cs) => {
  return plugin.before({ modelFileNameSuffix: ['.dto.ts'] }, cs.program);
};
// jest.config.ts

import type { JestConfigWithTsJest } from 'ts-jest';

export default {
  // ...
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        astTransformers: {
          before: ['<rootDir>/automapper.plugin.ts'],
        },
      },
    ],
  },
} satisfies JestConfigWithTsJest;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants