Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map objectId to object #52

Open
andrew-tpz opened this issue May 20, 2022 · 4 comments
Open

Map objectId to object #52

andrew-tpz opened this issue May 20, 2022 · 4 comments

Comments

@andrew-tpz
Copy link

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.

@smotastic
Copy link
Owner

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;
  }
}

@andrew-tpz
Copy link
Author

andrew-tpz commented May 23, 2022

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").

@andrew-tpz
Copy link
Author

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;

@smotastic
Copy link
Owner

smotastic commented Jun 4, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants