gen 2.2.0

This commit is contained in:
Tobe O 2018-12-08 15:53:49 -05:00
parent 60f36206fb
commit 66006ecf5b
25 changed files with 570 additions and 505 deletions

107
README.md
View file

@ -1,4 +1,5 @@
# serialize # serialize
[![Pub](https://img.shields.io/pub/v/angel_serialize.svg)](https://pub.dartlang.org/packages/angel_serialize) [![Pub](https://img.shields.io/pub/v/angel_serialize.svg)](https://pub.dartlang.org/packages/angel_serialize)
[![build status](https://travis-ci.org/angel-dart/serialize.svg)](https://travis-ci.org/angel-dart/serialize) [![build status](https://travis-ci.org/angel-dart/serialize.svg)](https://travis-ci.org/angel-dart/serialize)
@ -6,26 +7,29 @@ Source-generated serialization for Dart objects. This package uses `package:sour
the time you spend writing boilerplate serialization code for your models. the time you spend writing boilerplate serialization code for your models.
`package:angel_serialize` also powers `package:angel_orm`. `package:angel_serialize` also powers `package:angel_orm`.
* [Usage](#usage) - [Usage](#usage)
* [Models](#models) - [Models](#models)
* [Field Aliases](#aliases) - [Field Aliases](#aliases)
* [Excluding Keys](#excluding-keys) - [Excluding Keys](#excluding-keys)
* [Required Fields](#required-fields) - [Required Fields](#required-fields)
* [Serialization](#serializaition) - [Serialization](#serializaition)
* [Nesting](#nesting) - [Nesting](#nesting)
* [ID and Date Fields](#id-and-dates) - [ID and Date Fields](#id-and-dates)
* [TypeScript Definition Generator](#typescript-definitions) - [Binary Data](#binary-data)
* [Constructor Parameters](#constructor-parameters) - [TypeScript Definition Generator](#typescript-definitions)
- [Constructor Parameters](#constructor-parameters)
# Usage # Usage
In your `pubspec.yaml`, you need to install the following dependencies: In your `pubspec.yaml`, you need to install the following dependencies:
```yaml ```yaml
dependencies: dependencies:
angel_model: ^1.0.0 # Only required if using Angel!!! angel_model: ^1.0.0
angel_serialize: ^2.0.0 angel_serialize: ^2.0.0
dev_dependencies: dev_dependencies:
angel_serialize_generator: ^2.0.0 angel_serialize_generator: ^2.0.0
build_runner: ^0.8.0 build_runner: ^1.0.0
``` ```
With the recent updates to `package:build_runner`, you can build models in With the recent updates to `package:build_runner`, you can build models in
@ -38,6 +42,7 @@ If you want to watch for file changes and re-build when necessary, replace the `
with a call to `watch`. They take the same parameters. with a call to `watch`. They take the same parameters.
# Models # Models
There are a few changes opposed to normal Model classes. You need to add a `@serializable` annotation to your model There are a few changes opposed to normal Model classes. You need to add a `@serializable` annotation to your model
class to have it serialized, and a serializable model class's name should also start class to have it serialized, and a serializable model class's name should also start
with a leading underscore. with a leading underscore.
@ -61,13 +66,13 @@ part 'book.g.dart';
@serializable @serializable
abstract class _Book extends Model { abstract class _Book extends Model {
String get author; String get author;
String get title; String get title;
String get description; String get description;
int get pageCount; int get pageCount;
BookType get type; BookType get type;
} }
@ -78,17 +83,18 @@ enum BookType {
} }
``` ```
The following files will be generated: The following file will be generated:
* `book.g.dart`
* `book.serializer.g.dart` - `book.g.dart`
Producing these classes: Producing these classes:
* `Book`: Extends or implements `_Book`; may be `const`-enabled.
* `BookSerializer`: static functionality for serializing `Book` models. - `Book`: Extends or implements `_Book`; may be `const`-enabled.
* `BookFields`: The names of all fields from the `Book` model, statically-available. - `BookSerializer`: static functionality for serializing `Book` models.
- `BookFields`: The names of all fields from the `Book` model, statically-available.
# Serialization # Serialization
You can use the generated files as follows: You can use the generated files as follows:
```dart ```dart
@ -99,18 +105,18 @@ myFunction() {
description: 'You will cry after reading this.', description: 'You will cry after reading this.',
pageCount: 1225 pageCount: 1225
); );
// Easily serialize models into Maps // Easily serialize models into Maps
var map = BookSerializer.toMap(warAndPeace); var map = BookSerializer.toMap(warAndPeace);
// Also deserialize from Maps // Also deserialize from Maps
var book = BookSerializer.fromMap(map); var book = BookSerializer.fromMap(map);
print(book.title); // 'War and Peace' print(book.title); // 'War and Peace'
// For compatibility with `JSON.encode`, a `toJson` method // For compatibility with `JSON.encode`, a `toJson` method
// is included that forwards to `BookSerializer.toMap`: // is included that forwards to `BookSerializer.toMap`:
expect(book.toJson(), map); expect(book.toJson(), map);
// Generated classes act as value types, and thus can be compared. // Generated classes act as value types, and thus can be compared.
expect(BookSerializer.fromMap(map), equals(warAndPeace)); expect(BookSerializer.fromMap(map), equals(warAndPeace));
} }
@ -126,12 +132,15 @@ about the serialized names of keys on your model class.
} }
} }
``` ```
## Customizing Serialization ## Customizing Serialization
Currently, these serialization methods are supported: Currently, these serialization methods are supported:
* to `Map`
* to JSON - to `Map`
* to TypeScript definitions - to JSON
- to TypeScript definitions
You can customize these by means of `serializers`: You can customize these by means of `serializers`:
```dart ```dart
@ -139,8 +148,8 @@ You can customize these by means of `serializers`:
class _MyClass extends Model {} class _MyClass extends Model {}
``` ```
## Aliases ## Aliases
Whereas Dart fields conventionally are camelCased, most database columns Whereas Dart fields conventionally are camelCased, most database columns
tend to be snake_cased. This is not a problem, because we can define an alias tend to be snake_cased. This is not a problem, because we can define an alias
for a field. for a field.
@ -152,13 +161,13 @@ provide a custom name, or pass `autoSnakeCaseNames`: `false` to the builder;
@serializable @serializable
abstract class _Spy extends Model { abstract class _Spy extends Model {
/// Will show up as 'agency_id' in serialized JSON. /// Will show up as 'agency_id' in serialized JSON.
/// ///
/// When deserializing JSON, instead of searching for an 'agencyId' key, /// When deserializing JSON, instead of searching for an 'agencyId' key,
/// it will use 'agency_id'. /// it will use 'agency_id'.
/// ///
/// Hooray! /// Hooray!
String agencyId; String agencyId;
@Alias('foo') @Alias('foo')
String someOtherField; String someOtherField;
} }
@ -174,6 +183,7 @@ abstract class _OtherCasing extends Model {
``` ```
## Excluding Keys ## Excluding Keys
In pratice, there may keys that you want to exclude from JSON. In pratice, there may keys that you want to exclude from JSON.
To accomplish this, simply annotate them with `@exclude`: To accomplish this, simply annotate them with `@exclude`:
@ -196,7 +206,7 @@ In this case, use `canSerialize` or `canDeserialize`:
@serializable @serializable
abstract class _Whisper extends Model { abstract class _Whisper extends Model {
/// Will never be serialized to JSON /// Will never be serialized to JSON
/// ///
/// ... But it can be deserialized /// ... But it can be deserialized
@Exclude(canDeserialize: true) @Exclude(canDeserialize: true)
String secret; String secret;
@ -204,6 +214,7 @@ abstract class _Whisper extends Model {
``` ```
## Required Fields ## Required Fields
It is easy to mark a field as required; just use the It is easy to mark a field as required; just use the
`@required` annotation from `package:meta`: `@required` annotation from `package:meta`:
@ -212,7 +223,7 @@ It is easy to mark a field as required; just use the
abstract class _Foo extends Model { abstract class _Foo extends Model {
@required @required
int myRequiredInt; int myRequiredInt;
@Required('Custom message') @Required('Custom message')
int myOtherRequiredInt; int myOtherRequiredInt;
} }
@ -223,10 +234,12 @@ generated constructor, and serializers will check for its
presence, throwing a `FormatException` if it is missing. presence, throwing a `FormatException` if it is missing.
# Nesting # Nesting
`angel_serialize` also supports a few types of nesting of `@serializable` classes: `angel_serialize` also supports a few types of nesting of `@serializable` classes:
* As a class member, ex. `Book myField`
* As the type argument to a `List`, ex. `List<Book>` - As a class member, ex. `Book myField`
* As the second type argument to a `Map`, ex. `Map<String, Book>` - As the type argument to a `List`, ex. `List<Book>`
- As the second type argument to a `Map`, ex. `Map<String, Book>`
In other words, the following are all legal, and will be serialized/deserialized. In other words, the following are all legal, and will be serialized/deserialized.
You can use either the underscored name of a child class (ex. `_Book`), or the You can use either the underscored name of a child class (ex. `_Book`), or the
@ -246,11 +259,11 @@ then you will need to generate `book.g.dart` before, `author.g.dart`,
**in a separate build action**. This way, the analyzer can resolve the `Book` type. **in a separate build action**. This way, the analyzer can resolve the `Book` type.
# ID and Dates # ID and Dates
This package will automatically generate `id`, `createdAt`, and `updatedAt` fields for you, This package will automatically generate `id`, `createdAt`, and `updatedAt` fields for you,
in the style of an Angel `Model`. To disable this, set `autoIdAndDateFields` to `false` in the in the style of an Angel `Model`. To disable this, set `autoIdAndDateFields` to `false` in the
builder constructor. builder constructor.
You can also override `autoIdAndDateFields` per model: You can also override `autoIdAndDateFields` per model:
```dart ```dart
@ -258,7 +271,13 @@ You can also override `autoIdAndDateFields` per model:
abstract class _Skinny extends Model {} abstract class _Skinny extends Model {}
``` ```
# Binary Data
`package:angel_serialize` also handles `Uint8List` fields, by means of serialization to
and from `base64` encoding.
# TypeScript Definitions # TypeScript Definitions
It is quite common to build frontends with JavaScript and/or TypeScript, It is quite common to build frontends with JavaScript and/or TypeScript,
so why not generate typings as well? so why not generate typings as well?
@ -297,11 +316,13 @@ TypeScript definition. The rationale for this is that if a field (i.e. `password
never be sent to the client, the client shouldn't even know the field exists. never be sent to the client, the client shouldn't even know the field exists.
# Constructor Parameters # Constructor Parameters
Sometimes, you may need to have custom constructor parameters, for example, when Sometimes, you may need to have custom constructor parameters, for example, when
using depedency injection frameworks. For these cases, `angel_serialize` can forward using depedency injection frameworks. For these cases, `angel_serialize` can forward
custom constructor parameters. custom constructor parameters.
The following: The following:
```dart ```dart
@serializable @serializable
abstract class _Bookmark extends _BookmarkBase { abstract class _Bookmark extends _BookmarkBase {

View file

@ -1,3 +1,9 @@
# 2.2.0
* Build to `cache`.
* Only generate one `.g.dart` file.
* Support for `Uint8List`.
* Use `.cast()` for `List`s and `Map`s of *non-`Model`* types.
# 2.1.2 # 2.1.2
* Add `declare module` to generated TypeScript files. * Add `declare module` to generated TypeScript files.

View file

@ -7,13 +7,14 @@ builders:
- serializerBuilder - serializerBuilder
- typescriptDefinitionBuilder - typescriptDefinitionBuilder
auto_apply: root_package auto_apply: root_package
build_to: source build_to: cache
build_extensions: build_extensions:
.dart: .dart:
- "angel_serialize.g.part" - "angel_serialize.g.part"
- ".serializer.g.dart" - "angel_serialize_serializer.g.part"
- ".d.ts" - ".d.ts"
applies_builders: ["source_gen|combining_builder", "source_gen|part_cleanup"] applies_builders: ["source_gen|combining_builder", "source_gen|part_cleanup"]
runs_before: ["angel_orm_generator|angel_orm"]
targets: targets:
_book: _book:
sources: sources:

View file

@ -1,6 +1,7 @@
library angel_serialize_generator; library angel_serialize_generator;
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/dart/element/type.dart';
@ -28,10 +29,8 @@ Builder jsonModelBuilder(_) {
} }
Builder serializerBuilder(_) { Builder serializerBuilder(_) {
return new PartBuilder( return new SharedPartBuilder(
const [const SerializerGenerator()], const [const SerializerGenerator()], 'angel_serialize_serializer');
'.serializer.g.dart',
);
} }
Builder typescriptDefinitionBuilder(_) { Builder typescriptDefinitionBuilder(_) {
@ -73,8 +72,9 @@ bool isModelClass(DartType t) {
} }
bool isListOrMapType(DartType t) { bool isListOrMapType(DartType t) {
return const TypeChecker.fromRuntime(List).isAssignableFromType(t) || return (const TypeChecker.fromRuntime(List).isAssignableFromType(t) ||
const TypeChecker.fromRuntime(Map).isAssignableFromType(t); const TypeChecker.fromRuntime(Map).isAssignableFromType(t)) &&
!const TypeChecker.fromRuntime(Uint8List).isAssignableFromType(t);
} }
bool isEnumType(DartType t) { bool isEnumType(DartType t) {

View file

@ -180,7 +180,7 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
var eq = generateEquality(type.typeArguments[0]); var eq = generateEquality(type.typeArguments[0]);
return 'const ListEquality<${type.typeArguments[0].name}>($eq)'; return 'const ListEquality<${type.typeArguments[0].name}>($eq)';
} else } else
return 'const ListEquality<${type.typeArguments[0].name}>()'; return 'const ListEquality()';
} else if (const TypeChecker.fromRuntime(Map) } else if (const TypeChecker.fromRuntime(Map)
.isAssignableFromType(type)) { .isAssignableFromType(type)) {
if (type.typeParameters.length == 2) { if (type.typeParameters.length == 2) {
@ -188,7 +188,7 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
veq = generateEquality(type.typeArguments[1]); veq = generateEquality(type.typeArguments[1]);
return 'const MapEquality<${type.typeArguments[0].name}, ${type.typeArguments[1].name}>(keys: $keq, values: $veq)'; return 'const MapEquality<${type.typeArguments[0].name}, ${type.typeArguments[1].name}>(keys: $keq, values: $veq)';
} else } else
return 'const MapEquality()<${type.typeArguments[0].name}, ${type.typeArguments[1].name}>'; return 'const MapEquality()';
} }
return nullable ? null : 'const DefaultEquality<${type.name}>()'; return nullable ? null : 'const DefaultEquality<${type.name}>()';

View file

@ -128,6 +128,13 @@ class SerializerGenerator extends GeneratorForAnnotation<Serializable> {
null null
: ${t.name}.values.indexOf(model.${field.name}) : ${t.name}.values.indexOf(model.${field.name})
'''; ''';
} else if (const TypeChecker.fromRuntime(Uint8List)
.isAssignableFromType(t)) {
serializedRepresentation = '''
model.${field.name} == null ?
null
: base64.encode(model.${field.name})
''';
} }
} }
@ -237,6 +244,45 @@ class SerializerGenerator extends GeneratorForAnnotation<Serializable> {
: null : null
) )
'''; ''';
} else if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(t) &&
t.typeArguments.length == 1) {
var arg = convertTypeReference(t.typeArguments[0])
.accept(new DartEmitter());
deserializedRepresentation = '''
map['$alias'] is Iterable
? (map['$alias'] as Iterable).cast<$arg>().toList()
: null
''';
} else if (const TypeChecker.fromRuntime(Map)
.isAssignableFromType(t) &&
t.typeArguments.length == 2) {
var key = convertTypeReference(t.typeArguments[0])
.accept(new DartEmitter());
var value = convertTypeReference(t.typeArguments[1])
.accept(new DartEmitter());
deserializedRepresentation = '''
map['$alias'] is Map
? (map['$alias'] as Map).cast<$key, $value>()
: null
''';
} else if (const TypeChecker.fromRuntime(Uint8List)
.isAssignableFromType(t)) {
deserializedRepresentation = '''
map['$alias'] is Uint8List
? (map['$alias'] as Uint8List)
:
(
map['$alias'] is Iterable<int>
? new Uint8List.fromList((map['$alias'] as Iterable<int>).toList())
:
(
map['$alias'] is String
? new Uint8List.fromList(base64.decode(map['$alias'] as String))
: null
)
)
''';
} }
} }

View file

@ -1,5 +1,5 @@
name: angel_serialize_generator name: angel_serialize_generator
version: 2.1.2 version: 2.2.0
description: Model serialization generators, designed for use with Angel. Combine with angel_serialize for flexible modeling. description: Model serialization generators, designed for use with Angel. Combine with angel_serialize for flexible modeling.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/serialize homepage: https://github.com/angel-dart/serialize
@ -7,7 +7,7 @@ environment:
sdk: '>=2.0.0-dev.55 <3.0.0' sdk: '>=2.0.0-dev.55 <3.0.0'
dependencies: dependencies:
angel_model: ^1.0.0 angel_model: ^1.0.0
angel_serialize: ^2.0.0-alpha angel_serialize: ^2.0.0
build_config: ">=0.3.0 <2.0.0" build_config: ">=0.3.0 <2.0.0"
code_buffer: ^1.0.0 code_buffer: ^1.0.0
code_builder: ^3.0.0 code_builder: ^3.0.0

View file

@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'models/with_enum.dart'; import 'models/with_enum.dart';
@ -45,4 +47,15 @@ void main() {
test('const', () { test('const', () {
expect(identical(aWithEnum, aWithEnum2), true); expect(identical(aWithEnum, aWithEnum2), true);
}); });
test('uint8list', () {
var ee = new WithEnum(
imageBytes:
new Uint8List.fromList(new List<int>.generate(1000, (i) => i)));
var eeMap = ee.toJson();
print(eeMap);
var ef = WithEnumSerializer.fromMap(eeMap);
expect(ee.copyWith(), ee);
expect(ef, ee);
});
} }

View file

@ -1,21 +0,0 @@
/// <reference path="./book.d.ts" />
// GENERATED CODE - DO NOT MODIFY BY HAND
declare module 'angel_serialize_generator' {
interface Library {
id?: string;
collection?: LibraryCollection;
created_at?: any;
updated_at?: any;
}
interface LibraryCollection {
[key: string]: Book;
}
interface Bookmark {
id?: string;
history?: number[];
page: number;
comment?: string;
created_at?: any;
updated_at?: any;
}
}

View file

@ -5,11 +5,8 @@ import 'package:angel_serialize/angel_serialize.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'book.dart'; import 'book.dart';
part 'author.g.dart'; part 'author.g.dart';
part 'author.serializer.g.dart';
@serializable @serializable
abstract class _Author extends Model { abstract class _Author extends Model {
@required @required

View file

@ -220,3 +220,221 @@ class Bookmark extends _Bookmark {
return BookmarkSerializer.toMap(this); return BookmarkSerializer.toMap(this);
} }
} }
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class AuthorSerializer {
static Author fromMap(Map map) {
if (map['name'] == null) {
throw new FormatException("Missing required field 'name' on Author.");
}
if (map['age'] == null) {
throw new FormatException("Custom message for missing `age`");
}
return new Author(
id: map['id'] as String,
name: map['name'] as String,
age: map['age'] as int,
books: map['books'] is Iterable
? new List.unmodifiable(((map['books'] as Iterable)
.where((x) => x is Map) as Iterable<Map>)
.map(BookSerializer.fromMap))
: null,
newestBook: map['newest_book'] != null
? BookSerializer.fromMap(map['newest_book'] as Map)
: null,
obscured: map['obscured'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Author model) {
if (model == null) {
return null;
}
if (model.name == null) {
throw new FormatException("Missing required field 'name' on Author.");
}
if (model.age == null) {
throw new FormatException("Custom message for missing `age`");
}
return {
'id': model.id,
'name': model.name,
'age': model.age,
'books': model.books?.map((m) => m.toJson())?.toList(),
'newest_book': BookSerializer.toMap(model.newestBook),
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class AuthorFields {
static const List<String> allFields = const <String>[
id,
name,
age,
books,
newestBook,
secret,
obscured,
createdAt,
updatedAt
];
static const String id = 'id';
static const String name = 'name';
static const String age = 'age';
static const String books = 'books';
static const String newestBook = 'newest_book';
static const String secret = 'secret';
static const String obscured = 'obscured';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}
abstract class LibrarySerializer {
static Library fromMap(Map map) {
return new Library(
id: map['id'] as String,
collection: map['collection'] is Map
? new Map.unmodifiable(
(map['collection'] as Map).keys.fold({}, (out, key) {
return out
..[key] = BookSerializer.fromMap(
((map['collection'] as Map)[key]) as Map);
}))
: null,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Library model) {
if (model == null) {
return null;
}
return {
'id': model.id,
'collection': model.collection.keys?.fold({}, (map, key) {
return map..[key] = BookSerializer.toMap(model.collection[key]);
}),
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class LibraryFields {
static const List<String> allFields = const <String>[
id,
collection,
createdAt,
updatedAt
];
static const String id = 'id';
static const String collection = 'collection';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}
abstract class BookmarkSerializer {
static Bookmark fromMap(Map map, Book book) {
if (map['page'] == null) {
throw new FormatException("Missing required field 'page' on Bookmark.");
}
return new Bookmark(book,
id: map['id'] as String,
history: map['history'] is Iterable
? (map['history'] as Iterable).cast<int>().toList()
: null,
page: map['page'] as int,
comment: map['comment'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Bookmark model) {
if (model == null) {
return null;
}
if (model.page == null) {
throw new FormatException("Missing required field 'page' on Bookmark.");
}
return {
'id': model.id,
'history': model.history,
'page': model.page,
'comment': model.comment,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class BookmarkFields {
static const List<String> allFields = const <String>[
id,
history,
page,
comment,
createdAt,
updatedAt
];
static const String id = 'id';
static const String history = 'history';
static const String page = 'page';
static const String comment = 'comment';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}

View file

@ -1,219 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of angel_serialize.test.models.author;
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class AuthorSerializer {
static Author fromMap(Map map) {
if (map['name'] == null) {
throw new FormatException("Missing required field 'name' on Author.");
}
if (map['age'] == null) {
throw new FormatException("Custom message for missing `age`");
}
return new Author(
id: map['id'] as String,
name: map['name'] as String,
age: map['age'] as int,
books: map['books'] is Iterable
? new List.unmodifiable(((map['books'] as Iterable)
.where((x) => x is Map) as Iterable<Map>)
.map(BookSerializer.fromMap))
: null,
newestBook: map['newest_book'] != null
? BookSerializer.fromMap(map['newest_book'] as Map)
: null,
obscured: map['obscured'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Author model) {
if (model == null) {
return null;
}
if (model.name == null) {
throw new FormatException("Missing required field 'name' on Author.");
}
if (model.age == null) {
throw new FormatException("Custom message for missing `age`");
}
return {
'id': model.id,
'name': model.name,
'age': model.age,
'books': model.books?.map((m) => m.toJson())?.toList(),
'newest_book': BookSerializer.toMap(model.newestBook),
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class AuthorFields {
static const List<String> allFields = const <String>[
id,
name,
age,
books,
newestBook,
secret,
obscured,
createdAt,
updatedAt
];
static const String id = 'id';
static const String name = 'name';
static const String age = 'age';
static const String books = 'books';
static const String newestBook = 'newest_book';
static const String secret = 'secret';
static const String obscured = 'obscured';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}
abstract class LibrarySerializer {
static Library fromMap(Map map) {
return new Library(
id: map['id'] as String,
collection: map['collection'] is Map
? new Map.unmodifiable(
(map['collection'] as Map).keys.fold({}, (out, key) {
return out
..[key] = BookSerializer.fromMap(
((map['collection'] as Map)[key]) as Map);
}))
: null,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Library model) {
if (model == null) {
return null;
}
return {
'id': model.id,
'collection': model.collection.keys?.fold({}, (map, key) {
return map..[key] = BookSerializer.toMap(model.collection[key]);
}),
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class LibraryFields {
static const List<String> allFields = const <String>[
id,
collection,
createdAt,
updatedAt
];
static const String id = 'id';
static const String collection = 'collection';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}
abstract class BookmarkSerializer {
static Bookmark fromMap(Map map, Book book) {
if (map['page'] == null) {
throw new FormatException("Missing required field 'page' on Bookmark.");
}
return new Bookmark(book,
id: map['id'] as String,
history: map['history'] as List<int>,
page: map['page'] as int,
comment: map['comment'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Bookmark model) {
if (model == null) {
return null;
}
if (model.page == null) {
throw new FormatException("Missing required field 'page' on Bookmark.");
}
return {
'id': model.id,
'history': model.history,
'page': model.page,
'comment': model.comment,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class BookmarkFields {
static const List<String> allFields = const <String>[
id,
history,
page,
comment,
createdAt,
updatedAt
];
static const String id = 'id';
static const String history = 'history';
static const String page = 'page';
static const String comment = 'comment';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}

View file

@ -1,14 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
declare module 'angel_serialize_generator' {
interface Book {
id?: string;
author?: string;
title?: string;
description?: string;
page_count?: number;
not_models?: number[];
camelCase?: string;
created_at?: any;
updated_at?: any;
}
}

View file

@ -4,7 +4,6 @@ import 'package:angel_model/angel_model.dart';
import 'package:angel_serialize/angel_serialize.dart'; import 'package:angel_serialize/angel_serialize.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
part 'book.g.dart'; part 'book.g.dart';
part 'book.serializer.g.dart';
@Serializable(serializers: Serializers.all) @Serializable(serializers: Serializers.all)
abstract class _Book extends Model { abstract class _Book extends Model {

View file

@ -102,3 +102,81 @@ class Book extends _Book {
return BookSerializer.toMap(this); return BookSerializer.toMap(this);
} }
} }
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class BookSerializer {
static Book fromMap(Map map) {
return new Book(
id: map['id'] as String,
author: map['author'] as String,
title: map['title'] as String,
description: map['description'] as String,
pageCount: map['page_count'] as int,
notModels: map['not_models'] is Iterable
? (map['not_models'] as Iterable).cast<double>().toList()
: null,
camelCaseString: map['camelCase'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Book model) {
if (model == null) {
return null;
}
return {
'id': model.id,
'author': model.author,
'title': model.title,
'description': model.description,
'page_count': model.pageCount,
'not_models': model.notModels,
'camelCase': model.camelCaseString,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class BookFields {
static const List<String> allFields = const <String>[
id,
author,
title,
description,
pageCount,
notModels,
camelCaseString,
createdAt,
updatedAt
];
static const String id = 'id';
static const String author = 'author';
static const String title = 'title';
static const String description = 'description';
static const String pageCount = 'page_count';
static const String notModels = 'not_models';
static const String camelCaseString = 'camelCase';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}

View file

@ -1,79 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of angel_serialize.test.models.book;
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class BookSerializer {
static Book fromMap(Map map) {
return new Book(
id: map['id'] as String,
author: map['author'] as String,
title: map['title'] as String,
description: map['description'] as String,
pageCount: map['page_count'] as int,
notModels: map['not_models'] as List<double>,
camelCaseString: map['camelCase'] as String,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null);
}
static Map<String, dynamic> toMap(Book model) {
if (model == null) {
return null;
}
return {
'id': model.id,
'author': model.author,
'title': model.title,
'description': model.description,
'page_count': model.pageCount,
'not_models': model.notModels,
'camelCase': model.camelCaseString,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String()
};
}
}
abstract class BookFields {
static const List<String> allFields = const <String>[
id,
author,
title,
description,
pageCount,
notModels,
camelCaseString,
createdAt,
updatedAt
];
static const String id = 'id';
static const String author = 'author';
static const String title = 'title';
static const String description = 'description';
static const String pageCount = 'page_count';
static const String notModels = 'not_models';
static const String camelCaseString = 'camelCase';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
}

View file

@ -1,10 +1,8 @@
import 'package:angel_serialize/angel_serialize.dart'; import 'package:angel_serialize/angel_serialize.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'game_pad_button.dart'; import 'game_pad_button.dart';
part 'game_pad.g.dart'; part 'game_pad.g.dart';
part 'game_pad.serializer.g.dart';
@Serializable(autoIdAndDateFields: false) @Serializable(autoIdAndDateFields: false)
class _Gamepad { class _Gamepad {

View file

@ -45,3 +45,39 @@ class Gamepad extends _Gamepad {
return GamepadSerializer.toMap(this); return GamepadSerializer.toMap(this);
} }
} }
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class GamepadSerializer {
static Gamepad fromMap(Map map) {
return new Gamepad(
buttons: map['buttons'] is Iterable
? new List.unmodifiable(((map['buttons'] as Iterable)
.where((x) => x is Map) as Iterable<Map>)
.map(GamepadButtonSerializer.fromMap))
: null,
dynamicMap: map['dynamic_map'] is Map
? (map['dynamic_map'] as Map).cast<String, dynamic>()
: null);
}
static Map<String, dynamic> toMap(Gamepad model) {
if (model == null) {
return null;
}
return {
'buttons': model.buttons?.map((m) => m.toJson())?.toList(),
'dynamic_map': model.dynamicMap
};
}
}
abstract class GamepadFields {
static const List<String> allFields = const <String>[buttons, dynamicMap];
static const String buttons = 'buttons';
static const String dynamicMap = 'dynamic_map';
}

View file

@ -1,37 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'game_pad.dart';
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class GamepadSerializer {
static Gamepad fromMap(Map map) {
return new Gamepad(
buttons: map['buttons'] is Iterable
? new List.unmodifiable(((map['buttons'] as Iterable)
.where((x) => x is Map) as Iterable<Map>)
.map(GamepadButtonSerializer.fromMap))
: null,
dynamicMap: map['dynamic_map'] as Map<String, dynamic>);
}
static Map<String, dynamic> toMap(Gamepad model) {
if (model == null) {
return null;
}
return {
'buttons': model.buttons?.map((m) => m.toJson())?.toList(),
'dynamic_map': model.dynamicMap
};
}
}
abstract class GamepadFields {
static const List<String> allFields = const <String>[buttons, dynamicMap];
static const String buttons = 'buttons';
static const String dynamicMap = 'dynamic_map';
}

View file

@ -1,6 +1,5 @@
import 'package:angel_serialize/angel_serialize.dart'; import 'package:angel_serialize/angel_serialize.dart';
part 'game_pad_button.g.dart'; part 'game_pad_button.g.dart';
part 'game_pad_button.serializer.g.dart';
@Serializable(autoIdAndDateFields: false) @Serializable(autoIdAndDateFields: false)
abstract class _GamepadButton { abstract class _GamepadButton {

View file

@ -36,3 +36,29 @@ class GamepadButton implements _GamepadButton {
return GamepadButtonSerializer.toMap(this); return GamepadButtonSerializer.toMap(this);
} }
} }
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class GamepadButtonSerializer {
static GamepadButton fromMap(Map map) {
return new GamepadButton(
name: map['name'] as String, radius: map['radius'] as int);
}
static Map<String, dynamic> toMap(GamepadButton model) {
if (model == null) {
return null;
}
return {'name': model.name, 'radius': model.radius};
}
}
abstract class GamepadButtonFields {
static const List<String> allFields = const <String>[name, radius];
static const String name = 'name';
static const String radius = 'radius';
}

View file

@ -1,29 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'game_pad_button.dart';
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class GamepadButtonSerializer {
static GamepadButton fromMap(Map map) {
return new GamepadButton(
name: map['name'] as String, radius: map['radius'] as int);
}
static Map<String, dynamic> toMap(GamepadButton model) {
if (model == null) {
return null;
}
return {'name': model.name, 'radius': model.radius};
}
}
abstract class GamepadButtonFields {
static const List<String> allFields = const <String>[name, radius];
static const String name = 'name';
static const String radius = 'radius';
}

View file

@ -1,13 +1,16 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:angel_serialize/angel_serialize.dart'; import 'package:angel_serialize/angel_serialize.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
part 'with_enum.g.dart'; part 'with_enum.g.dart';
part 'with_enum.serializer.g.dart';
@Serializable(autoIdAndDateFields: false) @Serializable(autoIdAndDateFields: false)
abstract class _WithEnum { abstract class _WithEnum {
WithEnumType get type; WithEnumType get type;
List<int> get finalList; List<int> get finalList;
Uint8List get imageBytes;
} }
enum WithEnumType { a, b, c } enum WithEnumType { a, b, c }

View file

@ -8,7 +8,7 @@ part of 'with_enum.dart';
@generatedSerializable @generatedSerializable
class WithEnum implements _WithEnum { class WithEnum implements _WithEnum {
const WithEnum({this.type, List<int> this.finalList}); const WithEnum({this.type, List<int> this.finalList, this.imageBytes});
@override @override
final WithEnumType type; final WithEnumType type;
@ -16,24 +16,85 @@ class WithEnum implements _WithEnum {
@override @override
final List<int> finalList; final List<int> finalList;
WithEnum copyWith({WithEnumType type, List<int> finalList}) { @override
final Uint8List imageBytes;
WithEnum copyWith(
{WithEnumType type, List<int> finalList, Uint8List imageBytes}) {
return new WithEnum( return new WithEnum(
type: type ?? this.type, finalList: finalList ?? this.finalList); type: type ?? this.type,
finalList: finalList ?? this.finalList,
imageBytes: imageBytes ?? this.imageBytes);
} }
bool operator ==(other) { bool operator ==(other) {
return other is _WithEnum && return other is _WithEnum &&
other.type == type && other.type == type &&
const ListEquality<int>(const DefaultEquality<int>()) const ListEquality<int>(const DefaultEquality<int>())
.equals(other.finalList, finalList); .equals(other.finalList, finalList) &&
const ListEquality().equals(other.imageBytes, imageBytes);
} }
@override @override
int get hashCode { int get hashCode {
return hashObjects([type, finalList]); return hashObjects([type, finalList, imageBytes]);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return WithEnumSerializer.toMap(this); return WithEnumSerializer.toMap(this);
} }
} }
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class WithEnumSerializer {
static WithEnum fromMap(Map map) {
return new WithEnum(
type: map['type'] is WithEnumType
? (map['type'] as WithEnumType)
: (map['type'] is int
? WithEnumType.values[map['type'] as int]
: null),
finalList: map['final_list'] is Iterable
? (map['final_list'] as Iterable).cast<int>().toList()
: null,
imageBytes: map['image_bytes'] is Uint8List
? (map['image_bytes'] as Uint8List)
: (map['image_bytes'] is Iterable<int>
? new Uint8List.fromList(
(map['image_bytes'] as Iterable<int>).toList())
: (map['image_bytes'] is String
? new Uint8List.fromList(
base64.decode(map['image_bytes'] as String))
: null)));
}
static Map<String, dynamic> toMap(WithEnum model) {
if (model == null) {
return null;
}
return {
'type':
model.type == null ? null : WithEnumType.values.indexOf(model.type),
'final_list': model.finalList,
'image_bytes':
model.imageBytes == null ? null : base64.encode(model.imageBytes)
};
}
}
abstract class WithEnumFields {
static const List<String> allFields = const <String>[
type,
finalList,
imageBytes
];
static const String type = 'type';
static const String finalList = 'final_list';
static const String imageBytes = 'image_bytes';
}

View file

@ -1,38 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'with_enum.dart';
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class WithEnumSerializer {
static WithEnum fromMap(Map map) {
return new WithEnum(
type: map['type'] is WithEnumType
? (map['type'] as WithEnumType)
: (map['type'] is int
? WithEnumType.values[map['type'] as int]
: null),
finalList: map['final_list'] as List<int>);
}
static Map<String, dynamic> toMap(WithEnum model) {
if (model == null) {
return null;
}
return {
'type':
model.type == null ? null : WithEnumType.values.indexOf(model.type),
'final_list': model.finalList
};
}
}
abstract class WithEnumFields {
static const List<String> allFields = const <String>[type, finalList];
static const String type = 'type';
static const String finalList = 'final_list';
}