smartstruct
smartstruct copied to clipboard
Map objectId to object
Question: How to realize this kind of mapping?
class Target {
final String text1;
final Sourse2 source2;
Target(this.text1, this.source2);
}
class Source {
final String text1;
final int source2Id;
Source(this.text1);
}
class Source2 {
final int id;
final String text2;
Source2(this.text2);
}
"Multiple sources" example is close to that, but not exactly.
Hi, I'm not sure I understood correctly, but if you want to map your Source2 into the Target, you can achieve this by adding an explicit Function Mapping like this.
@Mapper()
abstract class TargetMapper {
@Mapping(target: 'source2', source: mapSource2)
Target fromSource(Source source, Source2 source2);
}
Source2 mapSource2(Source source, Source2 source2) => source2;
Would generate this mapper.
class TargetMapperImpl extends TargetMapper {
TargetMapperImpl() : super();
@override
Target fromSource(Source source, Source2 source2) {
final target = Target(source.text1, mapSource2(source, source2));
return target;
}
}
Hi, yes but no :) I tried this solution before posting the issue, but faced with some problems. Here is the more precise example:
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:smartstruct/smartstruct.dart';
part 'test_mapper.freezed.dart';
part 'test_mapper.mapper.g.dart';
@freezed
class UserModel with _$UserModel {
const factory UserModel({
required int id,
required int companyId, // we have id only in source
required String name,
}) = _UserModel;
const UserModel._();
}
@freezed
class User with _$User {
const factory User({
required int id,
required Company company, // we need entity in target
required String name,
}) = _User;
const User._();
}
@freezed
class Company with _$Company {
const factory Company({
required int id,
required String name,
}) = _Company;
const Company._();
}
@Mapper()
abstract class UserMapper {
@Mapping(target: 'company', source: _mapCompany)
User fromModel(UserModel model, Company company);
}
Company _mapCompany(UserModel _, Company company) => company;
Error: Mapper got case insensitive fields and contains fields: id and id. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.
This is because of UserModel and Company both have identical fields names "id" (and "name").
Test to reproduce:
part of 'mapper_test_input.dart';
class ObjectTarget {
final String text;
final num number;
final AnotherSource another;
ObjectTarget(this.text, this.number, this.another);
}
class ObjectSource {
final String text;
final num number;
final num anotherNumber;
ObjectSource(this.text, this.number, this.anotherNumber);
}
class AnotherSource {
final String text;
final num number;
AnotherSource(this.text, this.number);
}
@Mapper()
@ShouldGenerate(r'''
class ObjectMapperImpl extends ObjectMapper {
ObjectMapperImpl() : super();
@override
ObjectTarget fromSource(ObjectSource source, AnotherSource another) {
final objecttarget = ObjectTarget(
source.text, source.number, _mapAnother(source, another));
return objecttarget;
}
}
''')
abstract class ObjectMapper {
@Mapping(target: 'another', source: _mapAnother)
ObjectTarget fromSource(ObjectSource source, AnotherSource another);
}
AnotherSource _mapAnother(ObjectSource source, AnotherSource another) =>
another;
Yes, that's a usecase I didn't think about.
Right now I can ignore certain fields, but not by their source param. So one solution would be to be able to ignore a field by it's source param, such as.
class IdSource {
final num id;
IdSource(this.id);
}
class IdTarget1 {
final num id;
IdTarget1(this.id);
}
class IdTarget2 {
final num id;
IdTarget2(this.id);
}
@Mapper()
abstract class IdMapper {
@Mapping(target: 'idTarget2.id', ignore: true)
IdSource fromTarget(IdTarget1 idTarget1, IdTarget2 idTarget2);
}
This way it would only map the id of IdTarget1. Unfortunately this is not possible at the moment.