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

[core] version 4.1.0 has a different behavior from 4.0.0 when using mapWith #306

Closed
micalevisk opened this issue Jun 18, 2021 · 3 comments
Closed

Comments

@micalevisk
Copy link
Contributor

micalevisk commented Jun 18, 2021

Hi! After upgrading from 4.0.0 to 4.1.0 (which introduces the feat #301) I'm facing this error:

(node:46225) UnhandledPromiseRejectionWarning: TypeError: Cannot convert object to primitive value
    at ClassProfile.someMethod (xxx/src/resources/class/class.profile.ts:151:53)
    at xxx/src/resources/class/class.profile.ts:84:20
    at getMembers (xxx/packages/core/src/lib/create-mapper/get-member-path.util.ts:12:23)
    at Object.getMemberPath (xxx/packages/core/src/lib/create-mapper/get-member-path.util.ts:37:19)
    at Object.createMapForMember (xxx/packages/core/src/lib/create-mapper/create-map-for-member.util.ts:61:18)
    at Object.forMember (xxx/packages/core/src/lib/create-mapper/create-map-fluent-function.util.ts:37:14)
    at xxx/src/resources/class/class.profile.ts:78:10
    at Object.addProfile (xxx/packages/core/src/lib/create-mapper/create-mapper.ts:45:7)
    at xxx/packages/nestjs/src/lib/abstracts/automapper-profile.abstract.ts:8:46
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

Looks like this is due to the usage of the mapWith selector.

What I've notice is that now the second arg (a callback) passed to mapWith is not lazy anymore, this is why I'm getting that error.
You can see that by following the steps bellow.

I'm not sure if that callback is expected to run only when performing the mapping tho.


You can use the test suite in your main branch

git checkout 4.0.0
npm ci
gedit packages/integration-test/src/lib/with-classes/fixtures/profiles/user-profile.profile.ts
the new content of user-profile.profile.ts
import { convertUsing, mapWith } from '@automapper/core';
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
import type { Converter, Mapper, MappingProfile } from '@automapper/types';
import { Injectable } from '@nestjs/common';
import { Avatar, AvatarVm } from '../models/avatar';
import { UserProfile, UserProfileVm } from '../models/user-profile';

export const dateToStringConverter: Converter<Date, string> = {
  convert(source: Date | string): string {
    if (typeof source === 'string') return new Date(source).toDateString();
    return source.toDateString();
  },
};

@Injectable()
export class UserProfileProfile extends AutomapperProfile {
  constructor(@InjectMapper() mapper: Mapper) {
    super(mapper);
  }

  mapProfile(): MappingProfile {
    return (mapper) => {
      mapper
        .createMap(UserProfile, UserProfileVm)
        .forMember(
          (d) => d.avatar,
          mapWith(
            () => AvatarVm,
            (s) => {
              console.log("Log from inside mapWith's second arg")
              return s.avatar;
            },
            () => Avatar
          )
        )
        .forMember(
          (d) => d.birthday,
          convertUsing(dateToStringConverter, (s) => s.birthday)
        );
    };
  }
}
gedit packages/nestjs-integration-test/src/app/profiles/user.profile.spec.ts
the new content of user.profile.spec.ts
import { classes } from '@automapper/classes';
import { CamelCaseNamingConvention, createMapper } from '@automapper/core';
import { getMapperToken } from '@automapper/nestjs';
import type { Mapper } from '@automapper/types';
import { Test } from '@nestjs/testing';
import { getUser } from '../models/get-user';
import { User, UserVm } from '../models/user';
import {
  UserProfile as UserProfileModel,
  UserProfileVm,
} from '../models/user-profile';
import { AddressProfile } from './address.profile';
import { AvatarProfile } from './avatar.profile';
import { UserProfileProfile } from './user-profile.profile';
import { UserProfile } from './user.profile';

describe('addressProfile', () => {
  let mapper: Mapper;
  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [
        {
          provide: getMapperToken(),
          useValue: createMapper({
            name: '',
            pluginInitializer: classes,
            namingConventions: new CamelCaseNamingConvention(),
          }),
        },
        AddressProfile,
        AvatarProfile,
        UserProfileProfile,
        UserProfile,
      ],
    }).compile();
    mapper = moduleRef.get<Mapper>(getMapperToken());
  });

  it('should do nothing', () => {
    const user = getUser();
  });
});
npm t nestjs-integration-test -- --testPathPattern=user.profile.spec

You should see nothing printing out. But

git checkout 4.1.0
npm ci
npm t nestjs-integration-test -- --testPathPattern=user.profile.spec

now you see the message Log from inside mapWith's second arg


My use case is pretty much this:

mine

maybe I could do this same mapping in another way...

@AliYusuf95
Copy link
Contributor

AliYusuf95 commented Jun 18, 2021

As you said @micalevisk , the behavior has changed and the selector method will be called with a proxy object as a parameter to determine the path during mapping creation.

The error happened because the parameter passed to the selector is an empty proxy object it’s usage should be limited only to return the path.

For your case I think you should use mapDefer with mapWith or mapWithArguments to execute the logic.

@micalevisk
Copy link
Contributor Author

hey @AliYusuf95 I've tried to use mapDefer with mapWith but didn't succeed :( Can you help me with this, please? You could use the following file

mapWith(
() => AvatarVm,
(s) => s.avatar,
() => Avatar

@micalevisk
Copy link
Contributor Author

nvm, I've manged to make this work using mapDefer in this way:

image

not sure if this is the best way to do this

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

No branches or pull requests

2 participants