From 46e9d886f6692788c05661d0c4800fa8022cbed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Su=C5=A1ick=C3=BD?= Date: Wed, 6 May 2020 15:26:26 +0200 Subject: [PATCH] feat: allow to use pre-condition and condition on auto mapping pairs --- package.json | 8 ++--- src/execution/type-map-plan-builder.ts | 43 +++++++----------------- test/auto-mapping-map-using.spec.ts | 42 +++++++++++++++++++++++ test/bugs/auto-map-pre-condition.spec.ts | 39 +++++++++++++++++++++ 4 files changed, 98 insertions(+), 34 deletions(-) create mode 100644 test/auto-mapping-map-using.spec.ts create mode 100644 test/bugs/auto-map-pre-condition.spec.ts diff --git a/package.json b/package.json index 2c338bc..0427d7f 100644 --- a/package.json +++ b/package.json @@ -41,13 +41,13 @@ "devDependencies": { "@types/jest": "^24.0.22", "generate-changelog": "^1.8.0", - "jest": "^24.9.0", + "jest": "^25.5.4", "rollup": "^1.26.3", - "rollup-plugin-terser": "^5.1.2", + "rollup-plugin-terser": "^5.3.0", "rollup-plugin-typescript2": "^0.24.3", - "ts-jest": "^24.1.0", + "ts-jest": "^25.5.0", "ts-node": "^8.4.1", "tslint": "^5.20.1", - "typescript": "~3.6.4" + "typescript": "~3.8.3" } } diff --git a/src/execution/type-map-plan-builder.ts b/src/execution/type-map-plan-builder.ts index 5e4fc77..b07172f 100644 --- a/src/execution/type-map-plan-builder.ts +++ b/src/execution/type-map-plan-builder.ts @@ -31,10 +31,6 @@ export class TypeMapPlanBuilder { ...this.typeMap.profile.valueTransformers ]); - const ignoredSourceMembers = this.typeMap.implicitAutoMapping ? this.getIgnoredSourceMembers() : []; - const ignoredDestinationMembers = - this.typeMap.implicitAutoMapping ? this.ignoredOrCustomResolverDestinationMembers() : []; - return (source, destination, context) => { const subtypeMap = this.typeMap.subtypeMaps.find(map => map.condition(source)); @@ -49,8 +45,19 @@ export class TypeMapPlanBuilder { if (this.typeMap.implicitAutoMapping && source) { for (const key of Object.keys(source)) { - // auto map only when both source and destination are not ignored - if (!ignoredSourceMembers.includes(key) && !ignoredDestinationMembers.includes(key)) { + const sourceMap = this.typeMap.sourceMemberConfigs.get(key); + + if (sourceMap?.isIgnored()) { + continue; + } + + const propertyMap = this.typeMap.propertyMaps.get(key); + + if (propertyMap) { + if (propertyMap.canResolveValue && !propertyMap.isResolveConfigured) { + this.tryPropertyMap(propertyMap, propertyMap.destinationMember)(source, dest, context); + } + } else { dest[key] = transformerFunc(source[key]); } } @@ -171,28 +178,4 @@ export class TypeMapPlanBuilder { return value == null ? null : value; }; } - - private getIgnoredSourceMembers(): ReadonlyArray { - const members: MemberInfo[] = []; - - this.typeMap.sourceMemberConfigs.forEach(cfg => { - if (cfg.isIgnored()) { - members.push(cfg.sourceMember); - } - }); - - return members; - } - - private ignoredOrCustomResolverDestinationMembers(): ReadonlyArray { - const members: MemberInfo[] = []; - - this.typeMap.propertyMaps.forEach(cfg => { - if (!cfg.canResolveValue || cfg.isResolveConfigured) { - members.push(cfg.destinationMember); - } - }); - - return members; - } } diff --git a/test/auto-mapping-map-using.spec.ts b/test/auto-mapping-map-using.spec.ts new file mode 100644 index 0000000..b876730 --- /dev/null +++ b/test/auto-mapping-map-using.spec.ts @@ -0,0 +1,42 @@ +import { MapperConfiguration, MappingPair } from '../src'; + +describe('Auto mapping - map using', () => { + + class SourceValue { + code: number; + } + + class Source { + value: SourceValue[]; + } + + class DestinationValue { + code: string; + } + + class Destination { + value: DestinationValue[]; + } + + const SourceToDestination = new MappingPair(Source, Destination); + const ValueMap = new MappingPair(); + + const mapper = new MapperConfiguration(cfg => { + cfg.createAutoMap(SourceToDestination, { + value: opt => opt.mapFromUsing(src => src.value, ValueMap) + }); + + cfg.createMap(ValueMap, { + code: opt => opt.mapFrom(x => x.code.toString()) + }); + }).createMapper(); + + it('should correctly handle auto map with nested pair', () => { + const source = new Source(); + source.value = [{ code: 123 }]; + + const destination = mapper.map(SourceToDestination, source); + + expect(destination.value).toEqual([{ code: '123' }]); + }); +}); diff --git a/test/bugs/auto-map-pre-condition.spec.ts b/test/bugs/auto-map-pre-condition.spec.ts new file mode 100644 index 0000000..58ffb7f --- /dev/null +++ b/test/bugs/auto-map-pre-condition.spec.ts @@ -0,0 +1,39 @@ +import { MapperConfiguration, MappingPair } from '../../src'; + +describe('Auto map with pre condition', () => { + interface Source { + id: number; + } + + interface Destination { + id: number; + } + + const SourceToDestination = new MappingPair(); + + const mapper = new MapperConfiguration(cfg => { + cfg.createAutoMap(SourceToDestination, { + id: opt => opt.preCondition(src => src.id > 2) + }); + }).createMapper(); + + it('should not map property when precondition is not met', () => { + const source: Source = { + id: 1 + }; + + const destination = mapper.map(SourceToDestination, source); + expect(destination).toEqual({}); + }); + + it('should map when precondition is met', () => { + const source: Source = { + id: 3 + }; + + const destination = mapper.map(SourceToDestination, source); + expect(destination).toEqual({ + id: 3 + }); + }); +});