Coder Social home page Coder Social logo

smartstruct's Introduction

smartstruct's People

Contributors

antriadus avatar ladegeraet avatar petrnymsa avatar skykaka avatar smotastic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

smartstruct's Issues

Support lists

Lists should be mappable too.

When the sourcefield contains an iterable, we iterate through it, and map it respectively to the target field.
Primitive types will just map to itself, so we can also just create a new list with the old values in it.
Lists of nested Beans will call the mapping method, provided in the mapper class.

class NestedTarget {
  NestedTarget(this.subNested);

  final List<SubNestedTarget> subNested;
}
class NestedSource {
  NestedSource(this.subNested);

  final List<SubNestedSource> subNested;
}

@Mapper()
abstract class NestedMapper {
  @Mapping(source: 'subNestedSource', target: 'subNestedTarget')
  NestedTarget fromModel(NestedSource model);

  SubNestedTarget fromSubClassModel(SubNestedSource model);
}

Should generate something like this.

class NestedMapperImpl extends NestedMapper {
  @override
  NestedTarget fromModel(NestedSource model) {
    final nestedtarget = NestedTarget(model.subNested.map((e) => fromSubClassModel(e)).toList(););
    return nestedtarget;
  }

  @override
  SubNestedTarget fromSubClassModel(SubNestedSource model) {
    final subnestedtarget = SubNestedTarget(model.myProperty);
    return subnestedtarget;
  }
}

how to use other mapper as nested mapper

Hi and thank you for work
I have to use other mapper inside my mapper for mapping nested element of my model to entity
But currently I have to copy same method from other mapper

How to map entity to DTO and vise versa?

Let's say I have these classes:

class Product {
  final int id;
  final Money price;
}
class ProductDTO {
  final int id;
  final num price;
}
class Money {
  final num cents;
}

Is it possible to map Product to ProducMap and vise versa using your package?

Static mapping

For now we have to create mapper instance:

    final mapper = SomeMapperImpl();
    final entities = models.map(mapper.fromModel);

It would be greate to use mappers as static

    final entities = models.map(SomeMapper.fromModel);

Something like this:

@Mapper()
abstract class EntityMapper {
  static Entity fromModel(Model model) => _$EntityMapperFromModel(model);
}

Support inheritance

Will it be possible to map objects that inherit other objects?

i.e.

class BaseClass {
  BaseClass({required this.id});

  final String id;
}

class MyClass extends BaseClass {
  MyClass({required this.name, required String id}) : super(id: id);

  final String name;
}

SmartStruct issue generated with freezed

Hi. I`m using Smartstruct create mapper from UserResponse -> UserModel

Version

smartstruct: ^1.4.0
smartstruct_generator: ^1.4.0
freezed_annotation: ^2.2.0
freezed: ^2.3.2

UserResponse class

`@freezed
class UserResponse with _$UserResponse {
const factory UserResponse(
{@jsonkey(name: 'id') String? id,
@jsonkey(name: 'name') String? name,
@jsonkey(name: 'phone') String? phone,
@jsonkey(name: 'email') String? email,
@jsonkey(name: 'birthday') String? birthday,
@jsonkey(name: 'avata') String? avatar,
@jsonkey(name: 'status') String? status,
@jsonkey(name: 'gender') String? gender}) = _UserResponse;

factory UserResponse.fromJson(Map<String, dynamic> json) => _$UserResponseFromJson(json);
}
`

UserModel class

@freezed class UserModel with _$UserModel { const factory UserModel( {String? id, String? name, String? phone, String? email, String? birthday, String? avatar, String? status, String? gender}) = _UserModel; }

Finally class Mapper

`part 'user_mapper.mapper.g.dart';

@Mapper()
abstract class UserMapper {
@mapping(
target: 'copyWith',
ignore: true) // drawback as freezed generates a getter for the copyWith, and we have no way of determining that the copyWith shouldn't be mapped without explicitly ignoring it
UserModel fromModel(UserResponse model);
}
`

Build error -> Bad state: No element

I'm looking for help, is there anyone who can help me?

Mapper fails on stable version of flutter 2.10.0 & dart 2.16.0

When i upgrade the flutter version i got this error when generating mapper on version 1.2.4+1

Mapper got case insensitive fields and contains fields: box and box. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.

I tried to upgrade the package to 1.2.6 but i got this error
Because smartstruct_generator >=1.2.5 depends on path ^1.8.1 and every version of flutter_test from sdk depends on path 1.8.0, smartstruct_generator >=1.2.5 is incompatible with flutter_test from sdk. So, because app depends on both flutter_test from sdk and smartstruct_generator ^1.2.6, version solving failed.

Reusing existing mapper to avoid code duplication

Hi,
this library looks great! What about implementing the uses feature in the @Mapper annotation?

https://mapstruct.org/documentation/dev/reference/html/#_advanced_mapping_options

Using this flag, developers can reduce the code duplication to map existing objects, by plugging other mappers into the parent one.

Example

Entities

// TARGET

class ParentTarget {
  ParentTarget(this.childTarget);

  final ChildTarget childTarget;
}

class ChildTarget {
  ChildTarget(this.property);

  final String property;
}

// SOURCE

class ParentSource {
  ParentSource(this.childSource);

  final ChildSource childSource;
}

class ChildSource {
  ChildSource(this.property);

  final String property;
}

Mappers

@Mapper()
abstract class ChildMapper {
  @Mapping(source: 'childSource', target: 'childTarget')
  ChildTarget toChildTarget(ChildSource model);
}

@Mapper(uses: [ChildMapper])
abstract class ParentMapper {
  ParentTarget toParentTarget(ParentSource model);
}

The generated code should be something like down below.

class ParentMapperImpl extends ParentMapper {
  final ChildMapper childMapper;

  ParentMapperImpl({
    required this.childMapper,
  }) : super();

  ParentTarget toParentTarget(ParentSource model) {
    final parentTarget = ParentTarget(childMapper.toChildTarget(model.childSource));
    return parentTarget;
  }
}

update the package

Hi teams,

Please update the package. I am getting error below error.


D:\startup\app\demo_application
dart run build_runner build
Building package executable... (1.0s)
Built build_runner:build_runner.
[INFO] Generating build script completed, took 277ms
[WARNING] Throwing away cached asset graph because the language version of some package(s) changed. This would most commonly happen when updating dependencies or changing your min sdk constraint.
[INFO] Cleaning up outputs from previous builds. completed, took 28ms
[INFO] Generating build script completed, took 78ms
[WARNING] Invalidated precompiled build script due to missing asset graph.
[INFO] Precompiling build script... completed, took 1.1s
[INFO] Building new asset graph completed, took 1.4s
[INFO] Checking for unexpected pre-existing outputs. completed, took 0ms
[WARNING] retrofit_generator on test/widget_test.dart:
Your current `analyzer` version may not fully support your current SDK version.

Analyzer language version: 3.1.0
SDK language version: 3.4.0

Please update to the latest `analyzer` version (6.7.0) by running
`flutter packages upgrade`.

If you are not getting the latest version by running the above command, you
can try adding a constraint like the following to your pubspec to start
diagnosing why you can't get the latest version:

dev_dependencies:
  analyzer: ^6.7.0

[WARNING] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:
Bad state: No element
[WARNING] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:
#0      Iterable.first (dart:core/iterable.dart:643:7)
#1      _chooseConstructor (package:smartstruct_generator/code_builders/method_builder.dart:121:71)
#2      _generateBody (package:smartstruct_generator/code_builders/method_builder.dart:62:29)
#3      buildMapperImplementation.<anonymous closure> (package:smartstruct_generator/code_builders/method_builder.dart:26:14)
#4      _$MethodBuilder.update (package:code_builder/src/specs/method.g.dart:323:33)
#5      new _$Method (package:code_builder/src/specs/method.g.dart:38:29)
#6      buildMapperImplementation (package:smartstruct_generator/code_builders/method_builder.dart:22:10)
#7      _generateMapperImplementationClass.<anonymous closure>.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:83:15)
#8      MappedIterator.moveNext (dart:_internal/iterable.dart:403:20)
#9      List.addAll (dart:core-patch/growable_array.dart:319:13)
#10     ListBuilder.addAll (package:built_collection/src/list/list_builder.dart:98:14)
#11     _generateMapperImplementationClass.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:80:17)
#12     _$ClassBuilder.update (package:code_builder/src/specs/class.g.dart:345:33)
#13     new _$Class (package:code_builder/src/specs/class.g.dart:40:28)
#14     _generateMapperImplementationClass (package:smartstruct_generator/code_builders/class_builder.dart:73:10)
#15     buildMapperClass.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:16:11)
#16     _$LibraryBuilder.update (package:code_builder/src/specs/library.g.dart:226:33)
#17     new _$Library (package:code_builder/src/specs/library.g.dart:28:30)
#18     buildMapperClass (package:smartstruct_generator/code_builders/class_builder.dart:14:10)
#19     MapperGenerator.generateForAnnotatedElement (package:smartstruct_generator/generators/mapper_generator.dart:27:26)
#20     GeneratorForAnnotation.generate (package:source_gen/src/generator_for_annotation.dart:61:30)
#21     _generate (package:source_gen/src/builder.dart:342:33)
<asynchronous suspension>
#22     Stream.toList.<anonymous closure> (dart:async/stream.dart:1351:9)
<asynchronous suspension>
#23     _Builder._generateForLibrary (package:source_gen/src/builder.dart:107:9)
<asynchronous suspension>
#24     _Builder.build (package:source_gen/src/builder.dart:99:5)
<asynchronous suspension>
#25     runBuilder.buildForInput (package:build/src/generate/run_builder.dart:83:7)
<asynchronous suspension>
#26     Future.wait.<anonymous closure> (dart:async/future.dart:524:21)
<asynchronous suspension>
#27     scopeLogAsync.<anonymous closure> (package:build/src/builder/logging.dart:32:40)
<asynchronous suspension>

[SEVERE] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:

Bad state: No element
dart:core                                                               Iterable.first
package:smartstruct_generator/code_builders/method_builder.dart 121:71  _chooseConstructor
package:smartstruct_generator/code_builders/method_builder.dart 62:29   _generateBody
package:smartstruct_generator/code_builders/method_builder.dart 26:14   buildMapperImplementation.<fn>
package:code_builder/src/specs/method.g.dart 323:33                     _$MethodBuilder.update
package:code_builder/src/specs/method.g.dart 38:29                      new _$Method
package:smartstruct_generator/code_builders/method_builder.dart 22:10   buildMapperImplementation
package:smartstruct_generator/code_builders/class_builder.dart 83:15    _generateMapperImplementationClass.<fn>.<fn>
dart:core                                                               List.addAll
package:built_collection/src/list/list_builder.dart 98:14               ListBuilder.addAll
package:smartstruct_generator/code_builders/class_builder.dart 80:17    _generateMapperImplementationClass.<fn>
package:code_builder/src/specs/class.g.dart 345:33                      _$ClassBuilder.update
package:code_builder/src/specs/class.g.dart 40:28                       new _$Class
package:smartstruct_generator/code_builders/class_builder.dart 73:10    _generateMapperImplementationClass
package:smartstruct_generator/code_builders/class_builder.dart 16:11    buildMapperClass.<fn>
package:code_builder/src/specs/library.g.dart 226:33                    _$LibraryBuilder.update
package:code_builder/src/specs/library.g.dart 28:30                     new _$Library
package:smartstruct_generator/code_builders/class_builder.dart 14:10    buildMapperClass
package:smartstruct_generator/generators/mapper_generator.dart 27:26    MapperGenerator.generateForAnnotatedElement
package:source_gen/src/generator_for_annotation.dart 61:30              GeneratorForAnnotation.generate
package:source_gen/src/builder.dart 342:33                              _generate
dart:async                                                              Stream.toList.<fn>
package:source_gen/src/builder.dart 107:9                               _Builder._generateForLibrary
package:source_gen/src/builder.dart 99:5                                _Builder.build

[INFO] Running build completed, took 14.9s
[INFO] Caching finalized dependency graph completed, took 73ms
[SEVERE] Failed after 15.0s

Improvement custom field

Hi, this is a great package thanks for sharing. I did look at the documentation and did not see anything like...

For example, I have the class

class UserResponse { final String profile; ... }

And I have

enum UserProfile { investor, consumer }

class User {
final UserProfile profile;
...
}

How can I make the mapper to map with a custom logic for example:

profile: enumFromString<UserProfile>(
    UserProfile.values,
    response.profile,
    UserProfile.consumer,
  )

for the profile field. This is just one example there is several more like

class UserResponse {
   final String zipCode;
   final String number;
   final String street;
...
}

Map to

class User {
   final Address address;
}

Support adding smartstruct as a dev dependency

right now the annotations are in the same library as the generator, so you have to add smartstruct as a normal dependency, not as a dev dependency to be able to use it.
Maybe do something like injectable.
Where the generator and annotation are seperated from each other in 2 different libraries

Injectable Issue

Hello, I am going to apply smartstruct packages to my company projects. I am using freezed & injectable.
I want you to add a new feature for smartstruct with injectable.

This code is what I have written.

class DependencyOrder {
  static const int dataMapper = 1; // mapper
}
class DataMapper extends Injectable {
  const DataMapper({
    super.as,
    super.env,
    super.scope,
  }) : super(order: DependencyOrder.dataMapper);
abstract class Mappable<M, E> {
  M call(E entity);
}
@DataMapper(as: Mappable<User, UserRes>)
class UserMapper implements Mappable<User, UserRes> {
  @override
  User call(UserRes entity) {
    return User(
      admin: entity.admin,
      email: entity.email,
      imageUrl: entity.imageUrl.isNotEmpty ? entity.imageUrl : null,
      name: entity.name,
    );
  }
}

I want to convert my UserMapper class to same one with smart struct.

I have a problem with now version of smart struct. 1.4.0
User & UserRes class is composed of freezed.

If I apply smart struct to this code, I should change UserMapper to abstract class.
And I also would set useInjectable to true.

Then UserMapperImpl class generated by build_runner would have a @LazySingleton(as: UserMapper).

I want to custom value of as. not UserMapper but Mappable<User, UserRes>

// custom singleton or injectable or lazySingleton
@Injectable(
   as: Mappable<User, UserRes>, // custom
   order: DependencyOrder.dataMapper, // custom
)
class UserMapperImpl implements UserMapper {
  // generated code ...
}

I hope you to add this feature that custom injectable properties.

Named constructor support

Right now the first found constructor is used for populating data initially.

ConstructorElement _chooseConstructor(
    ClassElement outputClass, ClassElement _) {
  return outputClass.constructors.where((element) => !element.isFactory).first;
}

It would be nice, if in the Mapping Annotation you can define the constructor to use.

class Bar {
  final String text;
  Bar() : this.text = 'should not be used by mapper';
  Bar.useThis(this.text);
}

@Mapper()
class Mapper {
  @Mapping(constructor='useThis')
  Foo fromBar(Bar source);
}

Generated Mapper should then use the "useThis" constructor.

In the future we might use constructor tear off, right now it's not supported by dart and only in the beta.
https://github.com/dart-lang/language/blob/master/accepted/future-releases/constructor-tearoffs/feature-specification.md

Order of generation exception when using with `injectable_builder` on `build_runner: ^2.4.4`

After upgrade to Flutter 3.10, I excuted the build runner to process:

flutter pub run build_runner build --delete-conflicting-outputs

Output:

Invalid argument(s): Required input cycle for [{autoApply: AutoApply.dependents, import: package:smartstruct_generator/integrations/builder.dart, builderFactories: [smartstructBuilder], buildExtensions: {.dart: [mapper.g.dart]}, requiredInputs: [.g.dart], runsBefore: [injectable_generator:injectable_builder], isOptional: false, buildTo: BuildTo.source, defaults: Instance of 'TargetBuilderConfigDefaults'}]

I believe this issue caused by the new build_runner updated:

  • Use a stable order for builders without an order defined by dependencies.

How can I fix it ? Thanks

Freezed + Injectable + OpenApi Generator

Hi,

I'm using the OpenApi Generator to generate my ApiClient and Backend Models with JSON Serialization and want to Auto Map the backend Model into my Entities, which declared as freezed Models. So my generated Model looks like this:

//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// ignore_for_file: unused_element
import 'package:json_annotation/json_annotation.dart';
part 'api_country.g.dart';

@JsonSerializable(
  checked: true,
  createToJson: true,
  disallowUnrecognizedKeys: false,
  explicitToJson: true,
)
class ApiCountry {
  /// Returns a new [ApiCountry] instance.
  ApiCountry({
    required  this.id,
     this.name,
     this.isoCode,
  });

  @JsonKey(
    name: r'id',
    required: true,
    includeIfNull: false
  )
  final int id;

  @JsonKey(
    name: r'name',
    required: false,
    includeIfNull: false
  )
  final String? name;

  @JsonKey(
    name: r'isoCode',
    required: false,
    includeIfNull: false
  )
  final String? isoCode;

  @override
  bool operator ==(Object other) => identical(this, other) || other is ApiCountry &&
     other.id == id &&
     other.name == name &&
     other.isoCode == isoCode;

  @override
  int get hashCode =>
    id.hashCode +
    name.hashCode +
    isoCode.hashCode;

  factory ApiCountry.fromJson(Map<String, dynamic> json) => _$ApiCountryFromJson(json);

  Map<String, dynamic> toJson() => _$ApiCountryToJson(this);

  @override
  String toString() {
    return toJson().toString();
  }
}

and my Freezed Entity like this:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'country.freezed.dart';

@freezed
class Country with _$Country {
  const factory Country({
    required int id,
    String? name,
    String? isoCode
  }) = _Country;
}

Now I want to create a Mapper class like this:

import 'package:domain/domain.dart';
import 'package:injectable/injectable.dart';
import 'package:sample_api_client/sample_api_client.dart';
import 'package:smartstruct/smartstruct.dart';

part 'country_mapper.mapper.g.dart';

@Mapper(useInjection: true) 
abstract class CountryMapper {
  @Mapping(target: "copyWith", ignore: true)
  Country fromModel(ApiCountry model);
}

But on generation I'm getting the Bad state: no element error, like in another thread for freezed. I think this results from not mapping freezed into freezed, so the question is: Will this possible in the future or did I oversee something?

Thanks in advance, maybe I can find a way myself.

Mapper fails to generate

Mapper got case insensitive fields and contains fields: data and data. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.

I'm using the latest version. This was still working v1.2.3+1

Allow injection of other mappers/dependencies to constructor

Given the following source and target classes:

// Sources

class UserContract {
  UserContract(this.address);

  final AddressContract address;
}

class AddressContract {
  AddressContract(this.name);
  final String? name;
}

// Targets

class UserEntity {
  UserEntity(this.address);

  final AddressEntity address;
}

class AddressEntity {
  AddressEntity(this.name);

  final String? name;
}

Then our mapper would be like this:

// user_mapper.dart

@Mapper(useInjection: true)
abstract class UserMapper {
  UserEntity fromContract(UserContract contract);

  AddressEntity fromAddressContract(AddressContract contract);
}

// user_mapper.mapper.g.dart

@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
  @override
  UserEntity fromContract(UserContract contract) {
    final userentity = UserEntity(fromAddressContract(contract.address));
    return userentity;
  }

  @override
  AddressEntity fromAddressContract(AddressContract contract) {
    final addressentity = AddressEntity(contract.name);
    return addressentity;
  }
}

There will be instances that we would need a separate mapper for Address, and we would then create:

// address_mapper.dart

@Mapper(useInjection: true)
abstract class AddressMapper {
  AddressEntity fromContract(AddressContract contract);
}

// address_mapper.mapper.g.dart

@LazySingleton(as: AddressMapper)
class AddressMapperImpl extends AddressMapper {
  @override
  AddressEntity fromContract(AddressContract contract) {
    final addressentity = AddressEntity(contract.name);
    return addressentity;
  }
}

To reuse the logic from AddressMapper, we resolve AddressMapper in UserMapper and use it for mapping subclasses of UserContract in UserMapper.fromAddressContract. Right now we can do this by:

// user_mapper.dart

@Mapper(useInjection: true)
abstract class UserMapper {
  UserEntity fromContract(UserContract contract);

  @nonVirtual
  AddressEntity fromAddressContract(AddressContract contract) =>
      locator<AddressMapper>().fromContract(contract); // inline resolving using `get_it`
}

// user_mapper.mapper.g.dart

@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
  @override
  UserEntity fromContract(UserContract contract) {
    final userentity = UserEntity(fromAddressContract(contract.address));
    return userentity;
  }

  // UserMapper.fromAddressContract will not be generated since it was marked `nonVirtual`
}

It would be better if we can do the following:

// user_mapper.dart

@Mapper(useInjection: true)
abstract class UserMapper {
  final AddressMapper _addressMapper;

  UserMapper(this._addressMapper); // constructor-injected

  UserEntity fromContract(UserContract contract);

  @nonVirtual
  AddressEntity fromAddressContract(AddressContract contract) =>
      _addressMapper.fromContract(contract);
}

But the problem is that the generated mapper doesn't call the base constructor. The generated class should be:

// user_mapper.mapper.g.dart

@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
  UserMapperImpl(AddressMapper addressMapper) : super(addressMapper); // call super

  @override
  UserEntity fromContract(UserContract contract) {
    final userentity = UserEntity(fromAddressContract(contract.address));
    return userentity;
  }
}

Generator does not recognize inherited methods

Hi!

I have below an abstract class that maps one object to another:

abstract class ContractFromEntityMapper<C extends DataContract, E extends DomainEntity> {
  C? fromEntity(E? entity);
}

Then I inherit this to another class which will also be used to generate the mapper:

@Mapper(useInjection: true)
abstract class UserLoginContractFromEntityMapper extends ContractFromEntityMapper<UserLoginContract, UserLoginEntity> {}

After running build_runner, the generated file does not include fromEntity method:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user_login_mapper.dart';

// **************************************************************************
// MapperGenerator
// **************************************************************************

@LazySingleton(as: UserLoginContractFromEntityMapper)
class UserLoginContractFromEntityMapperImpl
    extends UserLoginContractFromEntityMapper {
  UserLoginContractFromEntityMapperImpl() : super();
}

But when explicitly adding the fromEntity method in UserLoginContractFromEntityMapper:

@Mapper(useInjection: true)
abstract class UserLoginContractFromEntityMapper extends ContractFromEntityMapper<UserLoginContract, UserLoginEntity> {
  @override
  UserLoginContract? fromEntity(UserLoginEntity? entity);
}

the generated file is complete:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user_login_mapper.dart';

// **************************************************************************
// MapperGenerator
// **************************************************************************

@LazySingleton(as: UserLoginContractFromEntityMapper)
class UserLoginContractFromEntityMapperImpl
    extends UserLoginContractFromEntityMapper {
  UserLoginContractFromEntityMapperImpl() : super();

  @override
  UserLoginContract? fromEntity(UserLoginEntity? entity) {
    if (entity == null) {
      return null;
    }
    ;
    final userlogincontract =
        UserLoginContract(email: entity.email, password: entity.password);
    return userlogincontract;
  }
}

@ignore annotation to exclude field from mapper

Thanks for the library. I'm a fan of Mapstruct and it's good to see a similar effort in the dart world.

One question or feature request. Is it possible to exclude a field from the automatic mapper, something similar to this?

The less we explicitly name the fields, the easier it becomes to maintain the mappings. This is particularly relevant when using libraries like Equatable that add helper fields we do not want to include in our mappings.

This would allow scenarios where we could say "map all fields except this one" as opposed to having to explicitly map all the ones we want.

DI Support

Ich will im Mapper konfigurieren können, ob dieser Mapper injectable ist.

Dann muss der Impl einfach nur eine zusätzliche Annotation
@LazySingleton(as: abstractclass)
hinzugefügt werden

Static Function Mapping for map Enums, List, Maps, Set not working

    @smotastic  Hi, thanks for info. 

I've tested new commits and unfortunately there is still broken Static mapping.

With this new change, it is not possible add helper methods for map Enums, List, Maps, Set or anything that is not a class as it generates invalid code

static EnumFoo _mapEnumFoo(Source model) => model.foo ... 
static List<String> _mapNames(Source model) => model.friends.map((f) => f.name).toList()

both will generate something like

EnumFoo _$_mapEnumFoo(Source model) {
   final enumFoo = EnumFoo._();
   return enumFoo;
}

for List it wil generate similar code.

So for now within my fork I've completely reverted static mapping as it is not usable in my application.

Originally posted by @petrnymsa in #58 (comment)

Support for nested classes

Is it possible to map classes with subclasses?

// Input

class MyClass {
  MyClass(this.mySubClass);

  final MySubClass mySubClass;
}

class MySubClass {
  MySubClass(this.myProperty);

  final String myProperty;
}

// Output

class MyClassModel {
  MyClassModel(this.mySubClass);

  final MySubClassModel mySubClass;
}

class MySubClassModel {
  MySubClassModel(this.myProperty);

  final String myProperty;
}

@Mapper(useInjection: true) not working, implementation class not being registered

Given below the my mapper class:

@Mapper(useInjection: true)
abstract class UserSigninMapper {
  UserSigninContract? fromEntity(UserSigninEntity? entity);
}

and the generated file contains:

@LazySingleton(as: UserSigninMapper)
class UserSigninMapperImpl extends UserSigninMapper {
  @override
  UserSigninContract? fromEntity(UserSigninEntity? entity) {
    if (entity == null) {
      return null;
    }
    ;
    final usersignincontract =
        UserSigninContract(email: entity.email, password: entity.password);
    return usersignincontract;
  }
}

Running flutter pub run build_runner build shows the following output:

[INFO] Running build...

// Removed for brevity

[AuthManagerImpl] depends on unregistered type [UserSigninMapper] from my_app/domain/mappers/authentication/user_signin_mapper.dart

Did you forget to annotate the above class(s) or their implementation with @injectable?
------------------------------------------------------------------------ 

// Removed for brevity

[INFO] Succeeded after 19.2s with 14 outputs (90 actions)

It seems that UserSigninMapper is not being registered. I think build_runner is ignoring generated files.

Nullable lists are not being mapped properly.

Nullable lists are not being mapped properly.
My Model contains: List<String>? values;
Generated mapper contains: values: entity.values.map((e) => e).toList()
which results in error "The method 'map' can't be unconditionally invoked because the receiver can be 'null'"

Shouldn't it be values: entity.values!.map((e) => e).toList()

Originally posted by @gopalsabhadiya in #12 (comment)

Mapper file is not generated if mapping is done with a RealmObject

I am trying to generate mapper using this lb but not file is getting generated.
Perhaps doesn't work with Realm
Code:

import 'package:deckinspectors/src/models/project_model.dart';
import 'package:deckinspectors/src/models/realm/realm_schemas.dart';
import 'package:smartstruct/smartstruct.dart';

@Mapper()
abstract class ChildMapper {
  Child? fromLocalChild(LocalChild? localChild);
  LocalChild fromChild(Child project);
}

Here, LocalChild class is a Realm generated.

Field explicit Mapping support

Auf Methodeneben möchte ich einstellen können wie gewisse Fields im in- und output gemapped werden, falls diese nicht den gleichen Namen haben.

Siehe Mapstruct
@mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car); 2

Add lifecycle methods (after & before)

It would be very helpful to have annotations for BeforeMapping & AfterMapping like the original mapstruct has.

Example usage:

class Source {}

class Target {
  Service _service;
  
  void setSevice(Service service) {
    _service = service;
  }
}

@Mapper()
abstract class SourceToTargetMapper {
  Service _service;

  SourceToTargetMapper(Service service) {
    _service = service;
  }

  Target fromSource(Source source);
  
  @AfterMapping()
  void afterMapping(Target target) {
    target.setService(_service);
  }
}

Getters are included in generated mapping

Often classes contains getters without explicit setter (computed getter,...). In such case, generated code tries to assign value to them.

Run smartstruct 1.4.0 against this mapper:

class GetterTarget {
  final String name;
  final int age;

  int foo = 0;

  GetterTarget({
    required this.name,
    required this.age,
  });

  List<Object?> get props => [name, age];

  bool get sample => false;
}

class GetterSource {
  final String name;
  final int age;

  int foo = 1;

  GetterSource({
    required this.name,
    required this.age,
  });

  List<Object?> get props => [name, age];

  bool get sample => true;
}

@Mapper()
abstract class GetterMapper {
  GetterTarget fromModel(GetterSource source);
}

Generated mapping

class GetterMapperImpl extends GetterMapper {
  GetterMapperImpl() : super();

  @override
  GetterTarget fromModel(GetterSource source) {
    final gettertarget = GetterTarget(
      name: source.name,
      age: source.age,
    );
    gettertarget.foo = source.foo;
     // NO SETTER !
    gettertarget.props = source.props.map((e) => e).toList();

   // NO SETTER !
    gettertarget.sample = source.sample;
    return gettertarget;
  }
}

This can happen alot if project uses Equatable, where props, stringify and hashCode is used.

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.

Mapper Singleton Instance Support

Ich möchte eine Singleton Instanz automatisch generieren auf die ich über einen globalen Kontext zugreifen kann.

CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

Setter support

Alles was nach dem constructor call nicht gesetzt wurde / werden konnte könnte noch über setter gesetzt werden.
Sollte nur für fields gelten die nicht final sind

Issue with JsonSerializable and contructor with none or one argument

Hi,
Given an example dto like the following, with serializable's toJson / fromJson methods

@JsonSerializable(explicitToJson: true)
class ActivityAssetsDto {
  @JsonKey(name: 'image')
  final String imageUrl;

  const ActivityAssetsDto({this.imageUrl = ""});

  factory ActivityAssetsDto.fromJson(Map<String, dynamic> json) =>
      _$ActivityAssetsDtoFromJson(json);

  Map<String, dynamic> toJson() => _$ActivityAssetsDtoToJson(this);
}

it generates

@override
  ActivityAssetsDto fromActivityAssets(ActivityAssets entity) {
    final activityassetsdto = ActivityAssetsDto.fromJson();
    return activityassetsdto;
  }

using "fromJson()" as constructor (obviously without parameter since it doesn't know what tu put there)

if I add a second parameter to the ActivityAssetsDto constructor the generator picks the correct constructors without problems.
It seems that the strategy of getting the constructor with the most arguments does not always work.

thank you for your time

Update to analyzer 5.0.0

There is new version available and many packages depend on it, so this is breaking version check.

Because smartstruct_generator >=1.3.0 depends on analyzer ^4.0.0 and json_serializable 6.6.0 depends on analyzer ^5.2.0, smartstruct_generator >=1.3.0 is incompatible with json_serializable 6.6.0.
And because no versions of json_serializable match >6.6.0 <7.0.0, smartstruct_generator >=1.3.0 is incompatible with json_serializable ^6.6.0.
So, because example depends on both json_serializable ^6.6.0 and smartstruct_generator ^1.3.0, version solving failed.
pub get failed (1; So, because example depends on both json_serializable ^6.6.0 and smartstruct_generator ^1.3.0, version solving failed.)

Cannot create Mapper for other created files

If a Mapper needs to be created for a Class which is also generated by source_gen, the mapper generator will throw an error that the source / target class is not a ClassElement.

The problem is, that my generator might, or might not run before the generator which will create the dependend class.

So the smartstruct_generator should always run after all class files which are potentially needed, are created.

See https://pub.dev/packages/build_config#adjusting-builder-ordering

feat: generate extension methods

Description

Given the following classes:

class Dog {
  final String breed;
  final int age;
  final String name;
  Dog(this.breed, this.age, this.name);
}

class DogModel {
  final String breed;
  final int age;
  final String name;
  DogModel(this.breed, this.age, this.name);
}

And given the following mapper interface:

// dogmapper.dart

part 'dogmapper.mapper.g.dart';

@Mapper()
abstract class DogMapper {
  Dog asEntity(DogModel model);
}

Instead of generating a mapper class, it would be great to generate mapper extension methods as follows:

// dogmapper.mapper.g.dart

extension ConvertibleDogModel on DogModel {
  Dog get asEntity => Dog(breed, age, name);
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.