1.0.0-alpha
This commit is contained in:
parent
328224fc10
commit
1ec4b89707
9 changed files with 220 additions and 149 deletions
47
README.md
47
README.md
|
@ -68,15 +68,8 @@ part 'book.g.dart';
|
|||
|
||||
@serializable
|
||||
abstract class _Book extends Model {
|
||||
@override
|
||||
String id;
|
||||
String author, title, description;
|
||||
|
||||
@Alias('page_count')
|
||||
int pageCount;
|
||||
|
||||
@override
|
||||
DateTime createdAt, updatedAt;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -129,15 +122,15 @@ class Book extends _Book {
|
|||
title: data['title'],
|
||||
description: data['description'],
|
||||
pageCount: data['page_count'],
|
||||
createdAt: data['createdAt'] is DateTime
|
||||
? data['createdAt']
|
||||
: (data['createdAt'] is String
|
||||
? DateTime.parse(data['createdAt'])
|
||||
createdAt: data['created_at'] is DateTime
|
||||
? data['created_at']
|
||||
: (data['created_at'] is String
|
||||
? DateTime.parse(data['created_at'])
|
||||
: null),
|
||||
updatedAt: data['updatedAt'] is DateTime
|
||||
? data['updatedAt']
|
||||
: (data['updatedAt'] is String
|
||||
? DateTime.parse(data['updatedAt'])
|
||||
updatedAt: data['updated_at'] is DateTime
|
||||
? data['updated_at']
|
||||
: (data['updated_at'] is String
|
||||
? DateTime.parse(data['updated_at'])
|
||||
: null));
|
||||
}
|
||||
|
||||
|
@ -147,8 +140,8 @@ class Book extends _Book {
|
|||
'title': title,
|
||||
'description': description,
|
||||
'page_count': pageCount,
|
||||
'createdAt': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
'created_at': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
};
|
||||
|
||||
static Book parse(Map map) => new Book.fromJson(map);
|
||||
|
@ -160,6 +153,9 @@ 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
|
||||
for a field.
|
||||
|
||||
By default `angel_serialize` will transform keys into snake case. Use `Alias` to
|
||||
provide a custom name, or pass `autoSnakeCaseNames`: `false` to the builder;
|
||||
|
||||
```dart
|
||||
@serializable
|
||||
abstract class _Spy extends Model {
|
||||
|
@ -169,8 +165,10 @@ abstract class _Spy extends Model {
|
|||
/// it will use 'agency_id'.
|
||||
///
|
||||
/// Hooray!
|
||||
@Alias('agency_id')
|
||||
String agencyId;
|
||||
|
||||
@Alias('foo')
|
||||
String someOtherField;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -200,10 +198,15 @@ Be sure to use the underscored name of a child class (ex. `_Book`):
|
|||
@serializable
|
||||
abstract class _Author extends Model {
|
||||
List<_Book> books;
|
||||
|
||||
@Alias('newest_book')
|
||||
_Book newestBook;
|
||||
|
||||
Map<String, _Book> booksByIsbn;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
The caveat here is that nested classes must be written in the same file. `source_gen`
|
||||
otherwise will not be able to resolve the nested type.
|
||||
|
||||
# ID and Dates
|
||||
This package will automatically generate `id`, `createdAt`, and `updatedAt` fields for you,
|
||||
in the style of an Angel `Model`. To disable this, set `autoIdAndDates` to `false` in the
|
||||
builder constructor.
|
79
lib/build_context.dart
Normal file
79
lib/build_context.dart
Normal file
|
@ -0,0 +1,79 @@
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:source_gen/src/annotation.dart';
|
||||
import 'src/find_annotation.dart';
|
||||
import 'context.dart';
|
||||
|
||||
// TODO: Should add id, createdAt, updatedAt...
|
||||
BuildContext buildContext(
|
||||
ClassElement clazz,
|
||||
Serializable annotation,
|
||||
BuildStep buildStep,
|
||||
Resolver resolver,
|
||||
bool autoSnakeCaseNames,
|
||||
bool autoIdAndDateFields,
|
||||
{bool heedExclude: true}) {
|
||||
var ctx = new BuildContext(annotation,
|
||||
originalClassName: clazz.name,
|
||||
sourceFilename: p.basename(buildStep.inputId.path));
|
||||
var lib = resolver.getLibrary(buildStep.inputId);
|
||||
List<String> fieldNames = [];
|
||||
|
||||
for (var field in clazz.fields) {
|
||||
if (field.getter != null && field.setter != null) {
|
||||
fieldNames.add(field.name);
|
||||
// Skip if annotated with @exclude
|
||||
var excludeAnnotation = field.metadata.firstWhere(
|
||||
(ann) => matchAnnotation(Exclude, ann),
|
||||
orElse: () => null);
|
||||
if (excludeAnnotation != null) continue;
|
||||
// Check for alias
|
||||
var alias = findAnnotation<Alias>(field, Alias);
|
||||
|
||||
if (alias?.name?.isNotEmpty == true) {
|
||||
ctx.aliases[field.name] = alias.name;
|
||||
} else if (autoSnakeCaseNames != false) {
|
||||
ctx.aliases[field.name] = new ReCase(field.name).snakeCase;
|
||||
}
|
||||
|
||||
ctx.fields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoIdAndDateFields != false) {
|
||||
if (!fieldNames.contains('id')) {
|
||||
var idField = new _ShimField('id', lib.context.typeProvider.stringType);
|
||||
ctx.fields.insert(0, idField);
|
||||
ctx.shimmed['id'] = true;
|
||||
}
|
||||
|
||||
DartType dateTime;
|
||||
['createdAt', 'updatedAt'].forEach((key) {
|
||||
if (!fieldNames.contains(key)) {
|
||||
if (dateTime == null) {
|
||||
var coreLib = resolver.libraries.singleWhere((lib) => lib.isDartCore);
|
||||
var dt = coreLib.getType('DateTime');
|
||||
dateTime = dt.type;
|
||||
}
|
||||
|
||||
var field = new _ShimField(key, dateTime);
|
||||
ctx.aliases[key] = new ReCase(key).snakeCase;
|
||||
ctx.fields.add(field);
|
||||
ctx.shimmed[key] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
class _ShimField extends FieldElementImpl {
|
||||
@override
|
||||
final DartType type;
|
||||
_ShimField(String name, this.type) : super(name, -1);
|
||||
}
|
|
@ -4,70 +4,57 @@ import 'package:analyzer/dart/element/type.dart';
|
|||
import 'package:build/build.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:code_builder/dart/core.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:source_gen/src/annotation.dart';
|
||||
import 'package:source_gen/source_gen.dart';
|
||||
import 'angel_serialize.dart';
|
||||
import 'build_context.dart';
|
||||
import 'context.dart';
|
||||
|
||||
class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
||||
const JsonModelGenerator();
|
||||
final bool autoSnakeCaseNames;
|
||||
final bool autoIdAndDateFields;
|
||||
const JsonModelGenerator(
|
||||
{this.autoSnakeCaseNames: true, this.autoIdAndDateFields: true});
|
||||
|
||||
@override
|
||||
Future<String> generateForAnnotatedElement(
|
||||
Element element, Serializable annotation, BuildStep buildStep) async {
|
||||
if (element.kind != ElementKind.CLASS)
|
||||
throw 'Only classes can be annotated with a @Serializable() annotation.';
|
||||
var lib = generateSerializerLibrary(element);
|
||||
var ctx = buildContext(
|
||||
element,
|
||||
annotation,
|
||||
buildStep,
|
||||
await buildStep.resolver,
|
||||
autoSnakeCaseNames != false,
|
||||
autoIdAndDateFields != false);
|
||||
var lib = generateSerializerLibrary(ctx);
|
||||
return prettyToSource(lib.buildAst());
|
||||
}
|
||||
|
||||
LibraryBuilder generateSerializerLibrary(ClassElement clazz) {
|
||||
LibraryBuilder generateSerializerLibrary(BuildContext ctx) {
|
||||
var lib = new LibraryBuilder();
|
||||
lib.addMember(generateBaseModelClass(clazz));
|
||||
lib.addMember(generateBaseModelClass(ctx));
|
||||
return lib;
|
||||
}
|
||||
|
||||
ClassBuilder generateBaseModelClass(ClassElement clazz) {
|
||||
if (!clazz.name.startsWith('_'))
|
||||
ClassBuilder generateBaseModelClass(BuildContext ctx) {
|
||||
if (!ctx.originalClassName.startsWith('_'))
|
||||
throw 'Classes annotated with @Serializable() must have names starting with a leading underscore.';
|
||||
|
||||
var genClassName = clazz.name.substring(1);
|
||||
var genClass =
|
||||
new ClassBuilder(genClassName, asExtends: new TypeBuilder(clazz.name));
|
||||
Map<String, DartType> fields = {};
|
||||
Map<String, String> aliases = {};
|
||||
|
||||
// Find all fields
|
||||
for (var field in clazz.fields) {
|
||||
// Skip if annotated with @exclude
|
||||
var excludeAnnotation = field.metadata.firstWhere(
|
||||
(ann) => matchAnnotation(Exclude, ann),
|
||||
orElse: () => null);
|
||||
|
||||
if (excludeAnnotation == null) {
|
||||
// Register the field
|
||||
fields[field.name] = field.type;
|
||||
|
||||
// Search for Alias
|
||||
var aliasAnnotation = field.metadata.firstWhere(
|
||||
(ann) => matchAnnotation(Alias, ann),
|
||||
orElse: () => null);
|
||||
if (aliasAnnotation != null) {
|
||||
var alias = instantiateAnnotation(aliasAnnotation) as Alias;
|
||||
aliases[field.name] = alias.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
var genClassName = ctx.modelClassName;
|
||||
var genClass = new ClassBuilder(genClassName,
|
||||
asExtends: new TypeBuilder(ctx.originalClassName));
|
||||
|
||||
// Now, add all fields to the base class
|
||||
clazz.fields.forEach((field) {
|
||||
ctx.fields.forEach((field) {
|
||||
genClass.addField(
|
||||
varField(field.name, type: new TypeBuilder(field.type.displayName))
|
||||
..addAnnotation(reference('override')));
|
||||
});
|
||||
|
||||
// Create convenience constructor
|
||||
var convenienceConstructor = constructor(clazz.fields.map((field) {
|
||||
var convenienceConstructor = constructor(ctx.fields.map((field) {
|
||||
return thisField(named(parameter(field.name)));
|
||||
}));
|
||||
genClass.addConstructor(convenienceConstructor);
|
||||
|
@ -75,20 +62,19 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
// Create toJson
|
||||
Map<String, ExpressionBuilder> toJsonFields = {};
|
||||
|
||||
fields.forEach((fieldName, type) {
|
||||
var resolvedName =
|
||||
aliases.containsKey(fieldName) ? aliases[fieldName] : fieldName;
|
||||
ctx.fields.forEach((field) {
|
||||
var resolvedName = ctx.resolveFieldName(field.name);
|
||||
ExpressionBuilder value;
|
||||
|
||||
// DateTime
|
||||
if (type.name == 'DateTime') {
|
||||
value = reference(fieldName).equals(literal(null)).ternary(
|
||||
literal(null), reference(fieldName).invoke('toIso8601String', []));
|
||||
if (field.type.name == 'DateTime') {
|
||||
value = reference(field.name).equals(literal(null)).ternary(
|
||||
literal(null), reference(field.name).invoke('toIso8601String', []));
|
||||
}
|
||||
|
||||
// Anything else
|
||||
else {
|
||||
value = reference(fieldName);
|
||||
value = reference(field.name);
|
||||
}
|
||||
|
||||
toJsonFields[resolvedName] = value;
|
||||
|
@ -106,12 +92,11 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
var fromJson = new ConstructorBuilder(name: 'fromJson', asFactory: true);
|
||||
fromJson.addPositional(parameter('data', [new TypeBuilder('Map')]));
|
||||
var namedParams =
|
||||
fields.keys.fold<Map<String, ExpressionBuilder>>({}, (out, fieldName) {
|
||||
var resolvedName =
|
||||
aliases.containsKey(fieldName) ? aliases[fieldName] : fieldName;
|
||||
ctx.fields.fold<Map<String, ExpressionBuilder>>({}, (out, field) {
|
||||
var resolvedName = ctx.resolveFieldName(field.name);
|
||||
var mapKey = reference('data')[literal(resolvedName)];
|
||||
ExpressionBuilder value = mapKey;
|
||||
var type = fields[fieldName];
|
||||
var type = field.type;
|
||||
|
||||
// DateTime
|
||||
if (type.name == 'DateTime') {
|
||||
|
@ -256,7 +241,7 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
}
|
||||
}
|
||||
|
||||
return out..[fieldName] = value;
|
||||
return out..[field.name] = value;
|
||||
});
|
||||
fromJson.addStatement(new TypeBuilder(genClassName)
|
||||
.newInstance([], named: namedParams).asReturn());
|
||||
|
|
24
lib/context.dart
Normal file
24
lib/context.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'angel_serialize.dart';
|
||||
|
||||
class BuildContext {
|
||||
final Map<String, String> aliases = {};
|
||||
final Map<String, bool> shimmed = {};
|
||||
final String originalClassName, sourceFilename;
|
||||
// Todo: We can use analyzer to copy straight from Model class
|
||||
final List<FieldElement> fields = [];
|
||||
final Serializable annotation;
|
||||
String primaryKeyName = 'id';
|
||||
|
||||
BuildContext(this.annotation, {this.originalClassName, this.sourceFilename});
|
||||
|
||||
String get modelClassName => originalClassName.startsWith('_')
|
||||
? originalClassName.substring(1)
|
||||
: originalClassName;
|
||||
|
||||
String get queryClassName => modelClassName + 'Query';
|
||||
String get whereClassName => queryClassName + 'Where';
|
||||
|
||||
String resolveFieldName(String name) =>
|
||||
aliases.containsKey(name) ? aliases[name] : name;
|
||||
}
|
8
lib/src/find_annotation.dart
Normal file
8
lib/src/find_annotation.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:source_gen/src/annotation.dart';
|
||||
|
||||
T findAnnotation<T>(FieldElement field, Type outType) {
|
||||
var first = field.metadata
|
||||
.firstWhere((ann) => matchAnnotation(outType, ann), orElse: () => null);
|
||||
return first == null ? null : instantiateAnnotation(first);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_serialize
|
||||
version: 0.0.0
|
||||
version: 1.0.0-alpha
|
||||
description: Model serialization generators.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/serialize
|
||||
|
|
|
@ -36,8 +36,8 @@ main() {
|
|||
expect(
|
||||
serializedDeathlyHallows['description'], deathlyHallows.description);
|
||||
expect(serializedDeathlyHallows['page_count'], deathlyHallows.pageCount);
|
||||
expect(serializedDeathlyHallows['createdAt'], isNull);
|
||||
expect(serializedDeathlyHallows['updatedAt'],
|
||||
expect(serializedDeathlyHallows['created_at'], isNull);
|
||||
expect(serializedDeathlyHallows['updated_at'],
|
||||
deathlyHallows.updatedAt.toIso8601String());
|
||||
});
|
||||
|
||||
|
|
|
@ -6,45 +6,21 @@ part 'book.g.dart';
|
|||
|
||||
@serializable
|
||||
abstract class _Book extends Model {
|
||||
@override
|
||||
String id;
|
||||
String author, title, description;
|
||||
|
||||
@Alias('page_count')
|
||||
int pageCount;
|
||||
|
||||
@override
|
||||
DateTime createdAt, updatedAt;
|
||||
}
|
||||
|
||||
@serializable
|
||||
abstract class _Author extends Model {
|
||||
@override
|
||||
String id;
|
||||
|
||||
String name;
|
||||
|
||||
int age;
|
||||
|
||||
@override
|
||||
DateTime createdAt, updatedAt;
|
||||
|
||||
List<_Book> books;
|
||||
|
||||
@Alias('newest_book')
|
||||
_Book newestBook;
|
||||
|
||||
@exclude
|
||||
String secret;
|
||||
}
|
||||
|
||||
@serializable
|
||||
abstract class _Library extends Model {
|
||||
@override
|
||||
String id;
|
||||
|
||||
@override
|
||||
DateTime createdAt, updatedAt;
|
||||
|
||||
Map<String, _Book> collection;
|
||||
}
|
|
@ -45,15 +45,15 @@ class Book extends _Book {
|
|||
title: data['title'],
|
||||
description: data['description'],
|
||||
pageCount: data['page_count'],
|
||||
createdAt: data['createdAt'] is DateTime
|
||||
? data['createdAt']
|
||||
: (data['createdAt'] is String
|
||||
? DateTime.parse(data['createdAt'])
|
||||
createdAt: data['created_at'] is DateTime
|
||||
? data['created_at']
|
||||
: (data['created_at'] is String
|
||||
? DateTime.parse(data['created_at'])
|
||||
: null),
|
||||
updatedAt: data['updatedAt'] is DateTime
|
||||
? data['updatedAt']
|
||||
: (data['updatedAt'] is String
|
||||
? DateTime.parse(data['updatedAt'])
|
||||
updatedAt: data['updated_at'] is DateTime
|
||||
? data['updated_at']
|
||||
: (data['updated_at'] is String
|
||||
? DateTime.parse(data['updated_at'])
|
||||
: null));
|
||||
}
|
||||
|
||||
|
@ -63,8 +63,8 @@ class Book extends _Book {
|
|||
'title': title,
|
||||
'description': description,
|
||||
'page_count': pageCount,
|
||||
'createdAt': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
'created_at': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
};
|
||||
|
||||
static Book parse(Map map) => new Book.fromJson(map);
|
||||
|
@ -85,12 +85,6 @@ class Author extends _Author {
|
|||
@override
|
||||
int age;
|
||||
|
||||
@override
|
||||
DateTime createdAt;
|
||||
|
||||
@override
|
||||
DateTime updatedAt;
|
||||
|
||||
@override
|
||||
List<_Book> books;
|
||||
|
||||
|
@ -98,33 +92,25 @@ class Author extends _Author {
|
|||
_Book newestBook;
|
||||
|
||||
@override
|
||||
String secret;
|
||||
DateTime createdAt;
|
||||
|
||||
@override
|
||||
DateTime updatedAt;
|
||||
|
||||
Author(
|
||||
{this.id,
|
||||
this.name,
|
||||
this.age,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.books,
|
||||
this.newestBook,
|
||||
this.secret});
|
||||
this.createdAt,
|
||||
this.updatedAt});
|
||||
|
||||
factory Author.fromJson(Map data) {
|
||||
return new Author(
|
||||
id: data['id'],
|
||||
name: data['name'],
|
||||
age: data['age'],
|
||||
createdAt: data['createdAt'] is DateTime
|
||||
? data['createdAt']
|
||||
: (data['createdAt'] is String
|
||||
? DateTime.parse(data['createdAt'])
|
||||
: null),
|
||||
updatedAt: data['updatedAt'] is DateTime
|
||||
? data['updatedAt']
|
||||
: (data['updatedAt'] is String
|
||||
? DateTime.parse(data['updatedAt'])
|
||||
: null),
|
||||
books: data['books'] is List
|
||||
? data['books']
|
||||
.map((x) =>
|
||||
|
@ -135,17 +121,27 @@ class Author extends _Author {
|
|||
? null
|
||||
: (data['newest_book'] is Book
|
||||
? data['newest_book']
|
||||
: new Book.fromJson(data['newest_book'])));
|
||||
: new Book.fromJson(data['newest_book'])),
|
||||
createdAt: data['created_at'] is DateTime
|
||||
? data['created_at']
|
||||
: (data['created_at'] is String
|
||||
? DateTime.parse(data['created_at'])
|
||||
: null),
|
||||
updatedAt: data['updated_at'] is DateTime
|
||||
? data['updated_at']
|
||||
: (data['updated_at'] is String
|
||||
? DateTime.parse(data['updated_at'])
|
||||
: null));
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'age': age,
|
||||
'createdAt': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String(),
|
||||
'books': books,
|
||||
'newest_book': newestBook
|
||||
'newest_book': newestBook,
|
||||
'created_at': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
};
|
||||
|
||||
static Author parse(Map map) => new Author.fromJson(map);
|
||||
|
@ -160,30 +156,20 @@ class Library extends _Library {
|
|||
@override
|
||||
String id;
|
||||
|
||||
@override
|
||||
Map<String, _Book> collection;
|
||||
|
||||
@override
|
||||
DateTime createdAt;
|
||||
|
||||
@override
|
||||
DateTime updatedAt;
|
||||
|
||||
@override
|
||||
Map<String, _Book> collection;
|
||||
|
||||
Library({this.id, this.createdAt, this.updatedAt, this.collection});
|
||||
Library({this.id, this.collection, this.createdAt, this.updatedAt});
|
||||
|
||||
factory Library.fromJson(Map data) {
|
||||
return new Library(
|
||||
id: data['id'],
|
||||
createdAt: data['createdAt'] is DateTime
|
||||
? data['createdAt']
|
||||
: (data['createdAt'] is String
|
||||
? DateTime.parse(data['createdAt'])
|
||||
: null),
|
||||
updatedAt: data['updatedAt'] is DateTime
|
||||
? data['updatedAt']
|
||||
: (data['updatedAt'] is String
|
||||
? DateTime.parse(data['updatedAt'])
|
||||
: null),
|
||||
collection: data['collection'] is Map
|
||||
? data['collection'].keys.fold({}, (out, k) {
|
||||
out[k] = data['collection'][k] == null
|
||||
|
@ -193,14 +179,24 @@ class Library extends _Library {
|
|||
: new Book.fromJson(data['collection'][k]));
|
||||
return out;
|
||||
})
|
||||
: null);
|
||||
: null,
|
||||
createdAt: data['created_at'] is DateTime
|
||||
? data['created_at']
|
||||
: (data['created_at'] is String
|
||||
? DateTime.parse(data['created_at'])
|
||||
: null),
|
||||
updatedAt: data['updated_at'] is DateTime
|
||||
? data['updated_at']
|
||||
: (data['updated_at'] is String
|
||||
? DateTime.parse(data['updated_at'])
|
||||
: null));
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'createdAt': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String(),
|
||||
'collection': collection
|
||||
'collection': collection,
|
||||
'created_at': createdAt == null ? null : createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt == null ? null : updatedAt.toIso8601String()
|
||||
};
|
||||
|
||||
static Library parse(Map map) => new Library.fromJson(map);
|
||||
|
|
Loading…
Reference in a new issue