Implement new serialization api in generated classes

This commit is contained in:
Simon Binder 2019-05-23 19:17:47 +02:00
parent 5db9a5f87d
commit 023c055e44
No known key found for this signature in database
GPG Key ID: B807FDF954BA00CF
5 changed files with 120 additions and 94 deletions

View File

@ -22,17 +22,19 @@ class Category extends DataClass {
.mapFromDatabaseResponse(data['${effectivePrefix}description']),
);
}
factory Category.fromJson(Map<String, dynamic> json) {
factory Category.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return Category(
id: json['id'] as int,
description: json['description'] as String,
id: serializer.fromJson<int>(json['id']),
description: serializer.fromJson<String>(json['description']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'description': description,
'id': serializer.toJson<int>(id),
'description': serializer.toJson<String>(description),
};
}
@ -140,21 +142,23 @@ class Recipe extends DataClass {
intType.mapFromDatabaseResponse(data['${effectivePrefix}category']),
);
}
factory Recipe.fromJson(Map<String, dynamic> json) {
factory Recipe.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return Recipe(
id: json['id'] as int,
title: json['title'] as String,
instructions: json['instructions'] as String,
category: json['category'] as int,
id: serializer.fromJson<int>(json['id']),
title: serializer.fromJson<String>(json['title']),
instructions: serializer.fromJson<String>(json['instructions']),
category: serializer.fromJson<int>(json['category']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'title': title,
'instructions': instructions,
'category': category,
'id': serializer.toJson<int>(id),
'title': serializer.toJson<String>(title),
'instructions': serializer.toJson<String>(instructions),
'category': serializer.toJson<int>(category),
};
}
@ -295,19 +299,21 @@ class Ingredient extends DataClass {
intType.mapFromDatabaseResponse(data['${effectivePrefix}calories']),
);
}
factory Ingredient.fromJson(Map<String, dynamic> json) {
factory Ingredient.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return Ingredient(
id: json['id'] as int,
name: json['name'] as String,
caloriesPer100g: json['caloriesPer100g'] as int,
id: serializer.fromJson<int>(json['id']),
name: serializer.fromJson<String>(json['name']),
caloriesPer100g: serializer.fromJson<int>(json['caloriesPer100g']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'name': name,
'caloriesPer100g': caloriesPer100g,
'id': serializer.toJson<int>(id),
'name': serializer.toJson<String>(name),
'caloriesPer100g': serializer.toJson<int>(caloriesPer100g),
};
}
@ -433,19 +439,21 @@ class IngredientInRecipe extends DataClass {
intType.mapFromDatabaseResponse(data['${effectivePrefix}amount']),
);
}
factory IngredientInRecipe.fromJson(Map<String, dynamic> json) {
factory IngredientInRecipe.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return IngredientInRecipe(
recipe: json['recipe'] as int,
ingredient: json['ingredient'] as int,
amountInGrams: json['amountInGrams'] as int,
recipe: serializer.fromJson<int>(json['recipe']),
ingredient: serializer.fromJson<int>(json['ingredient']),
amountInGrams: serializer.fromJson<int>(json['amountInGrams']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'recipe': recipe,
'ingredient': ingredient,
'amountInGrams': amountInGrams,
'recipe': serializer.toJson<int>(recipe),
'ingredient': serializer.toJson<int>(ingredient),
'amountInGrams': serializer.toJson<int>(amountInGrams),
};
}

View File

@ -5,13 +5,14 @@ import 'dart:convert';
abstract class DataClass {
const DataClass();
// todo better docs, explain ValueSerializer
/// Converts this object into a representation that can be encoded with
/// [json].
/// [json]. The [serializer] can be used to configure how individual values
/// will be encoded.
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()});
/// Converts this object into a json representation. The [serializer] can be
/// used to configure how individual values will be encoded.
String toJsonString(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return json.encode(toJson(serializer: serializer));
@ -21,9 +22,17 @@ abstract class DataClass {
/// Serializer responsible for mapping atomic types from and to json.
abstract class ValueSerializer {
const ValueSerializer();
/// The default serializer encodes date times as a unix-timestamp in
/// milliseconds.
const factory ValueSerializer.defaults() = _DefaultValueSerializer;
/// Converts the [value] to something that can be passed to
/// [JsonCodec.encode].
dynamic toJson<T>(T value);
/// Inverse of [toJson]: Converts a value obtained from [JsonCodec.decode]
/// into a value that can be hold by data classes.
T fromJson<T>(dynamic json);
}

View File

@ -33,23 +33,25 @@ class TodoEntry extends DataClass {
intType.mapFromDatabaseResponse(data['${effectivePrefix}category']),
);
}
factory TodoEntry.fromJson(Map<String, dynamic> json) {
factory TodoEntry.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return TodoEntry(
id: json['id'] as int,
title: json['title'] as String,
content: json['content'] as String,
targetDate: json['targetDate'] as DateTime,
category: json['category'] as int,
id: serializer.fromJson<int>(json['id']),
title: serializer.fromJson<String>(json['title']),
content: serializer.fromJson<String>(json['content']),
targetDate: serializer.fromJson<DateTime>(json['targetDate']),
category: serializer.fromJson<int>(json['category']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'title': title,
'content': content,
'targetDate': targetDate,
'category': category,
'id': serializer.toJson<int>(id),
'title': serializer.toJson<String>(title),
'content': serializer.toJson<String>(content),
'targetDate': serializer.toJson<DateTime>(targetDate),
'category': serializer.toJson<int>(category),
};
}
@ -215,17 +217,19 @@ class Category extends DataClass {
stringType.mapFromDatabaseResponse(data['${effectivePrefix}desc']),
);
}
factory Category.fromJson(Map<String, dynamic> json) {
factory Category.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return Category(
id: json['id'] as int,
description: json['description'] as String,
id: serializer.fromJson<int>(json['id']),
description: serializer.fromJson<String>(json['description']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'description': description,
'id': serializer.toJson<int>(id),
'description': serializer.toJson<String>(description),
};
}
@ -340,23 +344,25 @@ class User extends DataClass {
.mapFromDatabaseResponse(data['${effectivePrefix}creation_time']),
);
}
factory User.fromJson(Map<String, dynamic> json) {
factory User.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return User(
id: json['id'] as int,
name: json['name'] as String,
isAwesome: json['isAwesome'] as bool,
profilePicture: json['profilePicture'] as Uint8List,
creationTime: json['creationTime'] as DateTime,
id: serializer.fromJson<int>(json['id']),
name: serializer.fromJson<String>(json['name']),
isAwesome: serializer.fromJson<bool>(json['isAwesome']),
profilePicture: serializer.fromJson<Uint8List>(json['profilePicture']),
creationTime: serializer.fromJson<DateTime>(json['creationTime']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': id,
'name': name,
'isAwesome': isAwesome,
'profilePicture': profilePicture,
'creationTime': creationTime,
'id': serializer.toJson<int>(id),
'name': serializer.toJson<String>(name),
'isAwesome': serializer.toJson<bool>(isAwesome),
'profilePicture': serializer.toJson<Uint8List>(profilePicture),
'creationTime': serializer.toJson<DateTime>(creationTime),
};
}
@ -515,17 +521,19 @@ class SharedTodo extends DataClass {
user: intType.mapFromDatabaseResponse(data['${effectivePrefix}user']),
);
}
factory SharedTodo.fromJson(Map<String, dynamic> json) {
factory SharedTodo.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return SharedTodo(
todo: json['todo'] as int,
user: json['user'] as int,
todo: serializer.fromJson<int>(json['todo']),
user: serializer.fromJson<int>(json['user']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'todo': todo,
'user': user,
'todo': serializer.toJson<int>(todo),
'user': serializer.toJson<int>(user),
};
}
@ -632,17 +640,19 @@ class TableWithoutPKData extends DataClass {
numType.mapFromDatabaseResponse(data['${effectivePrefix}some_float']),
);
}
factory TableWithoutPKData.fromJson(Map<String, dynamic> json) {
factory TableWithoutPKData.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return TableWithoutPKData(
notReallyAnId: json['notReallyAnId'] as int,
someFloat: json['someFloat'] as num,
notReallyAnId: serializer.fromJson<int>(json['notReallyAnId']),
someFloat: serializer.fromJson<num>(json['someFloat']),
);
}
@override
Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'notReallyAnId': notReallyAnId,
'someFloat': someFloat,
'notReallyAnId': serializer.toJson<int>(notReallyAnId),
'someFloat': serializer.toJson<num>(someFloat),
};
}

View File

@ -8,27 +8,17 @@ import 'package:path/path.dart';
import 'format_coverage.dart' as fc;
const int _vmPort = 9876;
Future<void> main(List<String> args) async {
// First, generate the build script, see
// https://github.com/dart-lang/build/blob/3208cfe94c475ed3e1ec44c227aadaddaeac263d/build_runner/bin/build_runner.dart#L65
Pub.run('build_runner', arguments: ['generate-build-script']);
// Start coverage collection (resume isolates, don't wait for pause, collect
// when isolates exit).
final collectorFuture =
collect(Uri.parse('http://localhost:$_vmPort'), true, false, true);
// Next, run the test script in another dart process that has the vm services
// enabled.
final tests = join(File.fromUri(Platform.script).parent.path, 'tester.dart');
// not using Dart.run because that only prints to stdout after the process has
// completed.
await Dart.runAsync(tests,
vmArgs: ['--enable-vm-service=$_vmPort', '--pause-isolates-on-exit']);
final coverage = await runAndCollect(tests, onExit: true, printOutput: true);
File('coverage.json').writeAsStringSync(json.encode(await collectorFuture));
File('coverage.json').writeAsStringSync(json.encode(coverage));
print('formatting to .lcov format');
await fc.main();

View File

@ -101,25 +101,34 @@ class DataClassWriter {
final dataClassName = table.dartTypeName;
buffer
..write('factory $dataClassName.fromJson(Map<String, dynamic> json) {\n')
..write('factory $dataClassName.fromJson('
'Map<String, dynamic> json,'
'{ValueSerializer serializer = const ValueSerializer.defaults()}'
') {\n')
..write('return $dataClassName(');
for (var column in table.columns) {
final getter = column.dartGetterName;
final type = column.dartTypeName;
buffer.write("$getter: json['$getter'] as $type,");
buffer.write("$getter: serializer.fromJson<$type>(json['$getter']),");
}
buffer.write(');}\n');
}
void _writeToJson(StringBuffer buffer) {
buffer.write('@override Map<String, dynamic> toJson() {\n return {');
buffer.write('@override Map<String, dynamic> toJson('
'{ValueSerializer serializer = const ValueSerializer.defaults()}) {'
'\n return {');
for (var column in table.columns) {
final getter = column.dartGetterName;
buffer.write("'$getter': $getter,");
final name = column.dartGetterName;
final needsThis = name == 'serializer';
final value = needsThis ? 'this.$name' : name;
buffer
.write("'$name': serializer.toJson<${column.dartTypeName}>($value),");
}
buffer.write('};}');