From 183418a1f849ee56328ac2528ea1a25abd75174c Mon Sep 17 00:00:00 2001 From: Tobe O <thosakwe@gmail.com> Date: Thu, 7 Feb 2019 22:38:45 -0500 Subject: [PATCH] Fix joins --- angel_orm/CHANGELOG.md | 3 + angel_orm/lib/src/query.dart | 2 +- angel_orm_generator/CHANGELOG.md | 3 + angel_orm_generator/pubspec.yaml | 9 +- angel_orm_generator/test/models/book.g.dart | 127 +++++++++++++++-- angel_orm_generator/test/models/leg.g.dart | 83 +++++++++-- angel_orm_generator/test/models/order.g.dart | 129 +++++++++++++++-- angel_orm_generator/test/models/tree.g.dart | 141 +++++++++++++++++-- 8 files changed, 447 insertions(+), 50 deletions(-) diff --git a/angel_orm/CHANGELOG.md b/angel_orm/CHANGELOG.md index d234d963..48877583 100644 --- a/angel_orm/CHANGELOG.md +++ b/angel_orm/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2.0.0-dev.20 +* Join updates. + # 2.0.0-dev.19 * Implement cast-based `double` support. * Finish `ListSqlExpressionBuilder`. diff --git a/angel_orm/lib/src/query.dart b/angel_orm/lib/src/query.dart index 48f28bd4..ae4c0a60 100644 --- a/angel_orm/lib/src/query.dart +++ b/angel_orm/lib/src/query.dart @@ -280,7 +280,7 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> { return ss; })); _joins.forEach((j) { - var additional = j.additionalFields.map((s) => j.nameFor(s)).toList(); + var additional = j.additionalFields.map(j.nameFor).toList(); // if (!additional.contains(j.fieldName)) // additional.insert(0, j.fieldName); f.addAll(additional); diff --git a/angel_orm_generator/CHANGELOG.md b/angel_orm_generator/CHANGELOG.md index 784084a5..3d3fb7b6 100644 --- a/angel_orm_generator/CHANGELOG.md +++ b/angel_orm_generator/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2.0.0-dev.6 +* Fix bug where an extra field would be inserted into joins and botch the result. + # 2.0.0-dev.5 * Implement cast-based `double` support. * Finish `ListSqlExpressionBuilder`. diff --git a/angel_orm_generator/pubspec.yaml b/angel_orm_generator/pubspec.yaml index 45823504..5cde5602 100644 --- a/angel_orm_generator/pubspec.yaml +++ b/angel_orm_generator/pubspec.yaml @@ -6,7 +6,8 @@ homepage: https://github.com/angel-dart/orm environment: sdk: ">=2.0.0-dev <3.0.0" dependencies: - analyzer: ">=0.27.1 <2.0.0" + # analyzer: ">=0.27.1 <2.0.0" + analyzer: ">=0.27.1 <0.35.0" angel_model: ^1.0.0 angel_serialize: ^2.0.0 angel_orm: ^2.0.0-dev @@ -34,6 +35,6 @@ dev_dependencies: collection: ^1.0.0 postgres: ^1.0.0 test: ^1.0.0 -# dependency_overrides: -# angel_orm: -# path: ../angel_orm +dependency_overrides: + angel_orm: + path: ../angel_orm diff --git a/angel_orm_generator/test/models/book.g.dart b/angel_orm_generator/test/models/book.g.dart index 176d6ef0..b2136cef 100644 --- a/angel_orm_generator/test/models/book.g.dart +++ b/angel_orm_generator/test/models/book.g.dart @@ -2,6 +2,29 @@ part of angel_orm.generator.models.book; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class BookMigration extends Migration { + @override + up(Schema schema) { + schema.create('books', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + table.integer('author_id').references('authors', 'id'); + table.integer('partner_author_id').references('authors', 'id'); + }); + } + + @override + down(Schema schema) { + schema.drop('books'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** @@ -11,6 +34,10 @@ class BookQuery extends Query<Book, BookQueryWhere> { trampoline ??= Set(); trampoline.add(tableName); _where = BookQueryWhere(this); + leftJoin('authors', 'author_id', 'id', + additionalFields: const ['id', 'name', 'created_at', 'updated_at']); + leftJoin('authors', 'partner_author_id', 'id', + additionalFields: const ['id', 'name', 'created_at', 'updated_at']); } @override @@ -30,7 +57,14 @@ class BookQuery extends Query<Book, BookQueryWhere> { @override get fields { - return const ['id']; + return const [ + 'id', + 'author_id', + 'partner_author_id', + 'name', + 'created_at', + 'updated_at' + ]; } @override @@ -45,7 +79,19 @@ class BookQuery extends Query<Book, BookQueryWhere> { static Book parseRow(List row) { if (row.every((x) => x == null)) return null; - var model = Book(id: row[0].toString()); + var model = Book( + id: row[0].toString(), + name: (row[3] as String), + createdAt: (row[4] as DateTime), + updatedAt: (row[5] as DateTime)); + if (row.length > 6) { + model = + model.copyWith(author: AuthorQuery.parseRow(row.skip(6).toList())); + } + if (row.length > 10) { + model = model.copyWith( + partnerAuthor: AuthorQuery.parseRow(row.skip(10).toList())); + } return model; } @@ -57,13 +103,29 @@ class BookQuery extends Query<Book, BookQueryWhere> { class BookQueryWhere extends QueryWhere { BookQueryWhere(BookQuery query) - : id = NumericSqlExpressionBuilder<int>(query, 'id'); + : id = NumericSqlExpressionBuilder<int>(query, 'id'), + authorId = NumericSqlExpressionBuilder<int>(query, 'author_id'), + partnerAuthorId = + NumericSqlExpressionBuilder<int>(query, 'partner_author_id'), + name = StringSqlExpressionBuilder(query, 'name'), + createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), + updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'); final NumericSqlExpressionBuilder<int> id; + final NumericSqlExpressionBuilder<int> authorId; + + final NumericSqlExpressionBuilder<int> partnerAuthorId; + + final StringSqlExpressionBuilder name; + + final DateTimeSqlExpressionBuilder createdAt; + + final DateTimeSqlExpressionBuilder updatedAt; + @override get expressionBuilders { - return [id]; + return [id, authorId, partnerAuthorId, name, createdAt, updatedAt]; } } @@ -78,7 +140,42 @@ class BookQueryValues extends MapQueryValues { } set id(int value) => values['id'] = value; - void copyFrom(Book model) {} + int get authorId { + return (values['author_id'] as int); + } + + set authorId(int value) => values['author_id'] = value; + int get partnerAuthorId { + return (values['partner_author_id'] as int); + } + + set partnerAuthorId(int value) => values['partner_author_id'] = value; + String get name { + return (values['name'] as String); + } + + set name(String value) => values['name'] = value; + DateTime get createdAt { + return (values['created_at'] as DateTime); + } + + set createdAt(DateTime value) => values['created_at'] = value; + DateTime get updatedAt { + return (values['updated_at'] as DateTime); + } + + set updatedAt(DateTime value) => values['updated_at'] = value; + void copyFrom(Book model) { + name = model.name; + createdAt = model.createdAt; + updatedAt = model.updatedAt; + if (model.author != null) { + values['author_id'] = int.parse(model.author.id); + } + if (model.partnerAuthor != null) { + values['partner_author_id'] = int.parse(model.partnerAuthor.id); + } + } } // ************************************************************************** @@ -99,10 +196,10 @@ class Book extends _Book { final String id; @override - final dynamic author; + final Author author; @override - final dynamic partnerAuthor; + final Author partnerAuthor; @override final String name; @@ -115,8 +212,8 @@ class Book extends _Book { Book copyWith( {String id, - dynamic author, - dynamic partnerAuthor, + Author author, + Author partnerAuthor, String name, DateTime createdAt, DateTime updatedAt}) { @@ -157,8 +254,12 @@ abstract class BookSerializer { static Book fromMap(Map map) { return new Book( id: map['id'] as String, - author: map['author'] as dynamic, - partnerAuthor: map['partner_author'] as dynamic, + author: map['author'] != null + ? AuthorSerializer.fromMap(map['author'] as Map) + : null, + partnerAuthor: map['partner_author'] != null + ? AuthorSerializer.fromMap(map['partner_author'] as Map) + : null, name: map['name'] as String, createdAt: map['created_at'] != null ? (map['created_at'] is DateTime @@ -178,8 +279,8 @@ abstract class BookSerializer { } return { 'id': model.id, - 'author': model.author, - 'partner_author': model.partnerAuthor, + 'author': AuthorSerializer.toMap(model.author), + 'partner_author': AuthorSerializer.toMap(model.partnerAuthor), 'name': model.name, 'created_at': model.createdAt?.toIso8601String(), 'updated_at': model.updatedAt?.toIso8601String() diff --git a/angel_orm_generator/test/models/leg.g.dart b/angel_orm_generator/test/models/leg.g.dart index 36cc27c4..14a91b01 100644 --- a/angel_orm_generator/test/models/leg.g.dart +++ b/angel_orm_generator/test/models/leg.g.dart @@ -2,6 +2,27 @@ part of angel_orm_generator.test.models.leg; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class LegMigration extends Migration { + @override + up(Schema schema) { + schema.create('legs', (table) { + table.serial('id')..primaryKey(); + table.varChar('name'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('legs'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** @@ -11,6 +32,13 @@ class LegQuery extends Query<Leg, LegQueryWhere> { trampoline ??= Set(); trampoline.add(tableName); _where = LegQueryWhere(this); + leftJoin('feet', 'id', 'leg_id', additionalFields: const [ + 'id', + 'leg_id', + 'n_toes', + 'created_at', + 'updated_at' + ]); } @override @@ -30,7 +58,7 @@ class LegQuery extends Query<Leg, LegQueryWhere> { @override get fields { - return const ['id']; + return const ['id', 'name', 'created_at', 'updated_at']; } @override @@ -45,7 +73,14 @@ class LegQuery extends Query<Leg, LegQueryWhere> { static Leg parseRow(List row) { if (row.every((x) => x == null)) return null; - var model = Leg(id: row[0].toString()); + var model = Leg( + id: row[0].toString(), + name: (row[1] as String), + createdAt: (row[2] as DateTime), + updatedAt: (row[3] as DateTime)); + if (row.length > 4) { + model = model.copyWith(foot: FootQuery.parseRow(row.skip(4).toList())); + } return model; } @@ -57,13 +92,22 @@ class LegQuery extends Query<Leg, LegQueryWhere> { class LegQueryWhere extends QueryWhere { LegQueryWhere(LegQuery query) - : id = NumericSqlExpressionBuilder<int>(query, 'id'); + : id = NumericSqlExpressionBuilder<int>(query, 'id'), + name = StringSqlExpressionBuilder(query, 'name'), + createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), + updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'); final NumericSqlExpressionBuilder<int> id; + final StringSqlExpressionBuilder name; + + final DateTimeSqlExpressionBuilder createdAt; + + final DateTimeSqlExpressionBuilder updatedAt; + @override get expressionBuilders { - return [id]; + return [id, name, createdAt, updatedAt]; } } @@ -78,7 +122,26 @@ class LegQueryValues extends MapQueryValues { } set id(int value) => values['id'] = value; - void copyFrom(Leg model) {} + String get name { + return (values['name'] as String); + } + + set name(String value) => values['name'] = value; + DateTime get createdAt { + return (values['created_at'] as DateTime); + } + + set createdAt(DateTime value) => values['created_at'] = value; + DateTime get updatedAt { + return (values['updated_at'] as DateTime); + } + + set updatedAt(DateTime value) => values['updated_at'] = value; + void copyFrom(Leg model) { + name = model.name; + createdAt = model.createdAt; + updatedAt = model.updatedAt; + } } // ************************************************************************** @@ -93,7 +156,7 @@ class Leg extends _Leg { final String id; @override - final dynamic foot; + final Foot foot; @override final String name; @@ -106,7 +169,7 @@ class Leg extends _Leg { Leg copyWith( {String id, - dynamic foot, + Foot foot, String name, DateTime createdAt, DateTime updatedAt}) { @@ -145,7 +208,9 @@ abstract class LegSerializer { static Leg fromMap(Map map) { return new Leg( id: map['id'] as String, - foot: map['foot'] as dynamic, + foot: map['foot'] != null + ? FootSerializer.fromMap(map['foot'] as Map) + : null, name: map['name'] as String, createdAt: map['created_at'] != null ? (map['created_at'] is DateTime @@ -165,7 +230,7 @@ abstract class LegSerializer { } return { 'id': model.id, - 'foot': model.foot, + 'foot': FootSerializer.toMap(model.foot), 'name': model.name, 'created_at': model.createdAt?.toIso8601String(), 'updated_at': model.updatedAt?.toIso8601String() diff --git a/angel_orm_generator/test/models/order.g.dart b/angel_orm_generator/test/models/order.g.dart index e009f8de..3d7c2c9e 100644 --- a/angel_orm_generator/test/models/order.g.dart +++ b/angel_orm_generator/test/models/order.g.dart @@ -2,6 +2,30 @@ part of angel_orm_generator.test.models.order; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class OrderMigration extends Migration { + @override + up(Schema schema) { + schema.create('orders', (table) { + table.serial('id')..primaryKey(); + table.integer('employee_id'); + table.timeStamp('order_date'); + table.integer('shipper_id'); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + table.integer('customer_id').references('customers', 'id'); + }); + } + + @override + down(Schema schema) { + schema.drop('orders'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** @@ -11,6 +35,8 @@ class OrderQuery extends Query<Order, OrderQueryWhere> { trampoline ??= Set(); trampoline.add(tableName); _where = OrderQueryWhere(this); + leftJoin('customers', 'customer_id', 'id', + additionalFields: const ['id', 'created_at', 'updated_at']); } @override @@ -30,7 +56,15 @@ class OrderQuery extends Query<Order, OrderQueryWhere> { @override get fields { - return const ['id']; + return const [ + 'id', + 'customer_id', + 'employee_id', + 'order_date', + 'shipper_id', + 'created_at', + 'updated_at' + ]; } @override @@ -45,7 +79,17 @@ class OrderQuery extends Query<Order, OrderQueryWhere> { static Order parseRow(List row) { if (row.every((x) => x == null)) return null; - var model = Order(id: row[0].toString()); + var model = Order( + id: row[0].toString(), + employeeId: (row[2] as int), + orderDate: (row[3] as DateTime), + shipperId: (row[4] as int), + createdAt: (row[5] as DateTime), + updatedAt: (row[6] as DateTime)); + if (row.length > 7) { + model = model.copyWith( + customer: CustomerQuery.parseRow(row.skip(7).toList())); + } return model; } @@ -57,13 +101,39 @@ class OrderQuery extends Query<Order, OrderQueryWhere> { class OrderQueryWhere extends QueryWhere { OrderQueryWhere(OrderQuery query) - : id = NumericSqlExpressionBuilder<int>(query, 'id'); + : id = NumericSqlExpressionBuilder<int>(query, 'id'), + customerId = NumericSqlExpressionBuilder<int>(query, 'customer_id'), + employeeId = NumericSqlExpressionBuilder<int>(query, 'employee_id'), + orderDate = DateTimeSqlExpressionBuilder(query, 'order_date'), + shipperId = NumericSqlExpressionBuilder<int>(query, 'shipper_id'), + createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), + updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'); final NumericSqlExpressionBuilder<int> id; + final NumericSqlExpressionBuilder<int> customerId; + + final NumericSqlExpressionBuilder<int> employeeId; + + final DateTimeSqlExpressionBuilder orderDate; + + final NumericSqlExpressionBuilder<int> shipperId; + + final DateTimeSqlExpressionBuilder createdAt; + + final DateTimeSqlExpressionBuilder updatedAt; + @override get expressionBuilders { - return [id]; + return [ + id, + customerId, + employeeId, + orderDate, + shipperId, + createdAt, + updatedAt + ]; } } @@ -78,7 +148,46 @@ class OrderQueryValues extends MapQueryValues { } set id(int value) => values['id'] = value; - void copyFrom(Order model) {} + int get customerId { + return (values['customer_id'] as int); + } + + set customerId(int value) => values['customer_id'] = value; + int get employeeId { + return (values['employee_id'] as int); + } + + set employeeId(int value) => values['employee_id'] = value; + DateTime get orderDate { + return (values['order_date'] as DateTime); + } + + set orderDate(DateTime value) => values['order_date'] = value; + int get shipperId { + return (values['shipper_id'] as int); + } + + set shipperId(int value) => values['shipper_id'] = value; + DateTime get createdAt { + return (values['created_at'] as DateTime); + } + + set createdAt(DateTime value) => values['created_at'] = value; + DateTime get updatedAt { + return (values['updated_at'] as DateTime); + } + + set updatedAt(DateTime value) => values['updated_at'] = value; + void copyFrom(Order model) { + employeeId = model.employeeId; + orderDate = model.orderDate; + shipperId = model.shipperId; + createdAt = model.createdAt; + updatedAt = model.updatedAt; + if (model.customer != null) { + values['customer_id'] = int.parse(model.customer.id); + } + } } // ************************************************************************** @@ -100,7 +209,7 @@ class Order extends _Order { final String id; @override - final dynamic customer; + final Customer customer; @override final int employeeId; @@ -119,7 +228,7 @@ class Order extends _Order { Order copyWith( {String id, - dynamic customer, + Customer customer, int employeeId, DateTime orderDate, int shipperId, @@ -165,7 +274,9 @@ abstract class OrderSerializer { static Order fromMap(Map map) { return new Order( id: map['id'] as String, - customer: map['customer'] as dynamic, + customer: map['customer'] != null + ? CustomerSerializer.fromMap(map['customer'] as Map) + : null, employeeId: map['employee_id'] as int, orderDate: map['order_date'] != null ? (map['order_date'] is DateTime @@ -191,7 +302,7 @@ abstract class OrderSerializer { } return { 'id': model.id, - 'customer': model.customer, + 'customer': CustomerSerializer.toMap(model.customer), 'employee_id': model.employeeId, 'order_date': model.orderDate?.toIso8601String(), 'shipper_id': model.shipperId, diff --git a/angel_orm_generator/test/models/tree.g.dart b/angel_orm_generator/test/models/tree.g.dart index 4de935c7..3873006e 100644 --- a/angel_orm_generator/test/models/tree.g.dart +++ b/angel_orm_generator/test/models/tree.g.dart @@ -2,6 +2,27 @@ part of angel_orm_generator.test.models.tree; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class TreeMigration extends Migration { + @override + up(Schema schema) { + schema.create('trees', (table) { + table.serial('id')..primaryKey(); + table.declare('rings', ColumnType('smallint')); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + }); + } + + @override + down(Schema schema) { + schema.drop('trees'); + } +} + // ************************************************************************** // OrmGenerator // ************************************************************************** @@ -11,6 +32,14 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> { trampoline ??= Set(); trampoline.add(tableName); _where = TreeQueryWhere(this); + leftJoin(FruitQuery(trampoline: trampoline), 'id', 'tree_id', + additionalFields: const [ + 'id', + 'tree_id', + 'common_name', + 'created_at', + 'updated_at' + ]); } @override @@ -30,7 +59,7 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> { @override get fields { - return const ['id', 'rings']; + return const ['id', 'rings', 'created_at', 'updated_at']; } @override @@ -45,7 +74,17 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> { static Tree parseRow(List row) { if (row.every((x) => x == null)) return null; - var model = Tree(id: row[0].toString(), rings: (row[1] as int)); + var model = Tree( + id: row[0].toString(), + rings: (row[1] as int), + createdAt: (row[2] as DateTime), + updatedAt: (row[3] as DateTime)); + if (row.length > 4) { + model = model.copyWith( + fruits: [FruitQuery.parseRow(row.skip(4).toList())] + .where((x) => x != null) + .toList()); + } return model; } @@ -53,20 +92,83 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> { deserialize(List row) { return parseRow(row); } + + @override + get(QueryExecutor executor) { + return super.get(executor).then((result) { + return result.fold<List<Tree>>([], (out, model) { + var idx = out.indexWhere((m) => m.id == model.id); + + if (idx == -1) { + return out..add(model); + } else { + var l = out[idx]; + return out + ..[idx] = l.copyWith( + fruits: List<Fruit>.from(l.fruits ?? []) + ..addAll(model.fruits ?? [])); + } + }); + }); + } + + @override + update(QueryExecutor executor) { + return super.update(executor).then((result) { + return result.fold<List<Tree>>([], (out, model) { + var idx = out.indexWhere((m) => m.id == model.id); + + if (idx == -1) { + return out..add(model); + } else { + var l = out[idx]; + return out + ..[idx] = l.copyWith( + fruits: List<Fruit>.from(l.fruits ?? []) + ..addAll(model.fruits ?? [])); + } + }); + }); + } + + @override + delete(QueryExecutor executor) { + return super.delete(executor).then((result) { + return result.fold<List<Tree>>([], (out, model) { + var idx = out.indexWhere((m) => m.id == model.id); + + if (idx == -1) { + return out..add(model); + } else { + var l = out[idx]; + return out + ..[idx] = l.copyWith( + fruits: List<Fruit>.from(l.fruits ?? []) + ..addAll(model.fruits ?? [])); + } + }); + }); + } } class TreeQueryWhere extends QueryWhere { TreeQueryWhere(TreeQuery query) : id = NumericSqlExpressionBuilder<int>(query, 'id'), - rings = NumericSqlExpressionBuilder<int>(query, 'rings'); + rings = NumericSqlExpressionBuilder<int>(query, 'rings'), + createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), + updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'); final NumericSqlExpressionBuilder<int> id; final NumericSqlExpressionBuilder<int> rings; + final DateTimeSqlExpressionBuilder createdAt; + + final DateTimeSqlExpressionBuilder updatedAt; + @override get expressionBuilders { - return [id, rings]; + return [id, rings, createdAt, updatedAt]; } } @@ -86,8 +188,20 @@ class TreeQueryValues extends MapQueryValues { } set rings(int value) => values['rings'] = value; + DateTime get createdAt { + return (values['created_at'] as DateTime); + } + + set createdAt(DateTime value) => values['created_at'] = value; + DateTime get updatedAt { + return (values['updated_at'] as DateTime); + } + + set updatedAt(DateTime value) => values['updated_at'] = value; void copyFrom(Tree model) { rings = model.rings; + createdAt = model.createdAt; + updatedAt = model.updatedAt; } } @@ -98,11 +212,7 @@ class TreeQueryValues extends MapQueryValues { @generatedSerializable class Tree extends _Tree { Tree( - {this.id, - this.rings, - List<dynamic> fruits, - this.createdAt, - this.updatedAt}) + {this.id, this.rings, List<Fruit> fruits, this.createdAt, this.updatedAt}) : this.fruits = new List.unmodifiable(fruits ?? []); @override @@ -112,7 +222,7 @@ class Tree extends _Tree { final int rings; @override - final List<dynamic> fruits; + final List<Fruit> fruits; @override final DateTime createdAt; @@ -123,7 +233,7 @@ class Tree extends _Tree { Tree copyWith( {String id, int rings, - List<dynamic> fruits, + List<Fruit> fruits, DateTime createdAt, DateTime updatedAt}) { return new Tree( @@ -138,7 +248,7 @@ class Tree extends _Tree { return other is _Tree && other.id == id && other.rings == rings && - const ListEquality<dynamic>(const DefaultEquality()) + const ListEquality<Fruit>(const DefaultEquality<Fruit>()) .equals(other.fruits, fruits) && other.createdAt == createdAt && other.updatedAt == updatedAt; @@ -164,7 +274,10 @@ abstract class TreeSerializer { id: map['id'] as String, rings: map['rings'] as int, fruits: map['fruits'] is Iterable - ? (map['fruits'] as Iterable).cast<dynamic>().toList() + ? new List.unmodifiable( + ((map['fruits'] as Iterable).where((x) => x is Map)) + .cast<Map>() + .map(FruitSerializer.fromMap)) : null, createdAt: map['created_at'] != null ? (map['created_at'] is DateTime @@ -185,7 +298,7 @@ abstract class TreeSerializer { return { 'id': model.id, 'rings': model.rings, - 'fruits': model.fruits, + 'fruits': model.fruits?.map((m) => FruitSerializer.toMap(m))?.toList(), 'created_at': model.createdAt?.toIso8601String(), 'updated_at': model.updatedAt?.toIso8601String() };