From 857b4249a6a9749cdea15192669ccc4581755873 Mon Sep 17 00:00:00 2001 From: Petr Nymsa Date: Wed, 13 Dec 2023 19:09:00 +0100 Subject: [PATCH] Support zero argument function in custom mapping --- examples/injectable/lib/getit.config.dart | 2 +- packages/auto_mappr/README.md | 9 +++-- .../example/lib/mappr.auto_mappr.dart | 33 +++++++++++++++++++ packages/auto_mappr/example/lib/mappr.dart | 30 ++++++++++++++++- .../src/extensions/dart_object_extension.dart | 2 +- .../test/integration/custom_mapping_test.dart | 11 ++++--- .../integration/fixture/custom_mapping.dart | 6 ++++ 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/examples/injectable/lib/getit.config.dart b/examples/injectable/lib/getit.config.dart index bd6ea92c..a69a1ac7 100644 --- a/examples/injectable/lib/getit.config.dart +++ b/examples/injectable/lib/getit.config.dart @@ -14,7 +14,7 @@ import 'package:get_it/get_it.dart' as _i1; import 'package:injectable/injectable.dart' as _i2; extension GetItInjectableX on _i1.GetIt { -// initializes the registration of main-scope dependencies inside of GetIt + // initializes the registration of main-scope dependencies inside of GetIt _i1.GetIt init({ String? environment, _i2.EnvironmentFilter? environmentFilter, diff --git a/packages/auto_mappr/README.md b/packages/auto_mappr/README.md index dda69134..b95194ee 100644 --- a/packages/auto_mappr/README.md +++ b/packages/auto_mappr/README.md @@ -280,9 +280,11 @@ class Mappr extends $Mappr {} When you need to assign a custom function or a const value as a value for given target field, you can use the `custom` argument in a `Field` mapping. Alternatively, you can use the `Field.custom()` constructor -which hides other then-invalid parameters. +which hides other then-invalid parameters. Provide `const Target` value or custom mapping function. -You can set up `Target Function(Source dto)` function or `const Target` value. +Custom function has to follow one of these formals: +- has `Source` model argument - `Target Function(Source dto)` +- has exactly zero arguments and returns `Target` ```dart @AutoMappr([ @@ -298,7 +300,8 @@ class Mappr extends $Mappr { static String mapName(UserDto dto) => dto.name.toUpperCase(); } -int mapAge(UserDto _) => 42; +/// Return always 42 +int mapAge() => 42; ``` ### Ignore mapping diff --git a/packages/auto_mappr/example/lib/mappr.auto_mappr.dart b/packages/auto_mappr/example/lib/mappr.auto_mappr.dart index ab771404..586a8e9a 100644 --- a/packages/auto_mappr/example/lib/mappr.auto_mappr.dart +++ b/packages/auto_mappr/example/lib/mappr.auto_mappr.dart @@ -14,6 +14,7 @@ import 'mappr.dart' as _i2; /// {@template asset:auto_mappr/example/lib/mappr.dart} /// Available mappings: /// - `UserDto` → `User`. +/// - `UserDto` → `AnotherUser`. /// {@endtemplate} class $Mappr implements _i1.AutoMapprInterface { const $Mappr(); @@ -33,6 +34,12 @@ class $Mappr implements _i1.AutoMapprInterface { targetTypeOf == _typeOf<_i2.User?>())) { return true; } + if ((sourceTypeOf == _typeOf<_i2.UserDto>() || + sourceTypeOf == _typeOf<_i2.UserDto?>()) && + (targetTypeOf == _typeOf<_i2.AnotherUser>() || + targetTypeOf == _typeOf<_i2.AnotherUser?>())) { + return true; + } if (recursive) { for (final mappr in _delegates) { if (mappr.canConvert()) { @@ -199,6 +206,16 @@ class $Mappr implements _i1.AutoMapprInterface { } return (_map__i2$UserDto_To__i2$User((model as _i2.UserDto?)) as TARGET); } + if ((sourceTypeOf == _typeOf<_i2.UserDto>() || + sourceTypeOf == _typeOf<_i2.UserDto?>()) && + (targetTypeOf == _typeOf<_i2.AnotherUser>() || + targetTypeOf == _typeOf<_i2.AnotherUser?>())) { + if (canReturnNull && model == null) { + return null; + } + return (_map__i2$UserDto_To__i2$AnotherUser((model as _i2.UserDto?)) + as TARGET); + } throw Exception('No ${model.runtimeType} -> $targetTypeOf mapping.'); } @@ -212,6 +229,22 @@ class $Mappr implements _i1.AutoMapprInterface { return _i2.User( id: model.id, name: model.xname, + born: _i2.Utils.mapDateTime(), + ); + } + + _i2.AnotherUser _map__i2$UserDto_To__i2$AnotherUser(_i2.UserDto? input) { + final model = input; + if (model == null) { + throw Exception( + r'Mapping UserDto → AnotherUser failed because UserDto was null, and no default value was provided. ' + r'Consider setting the whenSourceIsNull parameter on the MapType to handle null values during mapping.'); + } + return _i2.AnotherUser( + id: model.id, + name: model.xname, + born: _i2.Utils.mapDateTime(), + special: _i2.Utils.mapSpecial(model), ); } } diff --git a/packages/auto_mappr/example/lib/mappr.dart b/packages/auto_mappr/example/lib/mappr.dart index e6c5fd84..47386850 100644 --- a/packages/auto_mappr/example/lib/mappr.dart +++ b/packages/auto_mappr/example/lib/mappr.dart @@ -1,11 +1,23 @@ import 'package:auto_mappr_annotation/auto_mappr_annotation.dart'; - import 'package:auto_mappr_example/mappr.auto_mappr.dart'; +class Utils { + static DateTime mapDateTime() { + return DateTime.now(); + } + + static String? mapSpecial(UserDto model) => '${model.xname}?!'; +} + @AutoMappr([ MapType( + fields: [Field('name', from: 'xname'), Field('born', custom: Utils.mapDateTime)], + ), + MapType( fields: [ Field('name', from: 'xname'), + Field('born', custom: Utils.mapDateTime), + Field('special', custom: Utils.mapSpecial) ], ), ]) @@ -14,10 +26,26 @@ class Mappr extends $Mappr {} class User { final int id; final String name; + final DateTime born; const User({ required this.id, required this.name, + required this.born, + }); +} + +class AnotherUser { + final int id; + final String name; + final DateTime born; + final String? special; + + AnotherUser({ + required this.id, + required this.name, + required this.born, + this.special, }); } diff --git a/packages/auto_mappr/lib/src/extensions/dart_object_extension.dart b/packages/auto_mappr/lib/src/extensions/dart_object_extension.dart index 4ea1550c..5d1f55c4 100644 --- a/packages/auto_mappr/lib/src/extensions/dart_object_extension.dart +++ b/packages/auto_mappr/lib/src/extensions/dart_object_extension.dart @@ -20,7 +20,7 @@ extension DartObjectExtension on DartObject { final asFunction = toFunctionValue(); if (asFunction != null) { return EmitterHelper.current.refer(asFunction.referCallString, asFunction.library.identifier).call([ - if (passModelArgument) refer('model'), + if (passModelArgument && asFunction.parameters.isNotEmpty) refer('model'), ]); } diff --git a/packages/auto_mappr/test/integration/custom_mapping_test.dart b/packages/auto_mappr/test/integration/custom_mapping_test.dart index a932ce92..950a4d29 100644 --- a/packages/auto_mappr/test/integration/custom_mapping_test.dart +++ b/packages/auto_mappr/test/integration/custom_mapping_test.dart @@ -81,19 +81,20 @@ void main() { expect( converted, equals( - const fixture.CustomFunctionFromEmpty( + fixture.CustomFunctionFromEmpty( 1.2, 2, 74.58, 'some test', true, - [null, true, 3, 8.6], - [ + const [null, true, 3, 8.6], + const [ [null, 'xx'], [true, 3, 8.6], ], - {1, 2, 3, 4, 5}, - {'one': 11, 'two': 22, 'three': 33}, + const {1, 2, 3, 4, 5}, + const {'one': 11, 'two': 22, 'three': 33}, + DateTime(2023), ), ), ); diff --git a/packages/auto_mappr/test/integration/fixture/custom_mapping.dart b/packages/auto_mappr/test/integration/fixture/custom_mapping.dart index 5c5470e4..12cdcef3 100644 --- a/packages/auto_mappr/test/integration/fixture/custom_mapping.dart +++ b/packages/auto_mappr/test/integration/fixture/custom_mapping.dart @@ -59,6 +59,7 @@ import 'custom_mapping.auto_mappr.dart'; Field.custom('listListValue', custom: Mappr.emptyToListListValue), Field.custom('setValue', custom: Mappr.emptyToSetValue), Field.custom('mapValue', custom: Mappr.emptyToMapValue), + Field.custom('dateValue', custom: Mappr.dateTimeFixed), ], ), // from value @@ -107,6 +108,8 @@ class Mappr extends $Mappr { static String convertToNameAndIdPositional(CustomFunctionPositionalDto? dto) => '${dto?.name} #${dto?.id}'; static String convertToNameAndIdNamed(CustomFunctionNamedDto? dto) => '${dto?.name} #${dto?.id}'; + + static DateTime dateTimeFixed() => DateTime(2023); } // custom type @@ -203,6 +206,7 @@ class CustomFunctionFromEmpty extends Equatable { final List> listListValue; final Set setValue; final Map mapValue; + final DateTime dateValue; @override List get props => [ @@ -215,6 +219,7 @@ class CustomFunctionFromEmpty extends Equatable { listListValue, setValue, mapValue, + dateValue, ]; const CustomFunctionFromEmpty( @@ -227,6 +232,7 @@ class CustomFunctionFromEmpty extends Equatable { this.listListValue, this.setValue, this.mapValue, + this.dateValue, ); }