loedeman / AutoMapper

A convention-based object-object mapper in JavaScript, written in TypeScript. Ported from: https://github.com/AutoMapper/AutoMapper
MIT License
311 stars 36 forks source link

Error: Impossible to use asynchronous mapping using automapper.map(); use automapper.mapAsync() instead #33

Open LWB-MatJ opened 7 years ago

LWB-MatJ commented 7 years ago

Hi,

I'm getting the following error even though my mapping function is not async. I'm using the mapFrom method.

Error: Impossible to use asynchronous mapping using automapper.map(); use automapper.mapAsync() instead

I've tracked the issue down to automapper.js in the dist folder.

See below. The async property is getting set to true if there are 2 parameterNames. I'm not sure what parameterNames is, it looks like a serialization of the mapping function. There is nothing async in my mapping function.

automapperasyncissue automapperasyncissue

Can you explain to me what this is trying to achieve or a way i can avoid this issue?

thanks Mat

LWB-MatJ commented 7 years ago

I'm having trouble uploading a screenshot. It's located on line 129 in the method AutoMapperHelper.getMappingMetadataFromTransformationFunction in file dist/automapper.js

LWB-MatJ commented 7 years ago

I was using an arrow function and this throws the getFunctionParameters out of wack. I will change to using proper functions

loedeman commented 7 years ago

Hi Matt,

Could you please post your mapping code resulting in this exception? It would help investigating and/or clarifying the problem you are facing ;) ...

Cheers, Bert

LWB-MatJ commented 7 years ago

Hi Bert,

Using arrow functions it doesn't seem to be determining the number of parameters correctly see below

const mapFromNullable = (opts, field) => {
  if (opts.sourceObject[field]) return opts.sourceObject[field]
  return ''
}

const automapper = require('automapper-ts')

automapper.createMap('input', 'output')
  .forMember('outputProp', opts => mapFromNullable(opts, 'input'))
  .ignoreAllNonExisting()

console.log(automapper.map('input', 'output', { inputProp: 'Test Prop' }))

To be honest it's no big deal. I've converted it to use explicit functions like below and it's fine

function (opts) { mapFromNullable(opts, 'input') }

thanks Mat

hirikarate commented 7 years ago

I found the root of this issue. Lucky me, I was about to register the same issue with forSourceMember.

In function AutoMapperHelper.getFunctionParameters, the author intends to count the number of parameters of forMember's callback:

opts => mapFromNullable(opts, 'input')

, which in this case should be 01 (opts). However the function makes mistake and counts number of params in mapFromNullable(opts, 'input') which yields 02. I can tell that the regular expression in AutoMapperHelper.getFunctionParameters mistakes mapFromNullable(opts, 'input') (with 2 input params) for opts => mapFromNullable(opts, 'input') (with 1 input param).

In the time being, this is a working workaround:

function transformation(opts) {
  return mapFromNullable(opts, 'input');
}

automapper.createMap('input', 'output')
  .forMember('outputProp', opts => transformation(opts))
  // .forMember('outputProp', transformation) => Don't do this. Believe me 😃 
  .ignoreAllNonExisting();
gdovicak commented 7 years ago

I experienced the same issue. Moving from arrow function expressions to function expressions fixed this for me as well.

loedeman commented 7 years ago

Hi @LWB-MatJ , @hirikarate and @gdovicak ,

I am unable to reproduce your issue using TypeScript. The TypeScript compiler compiles arrow functions to plain JavaScript functions at all times. At least, that is what happens with me. A couple of questions:

  1. Are you using Typescript to write front-end code?
  2. Which compiler target are you using? Is it possible that your resulting code still has arrow functions in it?

Number two would explain why changing arrow functions to plain JavaScript functions would change behavior at your end...

I hope to hear from you soon.

Cheers, Bert

hirikarate commented 6 years ago

Actually I am using automapper-ts for NodeJS backend code and it works pretty well except this issue (kind of minor one). Here is my tsconfig: {

    "compilerOptions": {
        "target": "es2016",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false,
        "allowSyntheticDefaultImports": true
    }
}
gdovicak commented 6 years ago

I am doing the same as @hirikarate and am not using Typescript. #2 would explain the issue I am seeing.

loedeman commented 6 years ago

Hi @hirikarate and @gdovicak ,

Unfortunately, AutoMapperTS does not fully support ES2016 (yet). The workaround in this scenario is to use a classic EcmaScript 5 function (e.g. function(opts) { ... }) instead for those mapping scenarios.

Please feel free to fix the problem and file a PR, should one of you have a little bit more spare time than I currently have.

Cheers, Bert

rageycomma commented 5 years ago

This is absolutely still an issue. Particularly if you are using prettier/eslint/beautify, which will remove function(){} definitions and replace them with arrow functions.

DrJuriko commented 4 years ago

This is absolutely still an issue. Particularly if you are using prettier/eslint/beautify, which will remove function(){} definitions and replace them with arrow functions.

It is something terrible… I spent 2-3 hours to understand why Angular 7 to 9 migrated project doesn't work! Issue is still here and needs to be fixed!

nloznjakovic commented 4 years ago

Hi, I used @gonza-lito fork on my project, and also I created PR there to fix incompatibility with arrow-functions. Maybe you can check that PR to fix the issue on your side. https://github.com/gonza-lito/AutoMapper/pull/1 The main change has been done here: https://github.com/gonza-lito/AutoMapper/pull/1/files#diff-e48398614b3d36beb47c5d3ae5f42b7e

DrJuriko commented 4 years ago

The main change has been done here: https://github.com/gonza-lito/AutoMapper/pull/1/files#diff-e48398614b3d36beb47c5d3ae5f42b7e

Thank you, works fine... in readme you wrote that "Remove global scope variable", please, provide at least a minimal description for suggested usage...