From 642a7d98a87a2ce058fd8b776aacc3b5f23010ed Mon Sep 17 00:00:00 2001 From: Tobe O Date: Thu, 4 Jul 2019 14:30:45 -0400 Subject: [PATCH] Finish subclass --- README.md | 31 ++ angel_serialize_generator/CHANGELOG.md | 3 + .../lib/build_context.dart | 61 ++-- angel_serialize_generator/lib/model.dart | 7 +- .../test/models/book.d.ts | 14 +- .../test/models/book.g.dart | 314 +++++++++--------- .../test/models/subclass.dart | 22 ++ .../test/models/subclass.g.dart | 214 ++++++++++++ 8 files changed, 482 insertions(+), 184 deletions(-) create mode 100644 angel_serialize_generator/test/models/subclass.dart create mode 100644 angel_serialize_generator/test/models/subclass.g.dart diff --git a/README.md b/README.md index c4175321..e564cc8c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ the time you spend writing boilerplate serialization code for your models. - [Usage](#usage) - [Models](#models) + - [Subclasses](#subclasses) - [Field Aliases](#aliases) - [Excluding Keys](#excluding-keys) - [Required Fields](#required-fields) @@ -158,6 +159,36 @@ You can customize these by means of `serializers`: class _MyClass extends Model {} ``` +## Subclasses +`angel_serialize` pulls in fields from parent classes, as well as +implemented interfaces, so it is extremely easy to share attributes among +model classes: + +```dart +import 'package:angel_serialize/angel_serialize.dart'; +part 'subclass.g.dart'; + +@serializable +class _Animal { + @notNull + String genus; + @notNull + String species; +} + +@serializable +class _Bird extends _Animal { + @DefaultsTo(false) + bool isSparrow; +} + +var saxaulSparrow = Bird( + genus: 'Passer', + species: 'ammodendri', + isSparrow: true, +); +``` + ## Aliases Whereas Dart fields conventionally are camelCased, most database columns diff --git a/angel_serialize_generator/CHANGELOG.md b/angel_serialize_generator/CHANGELOG.md index 38316cba..03798661 100644 --- a/angel_serialize_generator/CHANGELOG.md +++ b/angel_serialize_generator/CHANGELOG.md @@ -1,6 +1,9 @@ # 2.5.0 * Support mutable models (again). * Use `whereType()` instead of chaining `where()` and `cast()`. +* Support pulling fields from parent classes and interfaces. +* Only generate `const` constructors if *all* +fields lack a setter. # 2.4.4 * Remove unnecessary `new` and `const`. diff --git a/angel_serialize_generator/lib/build_context.dart b/angel_serialize_generator/lib/build_context.dart index 35e97d4e..31d92216 100644 --- a/angel_serialize_generator/lib/build_context.dart +++ b/angel_serialize_generator/lib/build_context.dart @@ -53,10 +53,22 @@ Future buildContext(ClassElement clazz, ConstantReader annotation, includeAnnotations: annotation.peek('includeAnnotations')?.listValue ?? [], ); - var lib = await resolver.libraryFor(buildStep.inputId); + // var lib = await resolver.libraryFor(buildStep.inputId); List fieldNames = []; + var fields = []; - for (var field in clazz.fields) { + // Crawl for classes from parent classes. + void crawlClass(InterfaceType t) { + while (t != null) { + fields.insertAll(0, t.element.fields); + t.interfaces.forEach(crawlClass); + t = t.superclass; + } + } + + crawlClass(clazz.type); + + for (var field in fields) { // Skip private fields if (field.name.startsWith('_')) { continue; @@ -196,30 +208,31 @@ Future buildContext(ClassElement clazz, ConstantReader annotation, } } - if (const TypeChecker.fromRuntime(Model).isAssignableFromType(clazz.type)) { - if (!fieldNames.contains('id')) { - var idField = ShimFieldImpl('id', lib.context.typeProvider.stringType); - ctx.fields.insert(0, idField); - ctx.shimmed['id'] = true; - } + // ShimFields are no longer used. + // if (const TypeChecker.fromRuntime(Model).isAssignableFromType(clazz.type)) { + // if (!fieldNames.contains('id')) { + // var idField = ShimFieldImpl('id', lib.context.typeProvider.stringType); + // ctx.fields.insert(0, idField); + // ctx.shimmed['id'] = true; + // } - DartType dateTime; - for (var key in ['createdAt', 'updatedAt']) { - if (!fieldNames.contains(key)) { - if (dateTime == null) { - var coreLib = - await resolver.libraries.singleWhere((lib) => lib.isDartCore); - var dt = coreLib.getType('DateTime'); - dateTime = dt.type; - } + // DartType dateTime; + // for (var key in ['createdAt', 'updatedAt']) { + // if (!fieldNames.contains(key)) { + // if (dateTime == null) { + // var coreLib = + // await resolver.libraries.singleWhere((lib) => lib.isDartCore); + // var dt = coreLib.getType('DateTime'); + // dateTime = dt.type; + // } - var field = ShimFieldImpl(key, dateTime); - ctx.aliases[key] = ReCase(key).snakeCase; - ctx.fields.add(field); - ctx.shimmed[key] = true; - } - } - } + // var field = ShimFieldImpl(key, dateTime); + // ctx.aliases[key] = ReCase(key).snakeCase; + // ctx.fields.add(field); + // ctx.shimmed[key] = true; + // } + // } + // } // Get constructor params, if any ctx.constructorParameters.addAll(clazz.unnamedConstructor.parameters); diff --git a/angel_serialize_generator/lib/model.dart b/angel_serialize_generator/lib/model.dart index 07e3a093..be91a446 100644 --- a/angel_serialize_generator/lib/model.dart +++ b/angel_serialize_generator/lib/model.dart @@ -94,8 +94,11 @@ class JsonModelGenerator extends GeneratorForAnnotation { BuildContext ctx, ClassBuilder clazz, LibraryBuilder file) { clazz.constructors.add(Constructor((constructor) { // Add all `super` params - constructor.constant = ctx.clazz.unnamedConstructor?.isConst == true || - shouldBeConstant(ctx); + constructor.constant = (ctx.clazz.unnamedConstructor?.isConst == true || + shouldBeConstant(ctx)) && + ctx.fields.every((f) { + return f.setter == null && f is! ShimFieldImpl; + }); for (var param in ctx.constructorParameters) { constructor.requiredParameters.add(Parameter((b) => b diff --git a/angel_serialize_generator/test/models/book.d.ts b/angel_serialize_generator/test/models/book.d.ts index 64ff06e2..c0c01be5 100644 --- a/angel_serialize_generator/test/models/book.d.ts +++ b/angel_serialize_generator/test/models/book.d.ts @@ -2,39 +2,39 @@ declare module 'angel_serialize_generator' { interface Book { id?: string; + created_at?: any; + updated_at?: any; author?: string; title?: string; description?: string; page_count?: number; not_models?: number[]; camelCase?: string; - created_at?: any; - updated_at?: any; } interface Author { id?: string; + created_at?: any; + updated_at?: any; name: string; age: number; books?: Book[]; newest_book?: Book; - created_at?: any; - updated_at?: any; } interface Library { id?: string; - collection?: LibraryCollection; created_at?: any; updated_at?: any; + collection?: LibraryCollection; } interface LibraryCollection { [key: string]: Book; } interface Bookmark { id?: string; + created_at?: any; + updated_at?: any; history?: number[]; page: number; comment?: string; - created_at?: any; - updated_at?: any; } } \ No newline at end of file diff --git a/angel_serialize_generator/test/models/book.g.dart b/angel_serialize_generator/test/models/book.g.dart index f1d25292..ead62913 100644 --- a/angel_serialize_generator/test/models/book.g.dart +++ b/angel_serialize_generator/test/models/book.g.dart @@ -12,19 +12,28 @@ part of angel_serialize.test.models.book; class Book extends _Book { Book( {this.id, + this.createdAt, + this.updatedAt, this.author, this.title, this.description, this.pageCount, List notModels, - this.camelCaseString, - this.createdAt, - this.updatedAt}) + this.camelCaseString}) : this.notModels = List.unmodifiable(notModels ?? []); + /// A unique identifier corresponding to this item. @override String id; + /// The time at which this item was created. + @override + DateTime createdAt; + + /// The last time at which this item was updated. + @override + DateTime updatedAt; + @override String author; @@ -44,66 +53,60 @@ class Book extends _Book { @override String camelCaseString; - @override - DateTime createdAt; - - @override - DateTime updatedAt; - Book copyWith( {String id, + DateTime createdAt, + DateTime updatedAt, String author, String title, String description, int pageCount, List notModels, - String camelCaseString, - DateTime createdAt, - DateTime updatedAt}) { + String camelCaseString}) { return Book( id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, author: author ?? this.author, title: title ?? this.title, description: description ?? this.description, pageCount: pageCount ?? this.pageCount, notModels: notModels ?? this.notModels, - camelCaseString: camelCaseString ?? this.camelCaseString, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); + camelCaseString: camelCaseString ?? this.camelCaseString); } bool operator ==(other) { return other is _Book && other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && other.author == author && other.title == title && other.description == description && other.pageCount == pageCount && ListEquality(DefaultEquality()) .equals(other.notModels, notModels) && - other.camelCaseString == camelCaseString && - other.createdAt == createdAt && - other.updatedAt == updatedAt; + other.camelCaseString == camelCaseString; } @override int get hashCode { return hashObjects([ id, + createdAt, + updatedAt, author, title, description, pageCount, notModels, - camelCaseString, - createdAt, - updatedAt + camelCaseString ]); } @override String toString() { - return "Book(id=$id, author=$author, title=$title, description=$description, pageCount=$pageCount, notModels=$notModels, camelCaseString=$camelCaseString, createdAt=$createdAt, updatedAt=$updatedAt)"; + return "Book(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, author=$author, title=$title, description=$description, pageCount=$pageCount, notModels=$notModels, camelCaseString=$camelCaseString)"; } Map toJson() { @@ -115,19 +118,28 @@ class Book extends _Book { class Author extends _Author { Author( {this.id, + this.createdAt, + this.updatedAt, @required this.name, @required this.age, List<_Book> books, this.newestBook, this.secret, - this.obscured, - this.createdAt, - this.updatedAt}) + this.obscured}) : this.books = List.unmodifiable(books ?? []); + /// A unique identifier corresponding to this item. @override String id; + /// The time at which this item was created. + @override + DateTime createdAt; + + /// The last time at which this item was updated. + @override + DateTime updatedAt; + @override final String name; @@ -147,66 +159,60 @@ class Author extends _Author { @override final String obscured; - @override - DateTime createdAt; - - @override - DateTime updatedAt; - Author copyWith( {String id, + DateTime createdAt, + DateTime updatedAt, String name, int age, List<_Book> books, _Book newestBook, String secret, - String obscured, - DateTime createdAt, - DateTime updatedAt}) { + String obscured}) { return Author( id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, name: name ?? this.name, age: age ?? this.age, books: books ?? this.books, newestBook: newestBook ?? this.newestBook, secret: secret ?? this.secret, - obscured: obscured ?? this.obscured, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); + obscured: obscured ?? this.obscured); } bool operator ==(other) { return other is _Author && other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && other.name == name && other.age == age && ListEquality<_Book>(DefaultEquality<_Book>()) .equals(other.books, books) && other.newestBook == newestBook && other.secret == secret && - other.obscured == obscured && - other.createdAt == createdAt && - other.updatedAt == updatedAt; + other.obscured == obscured; } @override int get hashCode { return hashObjects([ id, + createdAt, + updatedAt, name, age, books, newestBook, secret, - obscured, - createdAt, - updatedAt + obscured ]); } @override String toString() { - return "Author(id=$id, name=$name, age=$age, books=$books, newestBook=$newestBook, secret=$secret, obscured=$obscured, createdAt=$createdAt, updatedAt=$updatedAt)"; + return "Author(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, name=$name, age=$age, books=$books, newestBook=$newestBook, secret=$secret, obscured=$obscured)"; } Map toJson() { @@ -217,52 +223,55 @@ class Author extends _Author { @generatedSerializable class Library extends _Library { Library( - {this.id, Map collection, this.createdAt, this.updatedAt}) + {this.id, this.createdAt, this.updatedAt, Map collection}) : this.collection = Map.unmodifiable(collection ?? {}); + /// A unique identifier corresponding to this item. @override String id; + /// The time at which this item was created. + @override + DateTime createdAt; + + /// The last time at which this item was updated. + @override + DateTime updatedAt; + @override final Map collection; - @override - DateTime createdAt; - - @override - DateTime updatedAt; - Library copyWith( {String id, - Map collection, DateTime createdAt, - DateTime updatedAt}) { + DateTime updatedAt, + Map collection}) { return Library( id: id ?? this.id, - collection: collection ?? this.collection, createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); + updatedAt: updatedAt ?? this.updatedAt, + collection: collection ?? this.collection); } bool operator ==(other) { return other is _Library && other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && MapEquality( keys: DefaultEquality(), values: DefaultEquality<_Book>()) - .equals(other.collection, collection) && - other.createdAt == createdAt && - other.updatedAt == updatedAt; + .equals(other.collection, collection); } @override int get hashCode { - return hashObjects([id, collection, createdAt, updatedAt]); + return hashObjects([id, createdAt, updatedAt, collection]); } @override String toString() { - return "Library(id=$id, collection=$collection, createdAt=$createdAt, updatedAt=$updatedAt)"; + return "Library(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, collection=$collection)"; } Map toJson() { @@ -274,17 +283,26 @@ class Library extends _Library { class Bookmark extends _Bookmark { Bookmark(_Book book, {this.id, + this.createdAt, + this.updatedAt, List history, @required this.page, - this.comment, - this.createdAt, - this.updatedAt}) + this.comment}) : this.history = List.unmodifiable(history ?? []), super(book); + /// A unique identifier corresponding to this item. @override String id; + /// The time at which this item was created. + @override + DateTime createdAt; + + /// The last time at which this item was updated. + @override + DateTime updatedAt; + @override final List history; @@ -294,47 +312,41 @@ class Bookmark extends _Bookmark { @override final String comment; - @override - DateTime createdAt; - - @override - DateTime updatedAt; - Bookmark copyWith(_Book book, {String id, + DateTime createdAt, + DateTime updatedAt, List history, int page, - String comment, - DateTime createdAt, - DateTime updatedAt}) { + String comment}) { return Bookmark(book, id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, history: history ?? this.history, page: page ?? this.page, - comment: comment ?? this.comment, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); + comment: comment ?? this.comment); } bool operator ==(other) { return other is _Bookmark && other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && ListEquality(DefaultEquality()) .equals(other.history, history) && other.page == page && - other.comment == comment && - other.createdAt == createdAt && - other.updatedAt == updatedAt; + other.comment == comment; } @override int get hashCode { - return hashObjects([id, history, page, comment, createdAt, updatedAt]); + return hashObjects([id, createdAt, updatedAt, history, page, comment]); } @override String toString() { - return "Bookmark(id=$id, history=$history, page=$page, comment=$comment, createdAt=$createdAt, updatedAt=$updatedAt)"; + return "Bookmark(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, history=$history, page=$page, comment=$comment)"; } Map toJson() { @@ -372,14 +384,6 @@ class BookSerializer extends Codec { static Book fromMap(Map map) { return 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().toList() - : null, - camelCaseString: map['camelCase'] as String, createdAt: map['created_at'] != null ? (map['created_at'] is DateTime ? (map['created_at'] as DateTime) @@ -389,7 +393,15 @@ class BookSerializer extends Codec { ? (map['updated_at'] is DateTime ? (map['updated_at'] as DateTime) : DateTime.parse(map['updated_at'].toString())) - : null); + : null, + 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().toList() + : null, + camelCaseString: map['camelCase'] as String); } static Map toMap(_Book model) { @@ -398,14 +410,14 @@ class BookSerializer extends Codec { } return { 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), '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() + 'camelCase': model.camelCaseString }; } } @@ -413,18 +425,22 @@ class BookSerializer extends Codec { abstract class BookFields { static const List allFields = [ id, + createdAt, + updatedAt, author, title, description, pageCount, notModels, - camelCaseString, - createdAt, - updatedAt + camelCaseString ]; static const String id = 'id'; + static const String createdAt = 'created_at'; + + static const String updatedAt = 'updated_at'; + static const String author = 'author'; static const String title = 'title'; @@ -436,10 +452,6 @@ abstract class BookFields { static const String notModels = 'not_models'; static const String camelCaseString = 'camelCase'; - - static const String createdAt = 'created_at'; - - static const String updatedAt = 'updated_at'; } const AuthorSerializer authorSerializer = AuthorSerializer(); @@ -476,16 +488,6 @@ class AuthorSerializer extends Codec { return Author( id: map['id'] as String, - name: map['name'] as String, - age: map['age'] as int, - books: map['books'] is Iterable - ? List.unmodifiable(((map['books'] as Iterable).whereType()) - .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) @@ -495,7 +497,17 @@ class AuthorSerializer extends Codec { ? (map['updated_at'] is DateTime ? (map['updated_at'] as DateTime) : DateTime.parse(map['updated_at'].toString())) - : null); + : null, + name: map['name'] as String, + age: map['age'] as int, + books: map['books'] is Iterable + ? List.unmodifiable(((map['books'] as Iterable).whereType()) + .map(BookSerializer.fromMap)) + : null, + newestBook: map['newest_book'] != null + ? BookSerializer.fromMap(map['newest_book'] as Map) + : null, + obscured: map['obscured'] as String); } static Map toMap(_Author model) { @@ -512,12 +524,12 @@ class AuthorSerializer extends Codec { return { 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), 'name': model.name, 'age': model.age, 'books': model.books?.map((m) => BookSerializer.toMap(m))?.toList(), - 'newest_book': BookSerializer.toMap(model.newestBook), - 'created_at': model.createdAt?.toIso8601String(), - 'updated_at': model.updatedAt?.toIso8601String() + 'newest_book': BookSerializer.toMap(model.newestBook) }; } } @@ -525,18 +537,22 @@ class AuthorSerializer extends Codec { abstract class AuthorFields { static const List allFields = [ id, + createdAt, + updatedAt, name, age, books, newestBook, secret, - obscured, - createdAt, - updatedAt + obscured ]; static const String id = 'id'; + static const String createdAt = 'created_at'; + + static const String updatedAt = 'updated_at'; + static const String name = 'name'; static const String age = 'age'; @@ -548,10 +564,6 @@ abstract class AuthorFields { static const String secret = 'secret'; static const String obscured = 'obscured'; - - static const String createdAt = 'created_at'; - - static const String updatedAt = 'updated_at'; } const LibrarySerializer librarySerializer = LibrarySerializer(); @@ -580,14 +592,6 @@ class LibrarySerializer extends Codec { static Library fromMap(Map map) { return Library( id: map['id'] as String, - collection: map['collection'] is Map - ? 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) @@ -597,6 +601,14 @@ class LibrarySerializer extends Codec { ? (map['updated_at'] is DateTime ? (map['updated_at'] as DateTime) : DateTime.parse(map['updated_at'].toString())) + : null, + collection: map['collection'] is Map + ? Map.unmodifiable( + (map['collection'] as Map).keys.fold({}, (out, key) { + return out + ..[key] = BookSerializer.fromMap( + ((map['collection'] as Map)[key]) as Map); + })) : null); } @@ -606,11 +618,11 @@ class LibrarySerializer extends Codec { } return { 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), '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() + }) }; } } @@ -618,18 +630,18 @@ class LibrarySerializer extends Codec { abstract class LibraryFields { static const List allFields = [ id, - collection, createdAt, - updatedAt + updatedAt, + collection ]; static const String id = 'id'; - static const String collection = 'collection'; - static const String createdAt = 'created_at'; static const String updatedAt = 'updated_at'; + + static const String collection = 'collection'; } abstract class BookmarkSerializer { @@ -640,11 +652,6 @@ abstract class BookmarkSerializer { return Bookmark(book, id: map['id'] as String, - history: map['history'] is Iterable - ? (map['history'] as Iterable).cast().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) @@ -654,7 +661,12 @@ abstract class BookmarkSerializer { ? (map['updated_at'] is DateTime ? (map['updated_at'] as DateTime) : DateTime.parse(map['updated_at'].toString())) - : null); + : null, + history: map['history'] is Iterable + ? (map['history'] as Iterable).cast().toList() + : null, + page: map['page'] as int, + comment: map['comment'] as String); } static Map toMap(_Bookmark model) { @@ -667,11 +679,11 @@ abstract class BookmarkSerializer { return { 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), 'history': model.history, 'page': model.page, - 'comment': model.comment, - 'created_at': model.createdAt?.toIso8601String(), - 'updated_at': model.updatedAt?.toIso8601String() + 'comment': model.comment }; } } @@ -679,22 +691,22 @@ abstract class BookmarkSerializer { abstract class BookmarkFields { static const List allFields = [ id, + createdAt, + updatedAt, history, page, - comment, - createdAt, - updatedAt + comment ]; static const String id = 'id'; + static const String createdAt = 'created_at'; + + static const String updatedAt = 'updated_at'; + 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'; } diff --git a/angel_serialize_generator/test/models/subclass.dart b/angel_serialize_generator/test/models/subclass.dart new file mode 100644 index 00000000..76e41cf2 --- /dev/null +++ b/angel_serialize_generator/test/models/subclass.dart @@ -0,0 +1,22 @@ +import 'package:angel_serialize/angel_serialize.dart'; +part 'subclass.g.dart'; + +@serializable +class _Animal { + @notNull + String genus; + @notNull + String species; +} + +@serializable +class _Bird extends _Animal { + @DefaultsTo(false) + bool isSparrow; +} + +var saxaulSparrow = Bird( + genus: 'Passer', + species: 'ammodendri', + isSparrow: true, +); diff --git a/angel_serialize_generator/test/models/subclass.g.dart b/angel_serialize_generator/test/models/subclass.g.dart new file mode 100644 index 00000000..32aba631 --- /dev/null +++ b/angel_serialize_generator/test/models/subclass.g.dart @@ -0,0 +1,214 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'subclass.dart'; + +// ************************************************************************** +// JsonModelGenerator +// ************************************************************************** + +@generatedSerializable +class Animal extends _Animal { + Animal({@required this.genus, @required this.species}); + + @override + String genus; + + @override + String species; + + Animal copyWith({String genus, String species}) { + return Animal(genus: genus ?? this.genus, species: species ?? this.species); + } + + bool operator ==(other) { + return other is _Animal && other.genus == genus && other.species == species; + } + + @override + int get hashCode { + return hashObjects([genus, species]); + } + + @override + String toString() { + return "Animal(genus=$genus, species=$species)"; + } + + Map toJson() { + return AnimalSerializer.toMap(this); + } +} + +@generatedSerializable +class Bird extends _Bird { + Bird({@required this.genus, @required this.species, this.isSparrow = false}); + + @override + String genus; + + @override + String species; + + @override + bool isSparrow; + + Bird copyWith({String genus, String species, bool isSparrow}) { + return Bird( + genus: genus ?? this.genus, + species: species ?? this.species, + isSparrow: isSparrow ?? this.isSparrow); + } + + bool operator ==(other) { + return other is _Bird && + other.genus == genus && + other.species == species && + other.isSparrow == isSparrow; + } + + @override + int get hashCode { + return hashObjects([genus, species, isSparrow]); + } + + @override + String toString() { + return "Bird(genus=$genus, species=$species, isSparrow=$isSparrow)"; + } + + Map toJson() { + return BirdSerializer.toMap(this); + } +} + +// ************************************************************************** +// SerializerGenerator +// ************************************************************************** + +const AnimalSerializer animalSerializer = AnimalSerializer(); + +class AnimalEncoder extends Converter { + const AnimalEncoder(); + + @override + Map convert(Animal model) => AnimalSerializer.toMap(model); +} + +class AnimalDecoder extends Converter { + const AnimalDecoder(); + + @override + Animal convert(Map map) => AnimalSerializer.fromMap(map); +} + +class AnimalSerializer extends Codec { + const AnimalSerializer(); + + @override + get encoder => const AnimalEncoder(); + @override + get decoder => const AnimalDecoder(); + static Animal fromMap(Map map) { + if (map['genus'] == null) { + throw FormatException("Missing required field 'genus' on Animal."); + } + + if (map['species'] == null) { + throw FormatException("Missing required field 'species' on Animal."); + } + + return Animal( + genus: map['genus'] as String, species: map['species'] as String); + } + + static Map toMap(_Animal model) { + if (model == null) { + return null; + } + if (model.genus == null) { + throw FormatException("Missing required field 'genus' on Animal."); + } + + if (model.species == null) { + throw FormatException("Missing required field 'species' on Animal."); + } + + return {'genus': model.genus, 'species': model.species}; + } +} + +abstract class AnimalFields { + static const List allFields = [genus, species]; + + static const String genus = 'genus'; + + static const String species = 'species'; +} + +const BirdSerializer birdSerializer = BirdSerializer(); + +class BirdEncoder extends Converter { + const BirdEncoder(); + + @override + Map convert(Bird model) => BirdSerializer.toMap(model); +} + +class BirdDecoder extends Converter { + const BirdDecoder(); + + @override + Bird convert(Map map) => BirdSerializer.fromMap(map); +} + +class BirdSerializer extends Codec { + const BirdSerializer(); + + @override + get encoder => const BirdEncoder(); + @override + get decoder => const BirdDecoder(); + static Bird fromMap(Map map) { + if (map['genus'] == null) { + throw FormatException("Missing required field 'genus' on Bird."); + } + + if (map['species'] == null) { + throw FormatException("Missing required field 'species' on Bird."); + } + + return Bird( + genus: map['genus'] as String, + species: map['species'] as String, + isSparrow: map['is_sparrow'] as bool ?? false); + } + + static Map toMap(_Bird model) { + if (model == null) { + return null; + } + if (model.genus == null) { + throw FormatException("Missing required field 'genus' on Bird."); + } + + if (model.species == null) { + throw FormatException("Missing required field 'species' on Bird."); + } + + return { + 'genus': model.genus, + 'species': model.species, + 'is_sparrow': model.isSparrow + }; + } +} + +abstract class BirdFields { + static const List allFields = [genus, species, isSparrow]; + + static const String genus = 'genus'; + + static const String species = 'species'; + + static const String isSparrow = 'is_sparrow'; +}