Open LennartH opened 2 years ago
What about making AutoMap
accepts additional information like:
// š this needs better naming
@AutoMap({ type: () => [String], flattenSourcePath: ['foos', 'id']})
fooIds: string[] // it doesn't matter how this is named.
Sounds good! Much better than some fragile internal magic :sweat_smile:
A few thoughts:
foos.id
(I'd prefer this because it looks cleaner imho)Record<TSource, string | string[]>
in case the type is destination of multiple source types with different paths (feels like an edge case, but who knows)forMember
for better tool support and easier refactorings?sourcePath
or mapFrom
, since it looks like a shortcut of the mapFrom
configuration function.One minor question, is there a semantic difference between () => [String]
and () => String
or is it just an option to visually differentiate between array and non-array properties?
@AutoMap({type: () => [String], sourcePath: (source) => source.foos.id })
. There's no way to infer source
is a Foo[]
. Also it is awkward for array type with Selector function as you can seeYes. [String]
lets AutoMapper
knows that a type is an Array type. This doesn't affect much except for typeConverter()
(afaik xD)
function AutoMapper(config) {
if (config.flattenSourcePath && typeof config.flattenSourcePath === 'string') {
config.flattenSourcePath = config.flattenSourcePath.split('.');
}
// The remaining code can use config.flattenSourcePath as string[]
}
For example if two types have a property with different names (for whatever reasons) that are mapped to the same destination id array:
class Foo {
@AutoMap()
id: string;
@AutoMap()
name: string;
}
class Bar {
@AutoMap(() => [Foo])
foos: Foo[];
}
class BarVariant {
@AutoMap(() => [Foo])
specialFoos: Foo[];
}
class FlattenedBar {
@AutoMap({
type: () => [String],
flattenSourcePath: {
[Bar.name]: ['foos', 'id'],
[BarVariant.name]: ['specialFoos', 'id'],
}
})
fooIds: string[];
}
(source: Bar) => source.foo.id
to catch renaming of foo
or id
. Otherwise the mapping breaks, since there's no way to type check the provided path.I see :smile: Is this also considered by convertUsing
so a custom converter function A -> B
can also be used to map arrays?
Yeah, the "refactor-able" makes sense to me. I'll think about it.
This won't work for applications that use "mangle" when obfuscating/minimizing code for production. We might be able to make it work with Tuple instead:
@AutoMap({ type: () => [String], flattenSourcePath: [[Bar, ['foos', 'id']], [BarVariant, ['specialFoos', 'id']]]})
However, I think this gets into the weed where AutoMapper might not be a good fit if you have complex models like this.
I was thinking a bit more about my third point and I don't think it's reasonable to handle this case in the AutoMap-Config. Most of the time there will be one "main relation" between two models. The flattening for these models can be derived from the flattening path in the config and any other special cases can be handled by overriding the default behaviour with a mapFrom
modifier.
If you haven't started working on this I could try to create a PR for this. If you give me a pointer to how property selector functions work in decorators, I could also try to add support for this.
Thanks @LennartH for the offer!! You can start here: https://github.com/nartc/mapper/blob/main/packages/core/src/lib/mapping-configurations/for-member.ts#L31 to see how a Selector
is turned into a string[]
. Although, I would still think Selector
with Array seems weird because we cannot do: s => s.foos.id
I wanted to get started on this, but when running npm install
I get the error Invalid package name "@automapper/classes/mapped-types": name can only contain URL-friendly characters.
. I'm using node version 14.19.1 and npm version 8.7.0. It seems that the second slash is not allowed. Are there any restrictions/recommendations for the node and npm version? I couldn't see any in the Contributing Guide.
@LennartH I'm using npm v6 still. I'd love to change to pnpm
but I need patch-package
at the moment :(
Is your feature request related to a problem? Please describe.
I'd like to use the auto flattening features for array properties. I tried a datastructure like this:
When mapping the following object the resulting
foosId
property is 'undefined`:The property mapping is found since the names match the used
CamelCaseNamingConvention
, but whenmapInitializedValue
is resolved theget
function doesn't check thatsource['foos']
returns an array sofoos['id'] results in
undefined`.I also checked the following data structures to verify that flattening for simple cases works as expected:
Describe the solution you'd like
I'd like to be able to use auto flattening when mapping an array property to another array property. The perfect solution would allow for slight variations in source and destination property names (e.g.
foos
tofooIds
instead offoosId
). Covering all plural edge cases seems unfeasible, but removing/adding a trailings
when the source/destination property is an array and the default name isn't in source could cover most of the use cases.Describe alternatives you've considered
My current workaround is to use
convertUsing
:Another workaround is
mapFrom
:Additional context
No response