Skip to content

Commit

Permalink
fix(core): add check to only run nest map on applicable identifiers i…
Browse files Browse the repository at this point in the history
…n map member

ISSUES CLOSED: #480
  • Loading branch information
nartc committed Jul 1, 2022
1 parent 88650ad commit 262f86b
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 6 deletions.
28 changes: 22 additions & 6 deletions packages/core/src/lib/mappings/map-member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import type {
Primitive,
} from '../types';
import { MapFnClassId, TransformationType } from '../types';
import { isDateConstructor } from '../utils/is-date-constructor';
import { isPrimitiveConstructor } from '../utils/is-primitive-constructor';

export function mapMember<
TSource extends Dictionary<TSource>,
Expand All @@ -31,6 +33,12 @@ export function mapMember<
const transformationType: TransformationType =
transformationMapFn[MapFnClassId.type];
const mapFn = transformationMapFn[MapFnClassId.fn];
const shouldRunImplicitMap = !(
isPrimitiveConstructor(sourceMemberIdentifier) ||
isPrimitiveConstructor(destinationMemberIdentifier) ||
isDateConstructor(sourceMemberIdentifier) ||
isDateConstructor(destinationMemberIdentifier)
);

switch (transformationType) {
case TransformationType.MapFrom:
Expand Down Expand Up @@ -63,12 +71,7 @@ export function mapMember<
mapFn as ConditionReturn<TSource, TDestination>[MapFnClassId.fn]
)(sourceObject, destinationMemberPath);

if (
typeof value === 'object' &&
!(value instanceof Date) &&
sourceMemberIdentifier &&
destinationMemberIdentifier
) {
if (shouldRunImplicitMap && value != null) {
value = Array.isArray(value)
? mapper.mapArray(
value,
Expand Down Expand Up @@ -111,3 +114,16 @@ export function mapMember<
}
return value;
}

function isObject(

This comment has been minimized.

Copy link
@nartc

nartc Jul 1, 2022

Author Owner

unused; will remove

val: unknown,
sourceMemberIdentifier: unknown,
destinationMemberIdentifier: unknown
): boolean {
return (
typeof val === 'object' &&
!(val instanceof Date) &&
!!sourceMemberIdentifier &&
!!destinationMemberIdentifier
);
}
80 changes: 80 additions & 0 deletions packages/integration-test/src/classes/issues/480/480.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { AutoMap, classes } from '@automapper/classes';
import {
CamelCaseNamingConvention,
createMap,
createMapper,
forMember,
mapFrom,
nullSubstitution,
} from '@automapper/core';

enum Enum {
Value1 = 'Value1',
Value2 = 'Value2',
}

class Model {
@AutoMap()
data!: string;
}

class ModelDto {
@AutoMap()
dataDto!: string;
}

class Foo {
@AutoMap(() => [String])
values!: Enum[];
@AutoMap(() => Model)
model!: Model;
@AutoMap(() => [Model])
models!: Model[];
}

class Bar {
@AutoMap(() => [String])
values!: Enum[];
@AutoMap(() => ModelDto)
model!: ModelDto;
@AutoMap(() => [ModelDto])
models!: ModelDto[];
}

describe('Issue 480', () => {
const mapper = createMapper({
strategyInitializer: classes(),
namingConventions: new CamelCaseNamingConvention(),
});

it('should map properly', () => {
createMap(
mapper,
Model,
ModelDto,
forMember(
(dto) => dto.dataDto,
mapFrom((model) => model.data)
)
);
createMap(
mapper,
Foo,
Bar,
forMember((bar) => bar.values, nullSubstitution([])),
forMember((bar) => bar.model, nullSubstitution(new ModelDto())),
forMember((bar) => bar.models, nullSubstitution([]))
);

const foo = new Foo();
foo.values = [Enum.Value1];
foo.model = new Model();
foo.model.data = 'data';
foo.models = [new Model()];
foo.models[0].data = 'data in array';
const bar = mapper.map(foo, Foo, Bar);
expect(bar.values).toEqual([Enum.Value1]);
expect(bar.model).toEqual({ dataDto: 'data' });
expect(bar.models).toEqual([{ dataDto: 'data in array' }]);
});
});

0 comments on commit 262f86b

Please sign in to comment.