Skip to content

Commit

Permalink
feat: use non-nullable type converters for nullable->nullable convert
Browse files Browse the repository at this point in the history
  • Loading branch information
DevNico committed Oct 28, 2023
1 parent 696de91 commit d0f63ea
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/auto_mappr/example/lib/mappr.auto_mappr.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,66 @@ class TypeConverterBuilder extends AssignmentBuilderBase {
@override
bool canAssign() {
return assignment.typeConverters.firstWhereOrNull(
(converter) => converter.canBeUsed(
mappingSource: source,
mappingTarget: target,
),
(converter) =>
converter.canBeUsed(
mappingSource: source,
mappingTarget: target,
) ||
converter.canBeUsedNullable(
mappingSource: source,
mappingTarget: target,
),
) !=
null;
}

@override
Expression buildAssignment() {
final converter = assignment.typeConverters
// ignore: avoid-unsafe-collection-methods, checked by [canAssign]
.firstWhere((c) => c.canBeUsed(mappingSource: source, mappingTarget: target));
// ignore: avoid-unsafe-collection-methods, checked by [canAssign]
final converter = assignment.typeConverters.firstWhere(
(c) => c.canBeUsed(mappingSource: source, mappingTarget: target),
// ignore: avoid-unsafe-collection-methods, checked by [canAssign]
orElse: () => assignment.typeConverters.firstWhere(
(c) => c.canBeUsedNullable(
mappingSource: source,
mappingTarget: target,
),
),
);

// Call.
if (convertMethodArgument case final methodArgument?) {
final targetRefer = EmitterHelper.current.typeRefer(type: target);

return EmitterHelper.current
.refer(converter.converter.referCallString, converter.converter.library.identifier)
.call([methodArgument]).asA(targetRefer);
if (converter.canBeUsed(mappingSource: source, mappingTarget: target)) {
return EmitterHelper.current
.refer(
converter.converter.referCallString,
converter.converter.library.identifier,
)
.call([methodArgument]).asA(targetRefer);
}

return methodArgument.equalTo(literalNull).conditional(
literalNull,
EmitterHelper.current
.refer(
converter.converter.referCallString,
converter.converter.library.identifier,
)
.call([methodArgument.nullChecked]).asA(targetRefer),
);
}

final sourceEmitted = EmitterHelper.current.typeReferEmitted(type: source);
final targetEmitted = EmitterHelper.current.typeReferEmitted(type: target);

// Tear-off.
return EmitterHelper.current
.refer(converter.converter.referCallString, converter.converter.library.identifier)
.refer(
converter.converter.referCallString,
converter.converter.library.identifier,
)
.asA(refer('$targetEmitted Function($sourceEmitted)'));
}
}
12 changes: 12 additions & 0 deletions packages/auto_mappr/lib/src/models/type_converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ class TypeConverter extends Equatable {
_isConverterSubtype(target, mappingTarget, _ConversionRole.target);
}

bool canBeUsedNullable({
required DartType mappingSource,
required DartType mappingTarget,
}) {
if(!(mappingSource.isNullable && mappingTarget.isNullable)) return false;

return canBeUsed(
mappingSource: mappingSource.element!.library!.typeSystem.promoteToNonNull(mappingSource),
mappingTarget: mappingTarget.element!.library!.typeSystem.promoteToNonNull(mappingTarget),
);
}

bool _isConverterSubtype(DartType converterType, DartType fieldType, _ConversionRole role) {
// Same type.
if (converterType == fieldType) return true;
Expand Down
24 changes: 24 additions & 0 deletions packages/auto_mappr/test/integration/fixture/type_converters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import 'type_converters/module_alpha.dart';
MapType<PrimitivesDto, Primitives>(
converters: [TypeConverter<Object, String>(Mappr.objectToString)],
),
MapType<NullableDto, Nullable>(
converters: [
TypeConverter<int, Value<int>>(Mappr.intToValueInt),
],
),
MapType<NormalFieldDto, NormalField>(
converters: [TypeConverter<int, Value<int>>(Mappr.intToValueInt)],
),
Expand Down Expand Up @@ -57,6 +62,25 @@ class Mappr extends $Mappr {
}
}

// Nullables.

class NullableDto {
final int? alpha;
final int? beta;

const NullableDto({required this.alpha, required this.beta});
}

class Nullable with EquatableMixin {
final Value<int>? alpha;
final int? beta;

@override
List<Object?> get props => [alpha, beta];

const Nullable(this.alpha, this.beta);
}

// Primitives.

class PrimitivesDto {
Expand Down
11 changes: 11 additions & 0 deletions packages/auto_mappr/test/integration/type_converters_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ void main() {
mappr = const fixture.Mappr();
});

test('nullable', () {
const dto = fixture.NullableDto(alpha: 123456, beta: 123);
final converted =
mappr.convert<fixture.NullableDto, fixture.Nullable>(dto);

expect(
converted,
equals(const fixture.Nullable(fixture.Value(123456), 123)),
);
});

test('primitives', () {
const dto = fixture.PrimitivesDto(alpha: 123456, beta: false);
final converted = mappr.convert<fixture.PrimitivesDto, fixture.Primitives>(dto);
Expand Down

0 comments on commit d0f63ea

Please sign in to comment.