platform/README.md
2017-06-16 22:00:24 -04:00

5.6 KiB

serialize

Pub build status

This project is currently in the early stages, and may change at any given time without warning.

Source-generated serialization for Dart object. This package uses package:source_gen to eliminate the time you spend writing boilerplate serialization code for your models. package:angel_serialize also powers package:angel_postgres and other ORM functionality.

Usage

In your pubspec.yaml:

dependencies:
  angel_serialize:
    git: https://github.com/angel-dart/serialize.git
dev_dependencies:
  build_runner: ^0.3.0

You'll want to create a Dart script, usually named tool/phases.dart that invokes the JsonModelGenerator.

import 'package:build_runner/build_runner.dart';
import 'package:source_gen/source_gen.dart';
import 'package:angel_serialize/builder.dart';

final PhaseGroup PHASES = new PhaseGroup.singleAction(
    new GeneratorBuilder([const JsonModelGenerator()]),
    new InputSet('[YOUR_PACKAGE_NAME_HERE]', const ['lib/src/models/*.dart']));

And then, a tool/build.dart can build your serializers:

import 'package:build_runner/build_runner.dart';
import 'phases.dart';

main() => build(PHASES, deleteFilesByDefault: true);

If you want to watch for file changes and re-build when necessary, replace the build call with a call to watch. They take the same parameters.

Models

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 with a leading underscore. In addition, you may consider using an abstract class.

Rather you writing the public class, angel_serialize does it for you. This means that the main class can have its constructors automatically generated, in addition into serialization functions.

For example, say we have a Book model. Create a class named _Book:

library angel_serialize.test.models.book;

import 'package:angel_framework/common.dart';
import 'package:angel_serialize/angel_serialize.dart';
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;
}

The following will be generated in book.g.dart:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of angel_serialize.test.models.book;

// **************************************************************************
// Generator: JsonModelGenerator
// Target: abstract class _Book
// **************************************************************************

class Book extends _Book {
  @override
  String id;

  @override
  String author;

  @override
  String title;

  @override
  String description;

  @override
  int pageCount;

  @override
  DateTime createdAt;

  @override
  DateTime updatedAt;

  Book(
      {this.id,
      this.author,
      this.title,
      this.description,
      this.pageCount,
      this.createdAt,
      this.updatedAt});

  factory Book.fromJson(Map data) {
    return new Book(
        id: data['id'],
        author: data['author'],
        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'])
                : null),
        updatedAt: data['updatedAt'] is DateTime
            ? data['updatedAt']
            : (data['updatedAt'] is String
                ? DateTime.parse(data['updatedAt'])
                : null));
  }

  Map<String, dynamic> toJson() => {
        'id': id,
        'author': author,
        'title': title,
        'description': description,
        'page_count': pageCount,
        'createdAt': createdAt == null ? null : createdAt.toIso8601String(),
        'updatedAt': updatedAt == null ? null : updatedAt.toIso8601String()
      };

  static Book parse(Map map) => new Book.fromJson(map);
}

Aliases

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.

@serializable
abstract class _Spy extends Model {
  /// Will show up as 'agency_id' in serialized JSON.
  /// 
  /// When deserializing JSON, instead of searching for an 'agencyId' key,
  /// it will use 'agency_id'.
  /// 
  /// Hooray!
  @Alias('agency_id')
  String agencyId;
}

Excluding Keys

In pratice, there may keys that you want to exclude from JSON. To accomplish this, simply annotate them with @exclude:

@serializable
abstract class _Whisper extends Model {
  /// Will never be serialized to JSON
  @exclude
  String secret;
}

Nesting

angel_serialize also supports a few types of nesting of @serializable classes:

  • As a class member
  • As the type argument to a List
  • As the second type argument to a Map

In other words, the following are all legal, and will be serialized/deserialized. 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;
}