Fixed issue 68

This commit is contained in:
thomashii@dukefirehawk.com 2022-06-04 09:50:58 +08:00
parent b185baec7b
commit a714059cb9
22 changed files with 1693 additions and 40 deletions

View file

@ -1,5 +1,10 @@
# Change Log
## 6.0.2
* Fixed issue #68: Support for non-nullable type
* Upgraded to `lints` 2.x.x
## 6.0.1
* Added `mapToDateTime`

View file

@ -93,6 +93,7 @@ class ColumnType {
static const ColumnType smallMoney = ColumnType('smallmoney');
static const ColumnType float = ColumnType('float');
static const ColumnType real = ColumnType('real');
static const ColumnType double = ColumnType('double');
// Dates and times
static const ColumnType dateTime = ColumnType('datetime');

View file

@ -2,6 +2,8 @@ import 'package:charcode/ascii.dart';
bool isAscii(int ch) => ch >= $nul && ch <= $del;
final DateTime defaultDate = DateTime.parse("1970-01-01 00:00:00");
bool mapToBool(dynamic value) {
if (value is int) {
return value != 0;
@ -20,12 +22,12 @@ String mapToText(dynamic value) {
return value;
}
DateTime? mapToDateTime(dynamic value) {
DateTime mapToDateTime(dynamic value) {
if (value == null) {
return value;
return defaultDate;
}
if (value is String) {
return DateTime.tryParse(value);
return DateTime.tryParse(value) ?? defaultDate;
}
return value;
}

View file

@ -1,5 +1,5 @@
name: angel3_orm
version: 6.0.1
version: 6.0.2
description: Runtime support for Angel3 ORM. Includes base classes for queries.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm
@ -18,7 +18,7 @@ dev_dependencies:
angel3_serialize_generator: ^6.0.0
build_runner: ^2.1.1
test: ^1.17.4
lints: ^1.0.0
lints: ^2.0.0
# dependency_overrides:
# angel3_serialize:
# path: ../../serialize/angel_serialize

View file

@ -1,5 +1,10 @@
# Change Log
## 6.1.1
* Fixed issue #68: Support for non-nullable type
* Upgraded to `lints` 2.x.x
## 6.1.0
* Updated to `analyzer` 4.x.x

View file

@ -149,6 +149,9 @@ class MigrationGenerator extends GeneratorForAnnotation<Orm> {
case ColumnType.numeric:
methodName = 'numeric';
break;
case ColumnType.double:
methodName = 'float';
break;
case ColumnType.boolean:
methodName = 'boolean';
break;

View file

@ -342,10 +342,10 @@ ColumnType inferColumnType(DartType type) {
return ColumnType.int;
}
if (const TypeChecker.fromRuntime(double).isAssignableFromType(type)) {
return ColumnType.decimal;
return ColumnType.double;
}
if (const TypeChecker.fromRuntime(num).isAssignableFromType(type)) {
return ColumnType.numeric;
return ColumnType.double;
}
if (const TypeChecker.fromRuntime(bool).isAssignableFromType(type)) {
return ColumnType.boolean;

View file

@ -14,6 +14,7 @@ var floatTypes = [
ColumnType.float,
ColumnType.numeric,
ColumnType.real,
ColumnType.double,
const ColumnType('double precision'),
];
@ -241,7 +242,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..body = Block((b) {
var i = 0;
// Build the argurments for model
// Build the arguments for model
var args = <String, Expression>{};
for (var field in ctx.effectiveFields) {
var fType = field.type;
@ -274,16 +275,32 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// Generated Code: mapToBool(row[i])
expr = refer('mapToBool').call([expr]);
} else if (fType.element?.displayName == 'DateTime') {
//print("fType: ${fType.element?.displayName}");
// print("fType: ${fType.element?.displayName}");
// Generated Code: mapToDateTime(row[i])
expr = refer('mapToDateTime').call([expr]);
} else {
// Generated Code: (row[i] as type?)
expr = expr.asA(type);
}
Expression defaultRef = refer('null');
if (fType.nullabilitySuffix != NullabilitySuffix.question) {
if (fType.isDartCoreString) {
defaultRef = CodeExpression(Code('\'\''));
} else if (fType.isDartCoreBool) {
defaultRef = CodeExpression(Code('false'));
} else if (fType.isDartCoreDouble) {
defaultRef = CodeExpression(Code('0.0'));
} else if (fType.isDartCoreInt || fType.isDartCoreNum) {
defaultRef = CodeExpression(Code('0'));
} else if (fType.element?.displayName == 'DateTime') {
defaultRef = CodeExpression(
Code('DateTime.parse("1970-01-01 00:00:00")'));
}
}
expr = refer('fields').property('contains').call([
literalString(ctx.buildContext.resolveFieldName(field.name)!)
]).conditional(expr, refer('null'));
]).conditional(expr, defaultRef);
args[field.name] = expr;
}
@ -866,7 +883,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
value = refer('double')
.property('tryParse')
.call([value.asA(refer('String'))]);
.call([value.asA(refer('String'))]).ifNullThen(
CodeExpression(Code('0.0')));
} else {
value = value.asA(type);
}

View file

@ -1,5 +1,5 @@
name: angel3_orm_generator
version: 6.1.0
version: 6.1.1
description: Code generators for Angel3 ORM. Generates query builder classes.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_generator
@ -29,8 +29,8 @@ dev_dependencies:
build_runner: ^2.0.1
postgres: ^2.4.0
test: ^1.21.0
lints: ^1.0.0
# dependency_overrides:
lints: ^2.0.0
dependency_overrides:
# angel3_container:
# path: ../../container/angel_container
# angel3_framework:
@ -45,10 +45,10 @@ dev_dependencies:
# path: ../../mock_request
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
# angel3_orm:
# path: ../angel_orm
angel3_serialize_generator:
path: ../../serialize/angel_serialize_generator
angel3_orm:
path: ../angel_orm
# angel3_migration:
# path: ../angel_migration

View file

@ -2,7 +2,8 @@
## 6.0.1
* Updated generated test cases
* Added test cases for non nullable type
* Upgraded to `lints` 2.x.x
## 6.0.0

View file

@ -0,0 +1,23 @@
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_migration/angel3_migration.dart';
import 'package:optional/optional.dart';
part 'asset.g.dart';
@serializable
@orm
abstract class _Item extends Model {
String get description;
}
@serializable
@orm
abstract class _Asset extends Model {
String get description;
String get name;
@hasMany
List<_Item> get items;
}

View file

@ -0,0 +1,658 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'asset.dart';
// **************************************************************************
// MigrationGenerator
// **************************************************************************
class ItemMigration extends Migration {
@override
void up(Schema schema) {
schema.create('items', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.varChar('description', length: 255);
});
}
@override
void down(Schema schema) {
schema.drop('items');
}
}
class AssetMigration extends Migration {
@override
void up(Schema schema) {
schema.create('assets', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.varChar('description', length: 255);
table.varChar('name', length: 255);
});
}
@override
void down(Schema schema) {
schema.drop('assets', cascade: true);
}
}
// **************************************************************************
// OrmGenerator
// **************************************************************************
class ItemQuery extends Query<Item, ItemQueryWhere> {
ItemQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = ItemQueryWhere(this);
}
@override
final ItemQueryValues values = ItemQueryValues();
List<String> _selectedFields = [];
ItemQueryWhere? _where;
@override
Map<String, String> get casts {
return {};
}
@override
String get tableName {
return 'items';
}
@override
List<String> get fields {
const _fields = ['id', 'created_at', 'updated_at', 'description'];
return _selectedFields.isEmpty
? _fields
: _fields.where((field) => _selectedFields.contains(field)).toList();
}
ItemQuery select(List<String> selectedFields) {
_selectedFields = selectedFields;
return this;
}
@override
ItemQueryWhere? get where {
return _where;
}
@override
ItemQueryWhere newWhereClause() {
return ItemQueryWhere(this);
}
Optional<Item> parseRow(List row) {
if (row.every((x) => x == null)) {
return Optional.empty();
}
var model = Item(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
description: fields.contains('description') ? (row[3] as String) : '');
return Optional.of(model);
}
@override
Optional<Item> deserialize(List row) {
return parseRow(row);
}
}
class ItemQueryWhere extends QueryWhere {
ItemQueryWhere(ItemQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
description = StringSqlExpressionBuilder(query, 'description');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final StringSqlExpressionBuilder description;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [id, createdAt, updatedAt, description];
}
}
class ItemQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['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;
String get description {
return (values['description'] as String);
}
set description(String value) => values['description'] = value;
void copyFrom(Item model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
description = model.description;
}
}
class AssetQuery extends Query<Asset, AssetQueryWhere> {
AssetQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = AssetQueryWhere(this);
leftJoin(_items = ItemQuery(trampoline: trampoline, parent: this), 'id',
'asset_id',
additionalFields: const [
'id',
'created_at',
'updated_at',
'description'
],
trampoline: trampoline);
}
@override
final AssetQueryValues values = AssetQueryValues();
List<String> _selectedFields = [];
AssetQueryWhere? _where;
late ItemQuery _items;
@override
Map<String, String> get casts {
return {};
}
@override
String get tableName {
return 'assets';
}
@override
List<String> get fields {
const _fields = ['id', 'created_at', 'updated_at', 'description', 'name'];
return _selectedFields.isEmpty
? _fields
: _fields.where((field) => _selectedFields.contains(field)).toList();
}
AssetQuery select(List<String> selectedFields) {
_selectedFields = selectedFields;
return this;
}
@override
AssetQueryWhere? get where {
return _where;
}
@override
AssetQueryWhere newWhereClause() {
return AssetQueryWhere(this);
}
Optional<Asset> parseRow(List row) {
if (row.every((x) => x == null)) {
return Optional.empty();
}
var model = Asset(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
description: fields.contains('description') ? (row[3] as String) : '',
name: fields.contains('name') ? (row[4] as String) : '');
if (row.length > 5) {
var modelOpt = ItemQuery().parseRow(row.skip(5).take(4).toList());
modelOpt.ifPresent((m) {
model = model.copyWith(items: [m]);
});
}
return Optional.of(model);
}
@override
Optional<Asset> deserialize(List row) {
return parseRow(row);
}
ItemQuery get items {
return _items;
}
@override
Future<List<Asset>> get(QueryExecutor executor) {
return super.get(executor).then((result) {
return result.fold<List<Asset>>([], (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(
items: List<_Item>.from(l.items)..addAll(model.items));
}
});
});
}
@override
Future<List<Asset>> update(QueryExecutor executor) {
return super.update(executor).then((result) {
return result.fold<List<Asset>>([], (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(
items: List<_Item>.from(l.items)..addAll(model.items));
}
});
});
}
@override
Future<List<Asset>> delete(QueryExecutor executor) {
return super.delete(executor).then((result) {
return result.fold<List<Asset>>([], (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(
items: List<_Item>.from(l.items)..addAll(model.items));
}
});
});
}
}
class AssetQueryWhere extends QueryWhere {
AssetQueryWhere(AssetQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
description = StringSqlExpressionBuilder(query, 'description'),
name = StringSqlExpressionBuilder(query, 'name');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final StringSqlExpressionBuilder description;
final StringSqlExpressionBuilder name;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [id, createdAt, updatedAt, description, name];
}
}
class AssetQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['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;
String get description {
return (values['description'] as String);
}
set description(String value) => values['description'] = value;
String get name {
return (values['name'] as String);
}
set name(String value) => values['name'] = value;
void copyFrom(Asset model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
description = model.description;
name = model.name;
}
}
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class Item extends _Item {
Item({this.id, this.createdAt, this.updatedAt, required this.description});
/// 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 description;
Item copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? description}) {
return Item(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
description: description ?? this.description);
}
@override
bool operator ==(other) {
return other is _Item &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.description == description;
}
@override
int get hashCode {
return hashObjects([id, createdAt, updatedAt, description]);
}
@override
String toString() {
return 'Item(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, description=$description)';
}
Map<String, dynamic> toJson() {
return ItemSerializer.toMap(this);
}
}
@generatedSerializable
class Asset extends _Asset {
Asset(
{this.id,
this.createdAt,
this.updatedAt,
required this.description,
required this.name,
List<_Item> items = const []})
: items = List.unmodifiable(items);
/// 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 description;
@override
String name;
@override
List<_Item> items;
Asset copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? description,
String? name,
List<_Item>? items}) {
return Asset(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
description: description ?? this.description,
name: name ?? this.name,
items: items ?? this.items);
}
@override
bool operator ==(other) {
return other is _Asset &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.description == description &&
other.name == name &&
ListEquality<_Item>(DefaultEquality<_Item>())
.equals(other.items, items);
}
@override
int get hashCode {
return hashObjects([id, createdAt, updatedAt, description, name, items]);
}
@override
String toString() {
return 'Asset(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, description=$description, name=$name, items=$items)';
}
Map<String, dynamic> toJson() {
return AssetSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const ItemSerializer itemSerializer = ItemSerializer();
class ItemEncoder extends Converter<Item, Map> {
const ItemEncoder();
@override
Map convert(Item model) => ItemSerializer.toMap(model);
}
class ItemDecoder extends Converter<Map, Item> {
const ItemDecoder();
@override
Item convert(Map map) => ItemSerializer.fromMap(map);
}
class ItemSerializer extends Codec<Item, Map> {
const ItemSerializer();
@override
ItemEncoder get encoder => const ItemEncoder();
@override
ItemDecoder get decoder => const ItemDecoder();
static Item fromMap(Map map) {
return Item(
id: map['id'] as String?,
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,
description: map['description'] as String);
}
static Map<String, dynamic> toMap(_Item? model) {
if (model == null) {
throw FormatException("Required field [model] cannot be null");
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'description': model.description
};
}
}
abstract class ItemFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
description
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String description = 'description';
}
const AssetSerializer assetSerializer = AssetSerializer();
class AssetEncoder extends Converter<Asset, Map> {
const AssetEncoder();
@override
Map convert(Asset model) => AssetSerializer.toMap(model);
}
class AssetDecoder extends Converter<Map, Asset> {
const AssetDecoder();
@override
Asset convert(Map map) => AssetSerializer.fromMap(map);
}
class AssetSerializer extends Codec<Asset, Map> {
const AssetSerializer();
@override
AssetEncoder get encoder => const AssetEncoder();
@override
AssetDecoder get decoder => const AssetDecoder();
static Asset fromMap(Map map) {
return Asset(
id: map['id'] as String?,
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,
description: map['description'] as String,
name: map['name'] as String,
items: map['items'] is Iterable
? List.unmodifiable(((map['items'] as Iterable).whereType<Map>())
.map(ItemSerializer.fromMap))
: []);
}
static Map<String, dynamic> toMap(_Asset? model) {
if (model == null) {
throw FormatException("Required field [model] cannot be null");
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'description': model.description,
'name': model.name,
'items': model.items.map((m) => ItemSerializer.toMap(m)).toList()
};
}
}
abstract class AssetFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
description,
name,
items
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String description = 'description';
static const String name = 'name';
static const String items = 'items';
}

View file

@ -0,0 +1,22 @@
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_migration/angel3_migration.dart';
import 'package:optional/optional.dart';
part 'bike.g.dart';
@serializable
@orm
abstract class _Bike extends Model {
String get make;
String get description;
bool get familyFriendly;
DateTime get recalledAt;
double get price;
int get width;
}

View file

@ -0,0 +1,435 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'bike.dart';
// **************************************************************************
// MigrationGenerator
// **************************************************************************
class BikeMigration extends Migration {
@override
void up(Schema schema) {
schema.create('bikes', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.varChar('make', length: 255);
table.varChar('description', length: 255);
table.boolean('family_friendly');
table.timeStamp('recalled_at');
table.float('price');
table.integer('width');
});
}
@override
void down(Schema schema) {
schema.drop('bikes');
}
}
// **************************************************************************
// OrmGenerator
// **************************************************************************
class BikeQuery extends Query<Bike, BikeQueryWhere> {
BikeQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = BikeQueryWhere(this);
}
@override
final BikeQueryValues values = BikeQueryValues();
List<String> _selectedFields = [];
BikeQueryWhere? _where;
@override
Map<String, String> get casts {
return {'price': 'char'};
}
@override
String get tableName {
return 'bikes';
}
@override
List<String> get fields {
const _fields = [
'id',
'created_at',
'updated_at',
'make',
'description',
'family_friendly',
'recalled_at',
'price',
'width'
];
return _selectedFields.isEmpty
? _fields
: _fields.where((field) => _selectedFields.contains(field)).toList();
}
BikeQuery select(List<String> selectedFields) {
_selectedFields = selectedFields;
return this;
}
@override
BikeQueryWhere? get where {
return _where;
}
@override
BikeQueryWhere newWhereClause() {
return BikeQueryWhere(this);
}
Optional<Bike> parseRow(List row) {
if (row.every((x) => x == null)) {
return Optional.empty();
}
var model = Bike(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
make: fields.contains('make') ? (row[3] as String) : '',
description: fields.contains('description') ? (row[4] as String) : '',
familyFriendly:
fields.contains('family_friendly') ? mapToBool(row[5]) : false,
recalledAt: fields.contains('recalled_at')
? mapToDateTime(row[6])
: DateTime.parse("1970-01-01 00:00:00"),
price: fields.contains('price') ? mapToDouble(row[7]) : 0.0,
width: fields.contains('width') ? (row[8] as int) : 0);
return Optional.of(model);
}
@override
Optional<Bike> deserialize(List row) {
return parseRow(row);
}
}
class BikeQueryWhere extends QueryWhere {
BikeQueryWhere(BikeQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
make = StringSqlExpressionBuilder(query, 'make'),
description = StringSqlExpressionBuilder(query, 'description'),
familyFriendly = BooleanSqlExpressionBuilder(query, 'family_friendly'),
recalledAt = DateTimeSqlExpressionBuilder(query, 'recalled_at'),
price = NumericSqlExpressionBuilder<double>(query, 'price'),
width = NumericSqlExpressionBuilder<int>(query, 'width');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final StringSqlExpressionBuilder make;
final StringSqlExpressionBuilder description;
final BooleanSqlExpressionBuilder familyFriendly;
final DateTimeSqlExpressionBuilder recalledAt;
final NumericSqlExpressionBuilder<double> price;
final NumericSqlExpressionBuilder<int> width;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
];
}
}
class BikeQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {'price': 'double'};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['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;
String get make {
return (values['make'] as String);
}
set make(String value) => values['make'] = value;
String get description {
return (values['description'] as String);
}
set description(String value) => values['description'] = value;
bool get familyFriendly {
return (values['family_friendly'] as bool);
}
set familyFriendly(bool value) => values['family_friendly'] = value;
DateTime get recalledAt {
return (values['recalled_at'] as DateTime);
}
set recalledAt(DateTime value) => values['recalled_at'] = value;
double get price {
return double.tryParse((values['price'] as String)) ?? 0.0;
}
set price(double value) => values['price'] = value.toString();
int get width {
return (values['width'] as int);
}
set width(int value) => values['width'] = value;
void copyFrom(Bike model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
make = model.make;
description = model.description;
familyFriendly = model.familyFriendly;
recalledAt = model.recalledAt;
price = model.price;
width = model.width;
}
}
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class Bike extends _Bike {
Bike(
{this.id,
this.createdAt,
this.updatedAt,
required this.make,
required this.description,
required this.familyFriendly,
required this.recalledAt,
required this.price,
required this.width});
/// 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 make;
@override
String description;
@override
bool familyFriendly;
@override
DateTime recalledAt;
@override
double price;
@override
int width;
Bike copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? make,
String? description,
bool? familyFriendly,
DateTime? recalledAt,
double? price,
int? width}) {
return Bike(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
make: make ?? this.make,
description: description ?? this.description,
familyFriendly: familyFriendly ?? this.familyFriendly,
recalledAt: recalledAt ?? this.recalledAt,
price: price ?? this.price,
width: width ?? this.width);
}
@override
bool operator ==(other) {
return other is _Bike &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.make == make &&
other.description == description &&
other.familyFriendly == familyFriendly &&
other.recalledAt == recalledAt &&
other.price == price &&
other.width == width;
}
@override
int get hashCode {
return hashObjects([
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
]);
}
@override
String toString() {
return 'Bike(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, make=$make, description=$description, familyFriendly=$familyFriendly, recalledAt=$recalledAt, price=$price, width=$width)';
}
Map<String, dynamic> toJson() {
return BikeSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const BikeSerializer bikeSerializer = BikeSerializer();
class BikeEncoder extends Converter<Bike, Map> {
const BikeEncoder();
@override
Map convert(Bike model) => BikeSerializer.toMap(model);
}
class BikeDecoder extends Converter<Map, Bike> {
const BikeDecoder();
@override
Bike convert(Map map) => BikeSerializer.fromMap(map);
}
class BikeSerializer extends Codec<Bike, Map> {
const BikeSerializer();
@override
BikeEncoder get encoder => const BikeEncoder();
@override
BikeDecoder get decoder => const BikeDecoder();
static Bike fromMap(Map map) {
return Bike(
id: map['id'] as String?,
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,
make: map['make'] as String,
description: map['description'] as String,
familyFriendly: map['family_friendly'] as bool,
recalledAt: map['recalled_at'] != null
? (map['recalled_at'] is DateTime
? (map['recalled_at'] as DateTime)
: DateTime.parse(map['recalled_at'].toString()))
: DateTime.parse("1970-01-01 00:00:00"),
price: map['price'] as double,
width: map['width'] as int);
}
static Map<String, dynamic> toMap(_Bike? model) {
if (model == null) {
throw FormatException("Required field [model] cannot be null");
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'make': model.make,
'description': model.description,
'family_friendly': model.familyFriendly,
'recalled_at': model.recalledAt.toIso8601String(),
'price': model.price,
'width': model.width
};
}
}
abstract class BikeFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String make = 'make';
static const String description = 'description';
static const String familyFriendly = 'family_friendly';
static const String recalledAt = 'recalled_at';
static const String price = 'price';
static const String width = 'width';
}

View file

@ -0,0 +1,28 @@
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_migration/angel3_migration.dart';
import 'package:optional/optional.dart';
part 'boat.g.dart';
@serializable
@orm
abstract class _Boat extends Model {
@SerializableField(defaultValue: '')
String get make;
@SerializableField(defaultValue: 'none')
String get description;
@SerializableField(defaultValue: false)
bool get familyFriendly;
//@SerializableField(defaultValue: '1970-01-01 00:00:00')
DateTime get recalledAt;
@SerializableField(defaultValue: 0.0)
double get price;
@SerializableField(defaultValue: 0)
int get width;
}

View file

@ -0,0 +1,435 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'boat.dart';
// **************************************************************************
// MigrationGenerator
// **************************************************************************
class BoatMigration extends Migration {
@override
void up(Schema schema) {
schema.create('boats', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.varChar('make', length: 255).defaultsTo('');
table.varChar('description', length: 255).defaultsTo('none');
table.boolean('family_friendly').defaultsTo(false);
table.timeStamp('recalled_at');
table.float('price').defaultsTo(0.0);
table.integer('width').defaultsTo(0);
});
}
@override
void down(Schema schema) {
schema.drop('boats');
}
}
// **************************************************************************
// OrmGenerator
// **************************************************************************
class BoatQuery extends Query<Boat, BoatQueryWhere> {
BoatQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = BoatQueryWhere(this);
}
@override
final BoatQueryValues values = BoatQueryValues();
List<String> _selectedFields = [];
BoatQueryWhere? _where;
@override
Map<String, String> get casts {
return {'price': 'char'};
}
@override
String get tableName {
return 'boats';
}
@override
List<String> get fields {
const _fields = [
'id',
'created_at',
'updated_at',
'make',
'description',
'family_friendly',
'recalled_at',
'price',
'width'
];
return _selectedFields.isEmpty
? _fields
: _fields.where((field) => _selectedFields.contains(field)).toList();
}
BoatQuery select(List<String> selectedFields) {
_selectedFields = selectedFields;
return this;
}
@override
BoatQueryWhere? get where {
return _where;
}
@override
BoatQueryWhere newWhereClause() {
return BoatQueryWhere(this);
}
Optional<Boat> parseRow(List row) {
if (row.every((x) => x == null)) {
return Optional.empty();
}
var model = Boat(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
make: fields.contains('make') ? (row[3] as String) : '',
description: fields.contains('description') ? (row[4] as String) : '',
familyFriendly:
fields.contains('family_friendly') ? mapToBool(row[5]) : false,
recalledAt: fields.contains('recalled_at')
? mapToDateTime(row[6])
: DateTime.parse("1970-01-01 00:00:00"),
price: fields.contains('price') ? mapToDouble(row[7]) : 0.0,
width: fields.contains('width') ? (row[8] as int) : 0);
return Optional.of(model);
}
@override
Optional<Boat> deserialize(List row) {
return parseRow(row);
}
}
class BoatQueryWhere extends QueryWhere {
BoatQueryWhere(BoatQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
make = StringSqlExpressionBuilder(query, 'make'),
description = StringSqlExpressionBuilder(query, 'description'),
familyFriendly = BooleanSqlExpressionBuilder(query, 'family_friendly'),
recalledAt = DateTimeSqlExpressionBuilder(query, 'recalled_at'),
price = NumericSqlExpressionBuilder<double>(query, 'price'),
width = NumericSqlExpressionBuilder<int>(query, 'width');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final StringSqlExpressionBuilder make;
final StringSqlExpressionBuilder description;
final BooleanSqlExpressionBuilder familyFriendly;
final DateTimeSqlExpressionBuilder recalledAt;
final NumericSqlExpressionBuilder<double> price;
final NumericSqlExpressionBuilder<int> width;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
];
}
}
class BoatQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {'price': 'double'};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['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;
String get make {
return (values['make'] as String);
}
set make(String value) => values['make'] = value;
String get description {
return (values['description'] as String);
}
set description(String value) => values['description'] = value;
bool get familyFriendly {
return (values['family_friendly'] as bool);
}
set familyFriendly(bool value) => values['family_friendly'] = value;
DateTime get recalledAt {
return (values['recalled_at'] as DateTime);
}
set recalledAt(DateTime value) => values['recalled_at'] = value;
double get price {
return double.tryParse((values['price'] as String)) ?? 0.0;
}
set price(double value) => values['price'] = value.toString();
int get width {
return (values['width'] as int);
}
set width(int value) => values['width'] = value;
void copyFrom(Boat model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
make = model.make;
description = model.description;
familyFriendly = model.familyFriendly;
recalledAt = model.recalledAt;
price = model.price;
width = model.width;
}
}
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class Boat extends _Boat {
Boat(
{this.id,
this.createdAt,
this.updatedAt,
this.make = '',
this.description = 'none',
this.familyFriendly = false,
required this.recalledAt,
this.price = 0.0,
this.width = 0});
/// 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 make;
@override
String description;
@override
bool familyFriendly;
@override
DateTime recalledAt;
@override
double price;
@override
int width;
Boat copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
String? make,
String? description,
bool? familyFriendly,
DateTime? recalledAt,
double? price,
int? width}) {
return Boat(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
make: make ?? this.make,
description: description ?? this.description,
familyFriendly: familyFriendly ?? this.familyFriendly,
recalledAt: recalledAt ?? this.recalledAt,
price: price ?? this.price,
width: width ?? this.width);
}
@override
bool operator ==(other) {
return other is _Boat &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.make == make &&
other.description == description &&
other.familyFriendly == familyFriendly &&
other.recalledAt == recalledAt &&
other.price == price &&
other.width == width;
}
@override
int get hashCode {
return hashObjects([
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
]);
}
@override
String toString() {
return 'Boat(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, make=$make, description=$description, familyFriendly=$familyFriendly, recalledAt=$recalledAt, price=$price, width=$width)';
}
Map<String, dynamic> toJson() {
return BoatSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const BoatSerializer boatSerializer = BoatSerializer();
class BoatEncoder extends Converter<Boat, Map> {
const BoatEncoder();
@override
Map convert(Boat model) => BoatSerializer.toMap(model);
}
class BoatDecoder extends Converter<Map, Boat> {
const BoatDecoder();
@override
Boat convert(Map map) => BoatSerializer.fromMap(map);
}
class BoatSerializer extends Codec<Boat, Map> {
const BoatSerializer();
@override
BoatEncoder get encoder => const BoatEncoder();
@override
BoatDecoder get decoder => const BoatDecoder();
static Boat fromMap(Map map) {
return Boat(
id: map['id'] as String?,
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,
make: map['make'] as String? ?? '',
description: map['description'] as String? ?? 'none',
familyFriendly: map['family_friendly'] as bool? ?? false,
recalledAt: map['recalled_at'] != null
? (map['recalled_at'] is DateTime
? (map['recalled_at'] as DateTime)
: DateTime.parse(map['recalled_at'].toString()))
: DateTime.parse("1970-01-01 00:00:00"),
price: map['price'] as double? ?? 0.0,
width: map['width'] as int? ?? 0);
}
static Map<String, dynamic> toMap(_Boat? model) {
if (model == null) {
throw FormatException("Required field [model] cannot be null");
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'make': model.make,
'description': model.description,
'family_friendly': model.familyFriendly,
'recalled_at': model.recalledAt.toIso8601String(),
'price': model.price,
'width': model.width
};
}
}
abstract class BoatFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
make,
description,
familyFriendly,
recalledAt,
price,
width
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String make = 'make';
static const String description = 'description';
static const String familyFriendly = 'family_friendly';
static const String recalledAt = 'recalled_at';
static const String price = 'price';
static const String width = 'width';
}

View file

@ -31,8 +31,7 @@ class FootMigration extends Migration {
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.integer('leg_id');
table.declareColumn(
'n_toes', Column(type: ColumnType('decimal'), length: 255));
table.float('n_toes');
});
}
@ -280,7 +279,7 @@ class FootQueryWhere extends QueryWhere {
class FootQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {'n_toes': 'decimal'};
return {'n_toes': 'double'};
}
String? get id {
@ -304,7 +303,7 @@ class FootQueryValues extends MapQueryValues {
set legId(int? value) => values['leg_id'] = value;
double? get nToes {
return double.tryParse((values['n_toes'] as String));
return double.tryParse((values['n_toes'] as String)) ?? 0.0;
}
set nToes(double? value) => values['n_toes'] = value.toString();

View file

@ -15,8 +15,7 @@ class PersonOrderMigration extends Migration {
table.timeStamp('updated_at');
table.integer('person_id');
table.varChar('name', length: 255);
table.declareColumn(
'price', Column(type: ColumnType('decimal'), length: 255));
table.float('price');
table.boolean('deleted');
});
}
@ -141,7 +140,7 @@ class PersonOrderQueryWhere extends QueryWhere {
class PersonOrderQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {'price': 'decimal'};
return {'price': 'double'};
}
String? get id {
@ -170,7 +169,7 @@ class PersonOrderQueryValues extends MapQueryValues {
set name(String? value) => values['name'] = value;
double? get price {
return double.tryParse((values['price'] as String));
return double.tryParse((values['price'] as String)) ?? 0.0;
}
set price(double? value) => values['price'] = value.toString();
@ -302,7 +301,7 @@ class OrderWithPersonInfoQueryWhere extends QueryWhere {
class OrderWithPersonInfoQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {'price': 'decimal'};
return {'price': 'double'};
}
String? get id {
@ -326,7 +325,7 @@ class OrderWithPersonInfoQueryValues extends MapQueryValues {
set name(String? value) => values['name'] = value;
double? get price {
return double.tryParse((values['price'] as String));
return double.tryParse((values['price'] as String)) ?? 0.0;
}
set price(double? value) => values['price'] = value.toString();

View file

@ -18,8 +18,8 @@ dev_dependencies:
angel3_orm_generator: ^6.0.0
angel3_framework: ^6.0.0
build_runner: ^2.0.1
lints: ^1.0.0
# dependency_overrides:
lints: ^2.0.0
dependency_overrides:
# angel3_container:
# path: ../../container/angel_container
# angel3_framework:
@ -34,11 +34,11 @@ dev_dependencies:
# path: ../../mock_request
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
# angel3_orm:
# path: ../angel_orm
angel3_serialize_generator:
path: ../../serialize/angel_serialize_generator
angel3_orm:
path: ../angel_orm
# angel3_migration:
# path: ../angel_migration
# angel3_orm_generator:
# path: ../angel_orm_generator
angel3_orm_generator:
path: ../angel_orm_generator

View file

@ -1,5 +1,10 @@
# Change Log
## 6.1.1
* Fixed issue #68: Support for non-nullable type
* Upgraded to `lints` 2.x.x
## 6.1.0
* Updated to `analyzer` 4.x.x

View file

@ -114,6 +114,7 @@ class ${pascal}Decoder extends Converter<Map, $pascal> {
}));
}
// Generate toMapMethod
void generateToMapMethod(
ClassBuilder clazz, BuildContext ctx, LibraryBuilder file) {
var originalClassName = ctx.originalClassName;
@ -178,7 +179,12 @@ class ${pascal}Decoder extends Converter<Map, $pascal> {
// Serialize dates
else if (dateTimeTypeChecker.isAssignableFromType(type)) {
serializedRepresentation = 'model.${field.name}?.toIso8601String()';
var question =
field.type.nullabilitySuffix == NullabilitySuffix.question
? "?"
: "";
serializedRepresentation =
'model.${field.name}$question.toIso8601String()';
}
// Serialize model classes via `XSerializer.toMap`
@ -246,6 +252,7 @@ class ${pascal}Decoder extends Converter<Map, $pascal> {
}));
}
// Generate fromMapMethod
void generateFromMapMethod(
ClassBuilder clazz, BuildContext ctx, LibraryBuilder file) {
clazz.methods.add(Method((method) {
@ -336,6 +343,13 @@ class ${pascal}Decoder extends Converter<Map, $pascal> {
var name = MirrorSystem.getName(fieldNameDeserializer);
deserializedRepresentation = "$name(map['$alias'])";
} else if (dateTimeTypeChecker.isAssignableFromType(type)) {
if (field.type.nullabilitySuffix != NullabilitySuffix.question) {
if (defaultValue.toLowerCase() == 'null') {
defaultValue = 'DateTime.parse("1970-01-01 00:00:00")';
} else {
defaultValue = 'DateTime.parse("$defaultValue")';
}
}
deserializedRepresentation = "map['$alias'] != null ? "
"(map['$alias'] is DateTime ? (map['$alias'] as DateTime) : DateTime.parse(map['$alias'].toString()))"
' : $defaultValue';

View file

@ -1,5 +1,5 @@
name: angel3_serialize_generator
version: 6.1.0
version: 6.1.1
description: Angel3 model serialization generators, designed for use with Angel. Combine with angel_serialize for flexible modeling.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/serialize/angel_serialize_generator
@ -22,7 +22,7 @@ dependencies:
dev_dependencies:
build_runner: ^2.0.1
collection: ^1.15.0
lints: ^1.0.0
lints: ^2.0.0
test: ^1.21.0
# dependency_overrides:
# angel3_model: