Skip to content

Commit

Permalink
add docs for package migration
Browse files Browse the repository at this point in the history
  • Loading branch information
schultek committed May 6, 2023
1 parent 67fd1bb commit b603072
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 118 deletions.
138 changes: 21 additions & 117 deletions packages/dart_mappable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,120 +234,24 @@ The generated `<ClassName>Mappable` mixin will come with the following methods:
See the full documentation [here](https://pub.dev/documentation/dart_mappable/latest/topics/Introduction-topic.html)
or jump directly to the topic you are looking for:

- [**Models**](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html) show you how to structure and annotate your data models.
- [**Enums**](https://pub.dev/documentation/dart_mappable/latest/topics/Enums-topic.html) show you how to structure and annotate your enums.
- [**Configuration**](https://pub.dev/documentation/dart_mappable/latest/topics/Configuration-topic.html) goes into the different configuration options you have.
- [**Copy-With**](https://pub.dev/documentation/dart_mappable/latest/topics/Copy-With-topic.html) describes the copy-with functionalities and how to use them.
- [**Polymorphism**](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) shows how to do polymorphic classes and inheritance.
- [**Generics**](https://pub.dev/documentation/dart_mappable/latest/topics/Generics-topic.html) explain generic decoding and how to use it.
- [**Mapping Hooks**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html) shows how to use hooks to customize your de- and encoding process.
- [**Custom Mappers**](https://pub.dev/documentation/dart_mappable/latest/topics/Custom%20Mappers-topic.html) explains how to set up and use (non-generated) custom mappers.
- [**Mapper Container**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapper%20Container-topic.html) describes the inner workings of mapper containers in more detail.

## Compatibility

This package aims to be compatible with other code-generation packages. Check the `examples` directory for some common use-cases.

### freezed

[freezed](https://pub.dev/packages/freezed) is a "code generator for unions/pattern-matching/copy";
With this package, it is easy to create union or sealed classes.

Here is a simple example taken from their documentation:

```dart
part 'myfile.freezed.dart';
@freezed
class Union with _$Union {
const factory Union(int value) = Data;
const factory Union.loading() = Loading;
const factory Union.error([String? message]) = ErrorDetails;
}
```

To make it compatible with dart_mappable, just add your `@MappableClass` annotations to both the parent class, and all **factory constructors**, as if they were the child classes.
For a description of the `discriminatorKey` and `discriminatorValue` properties refer to the [Polymorphism](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) documentation.
You can also add the `@MappableField()` annotation to any of the fields.

```dart
part 'myfile.freezed.dart';
part 'myfile.mapper.dart';
@freezed
@MappableClass(discriminatorKey: 'type')
class Union with _$Union {
@MappableClass(discriminatorValue: 'data')
const factory Union.data(@MappableField(key: 'mykey') int value) = Data;
@MappableClass(discriminatorValue: 'loading')
const factory Union.loading() = Loading;
@MappableClass(discriminatorValue: 'error')
const factory Union.error([String? message]) = ErrorDetails;
}
```

This will now allow you to use this and the resulting `Data`, `Loading` and `ErrorDetails` classes as usual:

```dart
void main() {
var data = Union.data(42);
var dataJson = data.toJson();
print(dataJson); // {"mykey":42,"type":"data"}
var parsedData = UnionMapper.fromJson(dataJson);
print(parsedData); // Union.data(value: 42)
}
```

For the full example and generated files, check out the `examples/example_freezed` directory.

### json_serializable

[json_serializable](https://pub.dev/packages/json_serializable) is a popular serialization package
for simple applications. While this package was designed as a replacement / alternative for
json_serializable, you may come across situations where you need to deal with classes that either
use this package directly, or are designed to be compatible with it.

These classes always have the same structure:

1. A factory constructor `MyClass.fromJson(Map<String, Object?> json)` to decode json to an instance of the class, and
2. A `myClass.toJson()` method to encode an instance to json.

To use these classes with `dart_mappable`, you can use the `SerializableMapper` like this:

```dart
void main() {
var myClassMapper = SerializableMapper<MyClass, Map<String, dynamic>>(
decode: MyClass.fromJson,
encode: (myClass) => myClass.toJson,
);
// This makes it accessible by all other mappers.
MapperContainer.globals.use(myClassMapper);
}
```

For generic classes with one or two type parameters, use the `SerializableMapper.arg1` or
`SerializableMapper.arg2` constructors respectively.

### fast_immutable_collections

[fast_immutable_collections](https://pub.dev/packages/fast_immutable_collections) adds immutable
variants for the standard collections types (`List`, `Map`, `Set`). These types are compatible with
`json_serializable`, so we can use the `SerializableMapper` from above as follows:

```dart
final iListMapper = SerializableMapper<IList, dynamic>.arg1(
decode: IList.fromJson,
encode: (list) => list.toJson,
type: <E>(f) => f<IList<E>>(),
);
final iMapMapper = SerializableMapper<IMap, Map<String, dynamic>.arg2(
decode: IMap.fromJson,
encode: (map) => map.toJson,
type: <Key, Val>(f) => f<IMap<Key, Val>>(),
);
```

For a complete working example see the [fic_mappable example](https://github.com/schultek/dart_mappable/tree/main/examples/fic_mappable) on Github.
- [**Models**](https://pub.dev/documentation/dart_mappable/latest/topics/Models-topic.html)
show you how to structure and annotate your data models.
- [**Enums**](https://pub.dev/documentation/dart_mappable/latest/topics/Enums-topic.html)
show you how to structure and annotate your enums.
- [**Configuration**](https://pub.dev/documentation/dart_mappable/latest/topics/Configuration-topic.html)
goes into the different configuration options you have.
- [**Copy-With**](https://pub.dev/documentation/dart_mappable/latest/topics/Copy-With-topic.html)
describes the copy-with functionalities and how to use them.
- [**Polymorphism**](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html)
shows how to do polymorphic classes and inheritance.
- [**Generics**](https://pub.dev/documentation/dart_mappable/latest/topics/Generics-topic.html)
explain generic decoding and how to use it.
- [**Mapping Hooks**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapping%20Hooks-topic.html)
shows how to use hooks to customize your de- and encoding process.
- [**Custom Mappers**](https://pub.dev/documentation/dart_mappable/latest/topics/Custom%20Mappers-topic.html)
explains how to set up and use (non-generated) custom mappers.
- [**Mapper Container**](https://pub.dev/documentation/dart_mappable/latest/topics/Mapper%20Container-topic.html)
describes the inner workings of mapper containers in more detail.
- [**Migration and Compatibility**](https://pub.dev/documentation/dart_mappable/latest/topics/Migration%20and%20Compatibility-topic.html)
shows you how you can incrementally migrate from other packages like freezed or json_serializable and use compatible
packages like fast_immutable_collections.
5 changes: 4 additions & 1 deletion packages/dart_mappable/dartdoc_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ dartdoc:
markdown: "doc/custom.md"
"Mapper Container":
markdown: "doc/container.md"
"Migration and Compatibility":
markdown: "doc/migration.md"
categoryOrder:
- "Introduction"
- "Models"
Expand All @@ -30,4 +32,5 @@ dartdoc:
- "Generics"
- "Mapping Hooks"
- "Custom Mappers"
- "Mapper Container"
- "Mapper Container"
- "Migration and Compatibility"
113 changes: 113 additions & 0 deletions packages/dart_mappable/doc/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
`dart_mappable` tries to be compatible with other code-generation packages. Check the `examples` directory for some
common use-cases. Following are some popular packages that you can use together with `dart_mappable`.

### freezed

[freezed](https://pub.dev/packages/freezed) is a "code generator for unions/pattern-matching/copy";
With this package, it is easy to create union or sealed classes.

While `dart_mappable` can do everything freezed can do and more, it provides compatibility to give you an easy migration
path when you are considering switching to `dart_mappable`.

Here is a simple model taken from `freezed` readme:

```dart
part 'myfile.freezed.dart';
@freezed
class Union with _$Union {
const factory Union(int value) = Data;
const factory Union.loading() = Loading;
const factory Union.error([String? message]) = ErrorDetails;
}
```

To make it compatible with dart_mappable, just add your `@MappableClass` annotations to both the parent class, and all **factory constructors**, as if they were the child classes.
For a description of the `discriminatorKey` and `discriminatorValue` properties refer to the [Polymorphism](https://pub.dev/documentation/dart_mappable/latest/topics/Polymorphism-topic.html) documentation.
You can also add the `@MappableField()` annotation to any of the fields.

```dart
part 'myfile.freezed.dart';
part 'myfile.mapper.dart';
@freezed
@MappableClass(discriminatorKey: 'type')
class Union with _$Union {
@MappableClass(discriminatorValue: 'data')
const factory Union.data(@MappableField(key: 'mykey') int value) = Data;
@MappableClass(discriminatorValue: 'loading')
const factory Union.loading() = Loading;
@MappableClass(discriminatorValue: 'error')
const factory Union.error([String? message]) = ErrorDetails;
}
```

This will now allow you to use this and the resulting `Data`, `Loading` and `ErrorDetails` classes as usual:

```dart
void main() {
var data = Union.data(42);
var dataJson = data.toJson();
print(dataJson); // {"mykey":42,"type":"data"}
var parsedData = UnionMapper.fromJson(dataJson);
print(parsedData); // Union.data(value: 42)
}
```

For the full example and generated files, check out the `examples/example_freezed` directory.

### json_serializable

[json_serializable](https://pub.dev/packages/json_serializable) is a popular serialization package
for simple applications.

While this package was designed as a replacement / alternative for `json_serializable`, you may come across
situations where you need to deal with classes that either use this package directly, or are designed to be compatible with it.

Also when you want to switch from `json_serializable` to `dart_mappable`, you have an easy migration path where you can
start by only partly migrating models over to `dart_mappable` while still having full access to your *legacy* models.

Classes using `json_serializable` always have the same structure:

1. A factory constructor `MyClass.fromJson(Map<String, Object?> json)` to decode json to an instance of the class, and
2. A `myClass.toJson()` method to encode an instance to json.

To use these classes with `dart_mappable`, you can use the `SerializableMapper` like this:

```dart
void main() {
var myClassMapper = SerializableMapper<MyClass, Map<String, dynamic>>(
decode: MyClass.fromJson,
encode: (myClass) => myClass.toJson,
);
// This makes it accessible by all other mappers.
MapperContainer.globals.use(myClassMapper);
}
```

For generic classes with one or two type parameters, use the `SerializableMapper.arg1` or
`SerializableMapper.arg2` constructors respectively.

### fast_immutable_collections

[fast_immutable_collections](https://pub.dev/packages/fast_immutable_collections) adds immutable
variants for the standard collections types (`List`, `Map`, `Set`). These types are compatible with
`json_serializable`, so we can use the `SerializableMapper` from above as follows:

```dart
final iListMapper = SerializableMapper<IList, dynamic>.arg1(
decode: IList.fromJson,
encode: (list) => list.toJson,
type: <E>(f) => f<IList<E>>(),
);
final iMapMapper = SerializableMapper<IMap, Map<String, dynamic>.arg2(
decode: IMap.fromJson,
encode: (map) => map.toJson,
type: <Key, Val>(f) => f<IMap<Key, Val>>(),
);
```

For a complete working example see the [fic_mappable example](https://github.com/schultek/dart_mappable/tree/main/examples/fic_mappable) on github.
2 changes: 2 additions & 0 deletions packages/dart_mappable/lib/src/mappers/default_mappers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ typedef TypeFactory2 = Object? Function<A, B>(Object? Function<V>() f);
/// A mapper for handling classes that comply with the json_serializable format.
///
/// This mapper expects a `fromJson` and `toJson` method on a given class.
///
/// {@category Migration and Compatibility}
class SerializableMapper<T extends Object, V extends Object>
extends MapperBase<T> with PrimitiveMethodsMixin<T> {
late T Function(V value, DecodingContext context) _decoder;
Expand Down

0 comments on commit b603072

Please sign in to comment.