orm_service tests
This commit is contained in:
parent
55e8a2e83c
commit
4bc50eca69
7 changed files with 726 additions and 7 deletions
|
@ -1,3 +1,6 @@
|
|||
# 2.0.1
|
||||
* Gracefully handle `null` in enum fields.
|
||||
|
||||
# 2.0.0+2
|
||||
* Widen `analyzer` dependency range.
|
||||
|
||||
|
|
|
@ -192,7 +192,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
.property('tryParse')
|
||||
.call([expr.property('toString').call([])]);
|
||||
} else if (fType is InterfaceType && fType.element.isEnum) {
|
||||
expr = type.property('values').index(expr.asA(refer('int')));
|
||||
var isNull = expr.equalTo(literalNull);
|
||||
expr = isNull.conditional(literalNull,
|
||||
type.property('values').index(expr.asA(refer('int'))));
|
||||
} else
|
||||
expr = expr.asA(type);
|
||||
|
||||
|
@ -691,7 +693,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
Expression value = refer('value');
|
||||
|
||||
if (fType is InterfaceType && fType.element.isEnum) {
|
||||
value = value.property('index');
|
||||
value = CodeExpression(Code('value?.index'));
|
||||
} else if (const TypeChecker.fromRuntime(List)
|
||||
.isAssignableFromType(fType)) {
|
||||
value = refer('json').property('encode').call([value]);
|
||||
|
|
21
angel_orm_service/LICENSE
Normal file
21
angel_orm_service/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -63,7 +63,21 @@ class OrmService<Id, Data, TQuery extends Query<Data, QueryWhere>>
|
|||
await queryObj(query);
|
||||
} else if (queryObj is Map) {
|
||||
queryObj.forEach((k, v) {
|
||||
if (k is String && v is! RequestContext && v is! ResponseContext) {
|
||||
if (k == r'$sort') {
|
||||
if (v is Map) {
|
||||
v.forEach((key, value) {
|
||||
var descending = false;
|
||||
if (value is String)
|
||||
descending = value == '-1';
|
||||
else if (value is num) descending = value.toInt() == -1;
|
||||
query.orderBy(key.toString(), descending: descending);
|
||||
});
|
||||
} else if (v is String) {
|
||||
query.orderBy(v);
|
||||
}
|
||||
} else if (k is String &&
|
||||
v is! RequestContext &&
|
||||
v is! ResponseContext) {
|
||||
_apply(query, k, v);
|
||||
}
|
||||
});
|
||||
|
@ -74,6 +88,10 @@ class OrmService<Id, Data, TQuery extends Query<Data, QueryWhere>>
|
|||
@override
|
||||
Future<List<Data>> readMany(List<Id> ids,
|
||||
[Map<String, dynamic> params]) async {
|
||||
if (ids.isEmpty) {
|
||||
throw ArgumentError.value(ids, 'ids', 'cannot be empty');
|
||||
}
|
||||
|
||||
var query = await queryCreator();
|
||||
var builder = _findBuilder(query, idField);
|
||||
|
||||
|
@ -134,7 +152,6 @@ class OrmService<Id, Data, TQuery extends Query<Data, QueryWhere>>
|
|||
|
||||
@override
|
||||
Future<Data> modify(Id id, Data data, [Map<String, dynamic> params]) {
|
||||
// TODO: Is there any way to make this an actual modify, and not an update?
|
||||
return update(id, data, params);
|
||||
}
|
||||
|
||||
|
@ -151,7 +168,10 @@ class OrmService<Id, Data, TQuery extends Query<Data, QueryWhere>>
|
|||
'${query.values.runtimeType} has no `copyFrom` method, but OrmService requires this for updates.');
|
||||
}
|
||||
|
||||
return await query.updateOne(executor);
|
||||
var result = await query.updateOne(executor);
|
||||
if (result != null) return result;
|
||||
throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id');
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -170,7 +190,9 @@ class OrmService<Id, Data, TQuery extends Query<Data, QueryWhere>>
|
|||
await _applyQuery(query, params);
|
||||
}
|
||||
|
||||
var deleted = await query.delete(executor);
|
||||
return deleted.isEmpty ? null : deleted.first;
|
||||
var result = await query.deleteOne(executor);
|
||||
if (result != null) return result;
|
||||
throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id');
|
||||
}
|
||||
}
|
||||
|
|
233
angel_orm_service/test/all_test.dart
Normal file
233
angel_orm_service/test/all_test.dart
Normal file
|
@ -0,0 +1,233 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_orm_postgres/angel_orm_postgres.dart';
|
||||
import 'package:angel_orm_service/angel_orm_service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'pokemon.dart';
|
||||
|
||||
void main() {
|
||||
Logger logger;
|
||||
PostgreSqlExecutor executor;
|
||||
Service<int, Pokemon> pokemonService;
|
||||
|
||||
setUp(() async {
|
||||
var conn = PostgreSQLConnection('localhost', 5432, 'angel_orm_service_test',
|
||||
username: Platform.environment['POSTGRES_USERNAME'] ?? 'postgres',
|
||||
password: Platform.environment['POSTGRES_PASSWORD'] ?? 'password');
|
||||
hierarchicalLoggingEnabled = true;
|
||||
logger = Logger.detached('orm_service');
|
||||
logger.level = Level.ALL;
|
||||
if (Platform.environment['log'] == '1') logger.onRecord.listen(print);
|
||||
executor = PostgreSqlExecutor(conn, logger: logger);
|
||||
await conn.open();
|
||||
await conn.query('''
|
||||
CREATE TEMPORARY TABLE pokemons (
|
||||
id serial,
|
||||
species varchar,
|
||||
name varchar,
|
||||
level integer,
|
||||
type1 integer,
|
||||
type2 integer,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
||||
''');
|
||||
|
||||
pokemonService = OrmService(executor, () => PokemonQuery());
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await executor.close();
|
||||
pokemonService.close();
|
||||
logger.clearListeners();
|
||||
});
|
||||
|
||||
test('create', () async {
|
||||
var blaziken = await pokemonService.create(Pokemon(
|
||||
species: 'Blaziken',
|
||||
level: 100,
|
||||
type1: PokemonType.fire,
|
||||
type2: PokemonType.fighting));
|
||||
print(blaziken);
|
||||
expect(blaziken.id, isNotNull);
|
||||
expect(blaziken.species, 'Blaziken');
|
||||
expect(blaziken.level, 100);
|
||||
expect(blaziken.type1, PokemonType.fire);
|
||||
expect(blaziken.type2, PokemonType.fighting);
|
||||
});
|
||||
|
||||
group('after create', () {
|
||||
Pokemon giratina, pikachu;
|
||||
|
||||
setUp(() async {
|
||||
giratina = await pokemonService.create(Pokemon(
|
||||
species: 'Giratina',
|
||||
name: 'My First Legendary',
|
||||
level: 54,
|
||||
type1: PokemonType.ghost,
|
||||
type2: PokemonType.dragon));
|
||||
pikachu = await pokemonService.create(Pokemon(
|
||||
species: 'Pikachu',
|
||||
level: 100,
|
||||
type1: PokemonType.electric,
|
||||
));
|
||||
});
|
||||
|
||||
group('index', () {
|
||||
test('default', () async {
|
||||
expect(await pokemonService.index(), contains(giratina));
|
||||
expect(await pokemonService.index(), contains(pikachu));
|
||||
});
|
||||
|
||||
test('with callback', () async {
|
||||
var result = await pokemonService.index({
|
||||
'query': (PokemonQuery query) async {
|
||||
query.where.level.equals(pikachu.level);
|
||||
},
|
||||
});
|
||||
|
||||
expect(result, [pikachu]);
|
||||
});
|
||||
|
||||
test('search params', () async {
|
||||
Future<List<Pokemon>> searchByType1(PokemonType type1) async {
|
||||
var query = {PokemonFields.type1: type1};
|
||||
var params = {'query': query};
|
||||
return await pokemonService.index(params);
|
||||
}
|
||||
|
||||
expect(await searchByType1(PokemonType.ghost), [giratina]);
|
||||
expect(await searchByType1(PokemonType.electric), [pikachu]);
|
||||
expect(await searchByType1(PokemonType.grass), []);
|
||||
});
|
||||
|
||||
group(r'$sort', () {
|
||||
test('by name', () async {
|
||||
expect(
|
||||
await pokemonService.index({
|
||||
'query': {r'$sort': 'level'}
|
||||
}),
|
||||
[giratina, pikachu]);
|
||||
});
|
||||
|
||||
test('map number', () async {
|
||||
expect(
|
||||
await pokemonService.index({
|
||||
'query': {
|
||||
r'$sort': {'type1': -1}
|
||||
}
|
||||
}),
|
||||
[giratina, pikachu]);
|
||||
expect(
|
||||
await pokemonService.index({
|
||||
'query': {
|
||||
r'$sort': {'type1': 100}
|
||||
}
|
||||
}),
|
||||
[pikachu, giratina]);
|
||||
});
|
||||
|
||||
test('map string', () async {
|
||||
expect(
|
||||
await pokemonService.index({
|
||||
'query': {
|
||||
r'$sort': {'type1': '-1'}
|
||||
}
|
||||
}),
|
||||
[giratina, pikachu]);
|
||||
expect(
|
||||
await pokemonService.index({
|
||||
'query': {
|
||||
r'$sort': {'type1': 'foo'}
|
||||
}
|
||||
}),
|
||||
[pikachu, giratina]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('findOne', () {
|
||||
test('default', () async {
|
||||
expect(
|
||||
await pokemonService.findOne({
|
||||
'query': {PokemonFields.name: giratina.name}
|
||||
}),
|
||||
giratina);
|
||||
expect(
|
||||
await pokemonService.findOne({
|
||||
'query': {PokemonFields.level: pikachu.level}
|
||||
}),
|
||||
pikachu);
|
||||
expect(
|
||||
() => pokemonService.findOne({
|
||||
'query': {PokemonFields.level: pikachu.level * 3}
|
||||
}),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
|
||||
test('nonexistent throws 404', () {
|
||||
expect(
|
||||
() => pokemonService.findOne({
|
||||
'query': {PokemonFields.type1: PokemonType.poison}
|
||||
}),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
});
|
||||
|
||||
group('read', () {
|
||||
test('default', () async {
|
||||
expect(await pokemonService.read(pikachu.idAsInt), pikachu);
|
||||
expect(await pokemonService.read(giratina.idAsInt), giratina);
|
||||
});
|
||||
|
||||
test('nonexistent throws 404', () {
|
||||
expect(() => pokemonService.read(999),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
});
|
||||
|
||||
test('readMany', () async {
|
||||
expect(pokemonService.readMany([giratina.idAsInt, pikachu.idAsInt]),
|
||||
completion([giratina, pikachu]));
|
||||
expect(
|
||||
pokemonService.readMany([giratina.idAsInt]), completion([giratina]));
|
||||
expect(pokemonService.readMany([pikachu.idAsInt]), completion([pikachu]));
|
||||
expect(() => pokemonService.readMany([]), throwsArgumentError);
|
||||
});
|
||||
|
||||
group('update', () {
|
||||
test('default', () async {
|
||||
expect(
|
||||
await pokemonService.update(
|
||||
giratina.idAsInt, giratina.copyWith(name: 'Hello')),
|
||||
giratina.copyWith(name: 'Hello'));
|
||||
});
|
||||
|
||||
test('nonexistent throws 404', () {
|
||||
expect(
|
||||
() => pokemonService.update(999, giratina.copyWith(name: 'Hello')),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
});
|
||||
|
||||
group('remove', () {
|
||||
test('default', () async {
|
||||
expect(pokemonService.read(giratina.idAsInt), completion(giratina));
|
||||
expect(pokemonService.read(pikachu.idAsInt), completion(pikachu));
|
||||
});
|
||||
|
||||
test('nonexistent throws 404', () {
|
||||
expect(() => pokemonService.remove(999),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
|
||||
test('cannot remove all unless explicitly set', () async {
|
||||
expect(() => pokemonService.remove(null, {'provider': Providers.rest}),
|
||||
throwsA(TypeMatcher<AngelHttpException>()));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
33
angel_orm_service/test/pokemon.dart
Normal file
33
angel_orm_service/test/pokemon.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
import 'package:angel_migration/angel_migration.dart';
|
||||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
import 'package:angel_orm/angel_orm.dart';
|
||||
part 'pokemon.g.dart';
|
||||
|
||||
enum PokemonType {
|
||||
fire,
|
||||
grass,
|
||||
water,
|
||||
dragon,
|
||||
poison,
|
||||
dark,
|
||||
fighting,
|
||||
electric,
|
||||
ghost
|
||||
}
|
||||
|
||||
@serializable
|
||||
@orm
|
||||
abstract class _Pokemon extends Model {
|
||||
@notNull
|
||||
String get species;
|
||||
|
||||
String get name;
|
||||
|
||||
@notNull
|
||||
int get level;
|
||||
|
||||
@notNull
|
||||
PokemonType get type1;
|
||||
|
||||
PokemonType get type2;
|
||||
}
|
405
angel_orm_service/test/pokemon.g.dart
Normal file
405
angel_orm_service/test/pokemon.g.dart
Normal file
|
@ -0,0 +1,405 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'pokemon.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// MigrationGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class PokemonMigration extends Migration {
|
||||
@override
|
||||
up(Schema schema) {
|
||||
schema.create('pokemons', (table) {
|
||||
table.serial('id')..primaryKey();
|
||||
table.varChar('species');
|
||||
table.varChar('name');
|
||||
table.integer('level');
|
||||
table.integer('type1');
|
||||
table.integer('type2');
|
||||
table.timeStamp('created_at');
|
||||
table.timeStamp('updated_at');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
down(Schema schema) {
|
||||
schema.drop('pokemons');
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// OrmGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class PokemonQuery extends Query<Pokemon, PokemonQueryWhere> {
|
||||
PokemonQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = PokemonQueryWhere(this);
|
||||
}
|
||||
|
||||
@override
|
||||
final PokemonQueryValues values = PokemonQueryValues();
|
||||
|
||||
PokemonQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'pokemons';
|
||||
}
|
||||
|
||||
@override
|
||||
get fields {
|
||||
return const [
|
||||
'id',
|
||||
'species',
|
||||
'name',
|
||||
'level',
|
||||
'type1',
|
||||
'type2',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
PokemonQueryWhere get where {
|
||||
return _where;
|
||||
}
|
||||
|
||||
@override
|
||||
PokemonQueryWhere newWhereClause() {
|
||||
return PokemonQueryWhere(this);
|
||||
}
|
||||
|
||||
static Pokemon parseRow(List row) {
|
||||
if (row.every((x) => x == null)) return null;
|
||||
var model = Pokemon(
|
||||
id: row[0].toString(),
|
||||
species: (row[1] as String),
|
||||
name: (row[2] as String),
|
||||
level: (row[3] as int),
|
||||
type1: row[4] == null ? null : PokemonType.values[(row[4] as int)],
|
||||
type2: row[5] == null ? null : PokemonType.values[(row[5] as int)],
|
||||
createdAt: (row[6] as DateTime),
|
||||
updatedAt: (row[7] as DateTime));
|
||||
return model;
|
||||
}
|
||||
|
||||
@override
|
||||
deserialize(List row) {
|
||||
return parseRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
class PokemonQueryWhere extends QueryWhere {
|
||||
PokemonQueryWhere(PokemonQuery query)
|
||||
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
|
||||
species = StringSqlExpressionBuilder(query, 'species'),
|
||||
name = StringSqlExpressionBuilder(query, 'name'),
|
||||
level = NumericSqlExpressionBuilder<int>(query, 'level'),
|
||||
type1 = EnumSqlExpressionBuilder<PokemonType>(
|
||||
query, 'type1', (v) => v.index),
|
||||
type2 = EnumSqlExpressionBuilder<PokemonType>(
|
||||
query, 'type2', (v) => v.index),
|
||||
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
|
||||
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at');
|
||||
|
||||
final NumericSqlExpressionBuilder<int> id;
|
||||
|
||||
final StringSqlExpressionBuilder species;
|
||||
|
||||
final StringSqlExpressionBuilder name;
|
||||
|
||||
final NumericSqlExpressionBuilder<int> level;
|
||||
|
||||
final EnumSqlExpressionBuilder<PokemonType> type1;
|
||||
|
||||
final EnumSqlExpressionBuilder<PokemonType> type2;
|
||||
|
||||
final DateTimeSqlExpressionBuilder createdAt;
|
||||
|
||||
final DateTimeSqlExpressionBuilder updatedAt;
|
||||
|
||||
@override
|
||||
get expressionBuilders {
|
||||
return [id, species, name, level, type1, type2, createdAt, updatedAt];
|
||||
}
|
||||
}
|
||||
|
||||
class PokemonQueryValues extends MapQueryValues {
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
String get id {
|
||||
return (values['id'] as String);
|
||||
}
|
||||
|
||||
set id(String value) => values['id'] = value;
|
||||
String get species {
|
||||
return (values['species'] as String);
|
||||
}
|
||||
|
||||
set species(String value) => values['species'] = value;
|
||||
String get name {
|
||||
return (values['name'] as String);
|
||||
}
|
||||
|
||||
set name(String value) => values['name'] = value;
|
||||
int get level {
|
||||
return (values['level'] as int);
|
||||
}
|
||||
|
||||
set level(int value) => values['level'] = value;
|
||||
PokemonType get type1 {
|
||||
return PokemonType.values[(values['type1'] as int)];
|
||||
}
|
||||
|
||||
set type1(PokemonType value) => values['type1'] = value?.index;
|
||||
PokemonType get type2 {
|
||||
return PokemonType.values[(values['type2'] as int)];
|
||||
}
|
||||
|
||||
set type2(PokemonType value) => values['type2'] = value?.index;
|
||||
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(Pokemon model) {
|
||||
species = model.species;
|
||||
name = model.name;
|
||||
level = model.level;
|
||||
type1 = model.type1;
|
||||
type2 = model.type2;
|
||||
createdAt = model.createdAt;
|
||||
updatedAt = model.updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// JsonModelGenerator
|
||||
// **************************************************************************
|
||||
|
||||
@generatedSerializable
|
||||
class Pokemon extends _Pokemon {
|
||||
Pokemon(
|
||||
{this.id,
|
||||
@required this.species,
|
||||
this.name,
|
||||
@required this.level,
|
||||
@required this.type1,
|
||||
this.type2,
|
||||
this.createdAt,
|
||||
this.updatedAt});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
|
||||
@override
|
||||
final String species;
|
||||
|
||||
@override
|
||||
final String name;
|
||||
|
||||
@override
|
||||
final int level;
|
||||
|
||||
@override
|
||||
final PokemonType type1;
|
||||
|
||||
@override
|
||||
final PokemonType type2;
|
||||
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
@override
|
||||
final DateTime updatedAt;
|
||||
|
||||
Pokemon copyWith(
|
||||
{String id,
|
||||
String species,
|
||||
String name,
|
||||
int level,
|
||||
PokemonType type1,
|
||||
PokemonType type2,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt}) {
|
||||
return new Pokemon(
|
||||
id: id ?? this.id,
|
||||
species: species ?? this.species,
|
||||
name: name ?? this.name,
|
||||
level: level ?? this.level,
|
||||
type1: type1 ?? this.type1,
|
||||
type2: type2 ?? this.type2,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt);
|
||||
}
|
||||
|
||||
bool operator ==(other) {
|
||||
return other is _Pokemon &&
|
||||
other.id == id &&
|
||||
other.species == species &&
|
||||
other.name == name &&
|
||||
other.level == level &&
|
||||
other.type1 == type1 &&
|
||||
other.type2 == type2 &&
|
||||
other.createdAt == createdAt &&
|
||||
other.updatedAt == updatedAt;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashObjects(
|
||||
[id, species, name, level, type1, type2, createdAt, updatedAt]);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "Pokemon(id=$id, species=$species, name=$name, level=$level, type1=$type1, type2=$type2, createdAt=$createdAt, updatedAt=$updatedAt)";
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return PokemonSerializer.toMap(this);
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// SerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
const PokemonSerializer pokemonSerializer = const PokemonSerializer();
|
||||
|
||||
class PokemonEncoder extends Converter<Pokemon, Map> {
|
||||
const PokemonEncoder();
|
||||
|
||||
@override
|
||||
Map convert(Pokemon model) => PokemonSerializer.toMap(model);
|
||||
}
|
||||
|
||||
class PokemonDecoder extends Converter<Map, Pokemon> {
|
||||
const PokemonDecoder();
|
||||
|
||||
@override
|
||||
Pokemon convert(Map map) => PokemonSerializer.fromMap(map);
|
||||
}
|
||||
|
||||
class PokemonSerializer extends Codec<Pokemon, Map> {
|
||||
const PokemonSerializer();
|
||||
|
||||
@override
|
||||
get encoder => const PokemonEncoder();
|
||||
@override
|
||||
get decoder => const PokemonDecoder();
|
||||
static Pokemon fromMap(Map map) {
|
||||
if (map['species'] == null) {
|
||||
throw new FormatException("Missing required field 'species' on Pokemon.");
|
||||
}
|
||||
|
||||
if (map['level'] == null) {
|
||||
throw new FormatException("Missing required field 'level' on Pokemon.");
|
||||
}
|
||||
|
||||
if (map['type1'] == null) {
|
||||
throw new FormatException("Missing required field 'type1' on Pokemon.");
|
||||
}
|
||||
|
||||
return new Pokemon(
|
||||
id: map['id'] as String,
|
||||
species: map['species'] as String,
|
||||
name: map['name'] as String,
|
||||
level: map['level'] as int,
|
||||
type1: map['type1'] is PokemonType
|
||||
? (map['type1'] as PokemonType)
|
||||
: (map['type1'] is int
|
||||
? PokemonType.values[map['type1'] as int]
|
||||
: null),
|
||||
type2: map['type2'] is PokemonType
|
||||
? (map['type2'] as PokemonType)
|
||||
: (map['type2'] is int
|
||||
? PokemonType.values[map['type2'] as int]
|
||||
: 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(_Pokemon model) {
|
||||
if (model == null) {
|
||||
return null;
|
||||
}
|
||||
if (model.species == null) {
|
||||
throw new FormatException("Missing required field 'species' on Pokemon.");
|
||||
}
|
||||
|
||||
if (model.level == null) {
|
||||
throw new FormatException("Missing required field 'level' on Pokemon.");
|
||||
}
|
||||
|
||||
if (model.type1 == null) {
|
||||
throw new FormatException("Missing required field 'type1' on Pokemon.");
|
||||
}
|
||||
|
||||
return {
|
||||
'id': model.id,
|
||||
'species': model.species,
|
||||
'name': model.name,
|
||||
'level': model.level,
|
||||
'type1':
|
||||
model.type1 == null ? null : PokemonType.values.indexOf(model.type1),
|
||||
'type2':
|
||||
model.type2 == null ? null : PokemonType.values.indexOf(model.type2),
|
||||
'created_at': model.createdAt?.toIso8601String(),
|
||||
'updated_at': model.updatedAt?.toIso8601String()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PokemonFields {
|
||||
static const List<String> allFields = <String>[
|
||||
id,
|
||||
species,
|
||||
name,
|
||||
level,
|
||||
type1,
|
||||
type2,
|
||||
createdAt,
|
||||
updatedAt
|
||||
];
|
||||
|
||||
static const String id = 'id';
|
||||
|
||||
static const String species = 'species';
|
||||
|
||||
static const String name = 'name';
|
||||
|
||||
static const String level = 'level';
|
||||
|
||||
static const String type1 = 'type1';
|
||||
|
||||
static const String type2 = 'type2';
|
||||
|
||||
static const String createdAt = 'created_at';
|
||||
|
||||
static const String updatedAt = 'updated_at';
|
||||
}
|
Loading…
Reference in a new issue